diff options
author | Wolfgang Denk <wd@pollux.denx.de> | 2005-10-09 01:04:33 +0200 |
---|---|---|
committer | Wolfgang Denk <wd@pollux.denx.de> | 2005-10-09 01:04:33 +0200 |
commit | 7521af1c7d95ff087a4f7636ed050f4d4be91b59 (patch) | |
tree | acd83b262b72925dba271c7e0bcb0dcf7072bdae /board/amirix/ap1000/powerspan.c | |
parent | 95f9dda2165f045a7e1708885ee589878cc6f20b (diff) | |
download | u-boot-imx-7521af1c7d95ff087a4f7636ed050f4d4be91b59.zip u-boot-imx-7521af1c7d95ff087a4f7636ed050f4d4be91b59.tar.gz u-boot-imx-7521af1c7d95ff087a4f7636ed050f4d4be91b59.tar.bz2 |
Add support for AP1000 board.
Patch by James MacAulay, 07 Oct 2005
Diffstat (limited to 'board/amirix/ap1000/powerspan.c')
-rw-r--r-- | board/amirix/ap1000/powerspan.c | 712 |
1 files changed, 712 insertions, 0 deletions
diff --git a/board/amirix/ap1000/powerspan.c b/board/amirix/ap1000/powerspan.c new file mode 100644 index 0000000..fe395cc --- /dev/null +++ b/board/amirix/ap1000/powerspan.c @@ -0,0 +1,712 @@ +/** + * @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 <common.h> +#include <command.h> +#include <asm/processor.h> +#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; + +} + + + |