/** * @file powerspan.c Source file for PowerSpan II code. */ /* * (C) Copyright 2005 * AMIRIX Systems Inc. * * See file CREDITS for list of people who contributed to this * project. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ #include #include #include #include "powerspan.h" #define tolower(x) x #include "ap1000.h" #ifdef INCLUDE_PCI /** Write one byte with byte swapping. * @param addr [IN] the address to write to * @param val [IN] the value to write */ void write1(unsigned long addr, unsigned char val) { volatile unsigned char* p = (volatile unsigned char*)addr; #ifdef VERBOSITY if(gVerbosityLevel > 1){ printf("write1: addr=%08x val=%02x\n", addr, val); } #endif *p = val; PSII_SYNC(); } /** Read one byte with byte swapping. * @param addr [IN] the address to read from * @return the value at addr */ unsigned char read1(unsigned long addr) { unsigned char val; volatile unsigned char* p = (volatile unsigned char*)addr; val = *p; PSII_SYNC(); #ifdef VERBOSITY if(gVerbosityLevel > 1){ printf("read1: addr=%08x val=%02x\n", addr, val); } #endif return val; } /** Write one 2-byte word with byte swapping. * @param addr [IN] the address to write to * @param val [IN] the value to write */ void write2(unsigned long addr, unsigned short val) { volatile unsigned short* p = (volatile unsigned short*)addr; #ifdef VERBOSITY if(gVerbosityLevel > 1){ printf("write2: addr=%08x val=%04x -> *p=%04x\n", addr, val, ((val & 0xFF00) >> 8) | ((val & 0x00FF) << 8)); } #endif *p = ((val & 0xFF00) >> 8) | ((val & 0x00FF) << 8); PSII_SYNC(); } /** Read one 2-byte word with byte swapping. * @param addr [IN] the address to read from * @return the value at addr */ unsigned short read2(unsigned long addr) { unsigned short val; volatile unsigned short* p = (volatile unsigned short*)addr; val = *p; val = ((val & 0xFF00) >> 8) | ((val & 0x00FF) << 8); PSII_SYNC(); #ifdef VERBOSITY if(gVerbosityLevel > 1){ printf("read2: addr=%08x *p=%04x -> val=%04x\n", addr, *p, val); } #endif return val; } /** Write one 4-byte word with byte swapping. * @param addr [IN] the address to write to * @param val [IN] the value to write */ void write4(unsigned long addr, unsigned long val) { volatile unsigned long* p = (volatile unsigned long*)addr; #ifdef VERBOSITY if(gVerbosityLevel > 1){ printf("write4: addr=%08x val=%08x -> *p=%08x\n", addr, val, ((val & 0xFF000000) >> 24) | ((val & 0x000000FF) << 24) | ((val & 0x00FF0000) >> 8) | ((val & 0x0000FF00) << 8)); } #endif *p = ((val & 0xFF000000) >> 24) | ((val & 0x000000FF) << 24) | ((val & 0x00FF0000) >> 8) | ((val & 0x0000FF00) << 8); PSII_SYNC(); } /** Read one 4-byte word with byte swapping. * @param addr [IN] the address to read from * @return the value at addr */ unsigned long read4(unsigned long addr) { unsigned long val; volatile unsigned long* p = (volatile unsigned long*)addr; val = *p; val = ((val & 0xFF000000) >> 24) | ((val & 0x000000FF) << 24) | ((val & 0x00FF0000) >> 8) | ((val & 0x0000FF00) << 8); PSII_SYNC(); #ifdef VERBOSITY if(gVerbosityLevel > 1){ printf("read4: addr=%08x *p=%08x -> val=%08x\n", addr, *p, val); } #endif return val; } int PCIReadConfig(int bus, int dev, int fn, int reg, int width, unsigned long* val){ unsigned int conAdrVal; unsigned int conDataReg = REG_CONFIG_DATA; unsigned int status; int ret_val = 0; /* DEST bit hardcoded to 1: local pci is PCI-2 */ /* TYPE bit is hardcoded to 1: all config cycles are local */ conAdrVal = (1 << 24) | ((bus & 0xFF) << 16) | ((dev & 0xFF) << 11) | ((fn & 0x07) << 8) | (reg & 0xFC); /* clear any pending master aborts */ write4(REG_P1_CSR, CLEAR_MASTER_ABORT); /* Load the conAdrVal value first, then read from pb_conf_data */ write4(REG_CONFIG_ADDRESS, conAdrVal); PSII_SYNC(); /* Note: documentation does not match the pspan library code */ /* Note: *pData comes back as -1 if device is not present */ switch (width){ case 4:{ *(unsigned int*)val = read4(conDataReg); break; } case 2:{ *(unsigned short*)val = read2(conDataReg); break; } case 1:{ *(unsigned char*)val = read1(conDataReg); break; } default:{ ret_val = ILLEGAL_REG_OFFSET; break; } } PSII_SYNC(); /* clear any pending master aborts */ status = read4(REG_P1_CSR); if(status & CLEAR_MASTER_ABORT){ ret_val = NO_DEVICE_FOUND; write4(REG_P1_CSR, CLEAR_MASTER_ABORT); } return ret_val; } int PCIWriteConfig(int bus, int dev, int fn, int reg, int width, unsigned long val){ unsigned int conAdrVal; unsigned int conDataReg = REG_CONFIG_DATA; unsigned int status; int ret_val = 0; /* DEST bit hardcoded to 1: local pci is PCI-2 */ /* TYPE bit is hardcoded to 1: all config cycles are local */ conAdrVal = (1 << 24) | ((bus & 0xFF) << 16) | ((dev & 0xFF) << 11) | ((fn & 0x07) << 8) | (reg & 0xFC); /* clear any pending master aborts */ write4(REG_P1_CSR, CLEAR_MASTER_ABORT); /* Load the conAdrVal value first, then read from pb_conf_data */ write4(REG_CONFIG_ADDRESS, conAdrVal); PSII_SYNC(); /* Note: documentation does not match the pspan library code */ /* Note: *pData comes back as -1 if device is not present */ switch (width){ case 4:{ write4(conDataReg, val); break; } case 2:{ write2(conDataReg, val); break; } case 1:{ write1(conDataReg, val); break; } default:{ ret_val = ILLEGAL_REG_OFFSET; break; } } PSII_SYNC(); /* clear any pending master aborts */ status = read4(REG_P1_CSR); if(status & CLEAR_MASTER_ABORT){ ret_val = NO_DEVICE_FOUND; write4(REG_P1_CSR, CLEAR_MASTER_ABORT); } return ret_val; } int pci_read_config_byte(int bus, int dev, int fn, int reg, unsigned char* val){ unsigned long read_val; int ret_val; ret_val = PCIReadConfig(bus, dev, fn, reg, 1, &read_val); *val = read_val & 0xFF; return ret_val; } int pci_write_config_byte(int bus, int dev, int fn, int reg, unsigned char val){ return PCIWriteConfig(bus, dev, fn, reg, 1, val); } int pci_read_config_word(int bus, int dev, int fn, int reg, unsigned short* val){ unsigned long read_val; int ret_val; ret_val = PCIReadConfig(bus, dev, fn, reg, 2, &read_val); *val = read_val & 0xFFFF; return ret_val; } int pci_write_config_word(int bus, int dev, int fn, int reg, unsigned short val){ return PCIWriteConfig(bus, dev, fn, reg, 2, val); } int pci_read_config_dword(int bus, int dev, int fn, int reg, unsigned long* val){ return PCIReadConfig(bus, dev, fn, reg, 4, val); } int pci_write_config_dword(int bus, int dev, int fn, int reg, unsigned long val){ return PCIWriteConfig(bus, dev, fn, reg, 4, val); } #endif /* INCLUDE_PCI */ int I2CAccess(unsigned char theI2CAddress, unsigned char theDevCode, unsigned char theChipSel, unsigned char* theValue, int RWFlag){ int ret_val = 0; unsigned int reg_value; reg_value = PowerSpanRead(REG_I2C_CSR); if(reg_value & I2C_CSR_ACT){ printf("Error: I2C busy\n"); ret_val = I2C_BUSY; } else{ reg_value = ((theI2CAddress & 0xFF) << 24) | ((theDevCode & 0x0F) << 12) | ((theChipSel & 0x07) << 9) | I2C_CSR_ERR; if(RWFlag == I2C_WRITE){ reg_value |= I2C_CSR_RW | ((*theValue & 0xFF) << 16); } PowerSpanWrite(REG_I2C_CSR, reg_value); udelay(1); do{ reg_value = PowerSpanRead(REG_I2C_CSR); if((reg_value & I2C_CSR_ACT) == 0){ if(reg_value & I2C_CSR_ERR){ ret_val = I2C_ERR; } else{ *theValue = (reg_value & I2C_CSR_DATA) >> 16; } } } while(reg_value & I2C_CSR_ACT); } return ret_val; } int EEPROMRead(unsigned char theI2CAddress, unsigned char* theValue){ return I2CAccess(theI2CAddress, I2C_EEPROM_DEV, I2C_EEPROM_CHIP_SEL, theValue, I2C_READ); } int EEPROMWrite(unsigned char theI2CAddress, unsigned char theValue){ return I2CAccess(theI2CAddress, I2C_EEPROM_DEV, I2C_EEPROM_CHIP_SEL, &theValue, I2C_WRITE); } int do_eeprom(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){ char cmd; int ret_val = 0; unsigned int address = 0; unsigned char value = 1; unsigned char read_value; int ii; int error = 0; unsigned char* mem_ptr; unsigned char default_eeprom[] = EEPROM_DEFAULT; if(argc < 2){ goto usage; } cmd = argv[1][0]; if(argc > 2){ address = simple_strtoul(argv[2], NULL, 16); if(argc > 3){ value = simple_strtoul(argv[3], NULL, 16) & 0xFF; } } switch (cmd){ case 'r':{ if(address > 256){ printf("Illegal Address\n"); goto usage; } printf("@0x%x: ", address); for(ii = 0;ii < value;ii++){ if(EEPROMRead(address + ii, &read_value) != 0){ printf("Read Error\n"); } else{ printf("0x%02x ", read_value); } if(((ii + 1) % 16) == 0){ printf("\n"); } } printf("\n"); break; } case 'w':{ if(address > 256){ printf("Illegal Address\n"); goto usage; } if(argc < 4){ goto usage; } if(EEPROMWrite(address, value) != 0){ printf("Write Error\n"); } break; } case 'g':{ if(argc != 3){ goto usage; } mem_ptr = (unsigned char*)address; for(ii = 0;((ii < EEPROM_LENGTH) && (error == 0));ii++){ if(EEPROMRead(ii, &read_value) != 0){ printf("Read Error\n"); error = 1; } else{ *mem_ptr = read_value; mem_ptr++; } } break; } case 'p':{ if(argc != 3){ goto usage; } mem_ptr = (unsigned char*)address; for(ii = 0;((ii < EEPROM_LENGTH) && (error == 0));ii++){ if(EEPROMWrite(ii, *mem_ptr) != 0){ printf("Write Error\n"); error = 1; } mem_ptr++; } break; } case 'd':{ if(argc != 2){ goto usage; } for(ii = 0;((ii < EEPROM_LENGTH) && (error == 0));ii++){ if(EEPROMWrite(ii, default_eeprom[ii]) != 0){ printf("Write Error\n"); error = 1; } } break; } default:{ goto usage; } } goto done; usage: printf ("Usage:\n%s\n", cmdtp->help); done: return ret_val; } U_BOOT_CMD( eeprom, 4, 0, do_eeprom, "eeprom - read/write/copy to/from the PowerSpan II eeprom\n", "eeprom r OFF [NUM]\n" " - read NUM words starting at OFF\n" "eeprom w OFF VAL\n" " - write word VAL at offset OFF\n" "eeprom g ADD\n" " - store contents of eeprom at address ADD\n" "eeprom p ADD\n" " - put data stored at address ADD into the eeprom\n" "eeprom d\n" " - return eeprom to default contents\n" ); unsigned int PowerSpanRead(unsigned int theOffset){ volatile unsigned int* ptr = (volatile unsigned int*)(PSPAN_BASEADDR + theOffset); unsigned int ret_val; #ifdef VERBOSITY if(gVerbosityLevel > 1){ printf("PowerSpanRead: offset=%08x ", theOffset); } #endif ret_val = *ptr; PSII_SYNC(); #ifdef VERBOSITY if(gVerbosityLevel > 1){ printf("value=%08x\n", ret_val); } #endif return ret_val; } void PowerSpanWrite(unsigned int theOffset, unsigned int theValue){ volatile unsigned int* ptr = (volatile unsigned int*)(PSPAN_BASEADDR + theOffset); #ifdef VERBOSITY if(gVerbosityLevel > 1){ printf("PowerSpanWrite: offset=%08x val=%02x\n", theOffset, theValue); } #endif *ptr = theValue; PSII_SYNC(); } /** * Sets the indicated bits in the indicated register. * @param theOffset [IN] the register to access. * @param theMask [IN] bits set in theMask will be set in the register. */ void PowerSpanSetBits(unsigned int theOffset, unsigned int theMask){ volatile unsigned int* ptr = (volatile unsigned int*)(PSPAN_BASEADDR + theOffset); unsigned int register_value; #ifdef VERBOSITY if(gVerbosityLevel > 1){ printf("PowerSpanSetBits: offset=%08x mask=%02x\n", theOffset, theMask); } #endif register_value = *ptr; PSII_SYNC(); register_value |= theMask; *ptr = register_value; PSII_SYNC(); } /** * Clears the indicated bits in the indicated register. * @param theOffset [IN] the register to access. * @param theMask [IN] bits set in theMask will be cleared in the register. */ void PowerSpanClearBits(unsigned int theOffset, unsigned int theMask){ volatile unsigned int* ptr = (volatile unsigned int*)(PSPAN_BASEADDR + theOffset); unsigned int register_value; #ifdef VERBOSITY if(gVerbosityLevel > 1){ printf("PowerSpanClearBits: offset=%08x mask=%02x\n", theOffset, theMask); } #endif register_value = *ptr; PSII_SYNC(); register_value &= ~theMask; *ptr = register_value; PSII_SYNC(); } /** * Configures a slave image on the local bus, based on the parameters and some hardcoded system values. * Slave Images are images that cause the PowerSpan II to be a master on the PCI bus. Thus, they * are outgoing from the standpoint of the local bus. * @param theImageIndex [IN] the PowerSpan II image to set (assumed to be 0-7). * @param theBlockSize [IN] the block size of the image (as used by PowerSpan II: PB_SIx_CTL[BS]). * @param theMemIOFlag [IN] if PX_TGT_USE_MEM_IO, this image will have the MEM_IO bit set. * @param theEndianness [IN] the endian bits for the image (already shifted, use defines). * @param theLocalBaseAddr [IN] the Local address for the image (assumed to be valid with provided block size). * @param thePCIBaseAddr [IN] the PCI address for the image (assumed to be valid with provided block size). */ int SetSlaveImage(int theImageIndex, unsigned int theBlockSize, int theMemIOFlag, int theEndianness, unsigned int theLocalBaseAddr, unsigned int thePCIBaseAddr){ unsigned int reg_offset = theImageIndex * PB_SLAVE_IMAGE_OFF; unsigned int reg_value = 0; /* Make sure that the Slave Image is disabled */ PowerSpanClearBits((REGS_PB_SLAVE_CSR + reg_offset), PB_SLAVE_CSR_IMG_EN); /* Setup the mask required for requested PB Slave Image configuration */ reg_value = PB_SLAVE_CSR_TA_EN | theEndianness | (theBlockSize << 24); if(theMemIOFlag == PB_SLAVE_USE_MEM_IO){ reg_value |= PB_SLAVE_CSR_MEM_IO; } /* hardcoding the following: TA_EN = 1 MD_EN = 0 MODE = 0 PRKEEP = 0 RD_AMT = 0 */ PowerSpanWrite((REGS_PB_SLAVE_CSR + reg_offset), reg_value); /* these values are not checked by software */ PowerSpanWrite((REGS_PB_SLAVE_BADDR + reg_offset), theLocalBaseAddr); PowerSpanWrite((REGS_PB_SLAVE_TADDR + reg_offset), thePCIBaseAddr); /* Enable the Slave Image */ PowerSpanSetBits((REGS_PB_SLAVE_CSR + reg_offset), PB_SLAVE_CSR_IMG_EN); return 0; } /** * Configures a target image on the local bus, based on the parameters and some hardcoded system values. * Target Images are used when the PowerSpan II is acting as a target for an access. Thus, they * are incoming from the standpoint of the local bus. * In order to behave better on the host PCI bus, if thePCIBaseAddr is NULL (0x00000000), then the PCI * base address will not be updated; makes sense given that the hosts own memory should be mapped to * PCI address 0x00000000. * @param theImageIndex [IN] the PowerSpan II image to set. * @param theBlockSize [IN] the block size of the image (as used by PowerSpan II: Px_TIx_CTL[BS]). * @param theMemIOFlag [IN] if PX_TGT_USE_MEM_IO, this image will have the MEM_IO bit set. * @param theEndianness [IN] the endian bits for the image (already shifted, use defines). * @param theLocalBaseAddr [IN] the Local address for the image (assumed to be valid with provided block size). * @param thePCIBaseAddr [IN] the PCI address for the image (assumed to be valid with provided block size). */ int SetTargetImage(int theImageIndex, unsigned int theBlockSize, int theMemIOFlag, int theEndianness, unsigned int theLocalBaseAddr, unsigned int thePCIBaseAddr){ unsigned int csr_reg_offset = theImageIndex * P1_TGT_IMAGE_OFF; unsigned int pci_reg_offset = theImageIndex * P1_BST_OFF; unsigned int reg_value = 0; /* Make sure that the Slave Image is disabled */ PowerSpanClearBits((REGS_P1_TGT_CSR + csr_reg_offset), PB_SLAVE_CSR_IMG_EN); /* Setup the mask required for requested PB Slave Image configuration */ reg_value = PX_TGT_CSR_TA_EN | PX_TGT_CSR_BAR_EN | (theBlockSize << 24) | PX_TGT_CSR_RTT_READ | PX_TGT_CSR_WTT_WFLUSH | theEndianness; if(theMemIOFlag == PX_TGT_USE_MEM_IO){ reg_value |= PX_TGT_MEM_IO; } /* hardcoding the following: TA_EN = 1 BAR_EN = 1 MD_EN = 0 MODE = 0 DEST = 0 RTT = 01010 GBL = 0 CI = 0 WTT = 00010 PRKEEP = 0 MRA = 0 RD_AMT = 0 */ PowerSpanWrite((REGS_P1_TGT_CSR + csr_reg_offset), reg_value); PowerSpanWrite((REGS_P1_TGT_TADDR + csr_reg_offset), theLocalBaseAddr); if(thePCIBaseAddr != (unsigned int)NULL){ PowerSpanWrite((REGS_P1_BST + pci_reg_offset), thePCIBaseAddr); } /* Enable the Slave Image */ PowerSpanSetBits((REGS_P1_TGT_CSR + csr_reg_offset), PB_SLAVE_CSR_IMG_EN); return 0; } int do_bridge(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){ char cmd; int ret_val = 1; unsigned int image_index; unsigned int block_size; unsigned int mem_io; unsigned int local_addr; unsigned int pci_addr; int endianness; if(argc != 8){ goto usage; } cmd = argv[1][0]; image_index = simple_strtoul(argv[2], NULL, 16); block_size = simple_strtoul(argv[3], NULL, 16); mem_io = simple_strtoul(argv[4], NULL, 16); endianness = argv[5][0]; local_addr = simple_strtoul(argv[6], NULL, 16); pci_addr = simple_strtoul(argv[7], NULL, 16); switch (cmd){ case 'i':{ if(tolower(endianness) == 'b'){ endianness = PX_TGT_CSR_BIG_END; } else if(tolower(endianness) == 'l'){ endianness = PX_TGT_CSR_TRUE_LEND; } else{ goto usage; } SetTargetImage(image_index, block_size, mem_io, endianness, local_addr, pci_addr); break; } case 'o':{ if(tolower(endianness) == 'b'){ endianness = PB_SLAVE_CSR_BIG_END; } else if(tolower(endianness) == 'l'){ endianness = PB_SLAVE_CSR_TRUE_LEND; } else{ goto usage; } SetSlaveImage(image_index, block_size, mem_io, endianness, local_addr, pci_addr); break; } default:{ goto usage; } } goto done; usage: printf ("Usage:\n%s\n", cmdtp->help); done: return ret_val; }