diff options
Diffstat (limited to 'src/usr/console/ast2400.C')
-rw-r--r-- | src/usr/console/ast2400.C | 441 |
1 files changed, 395 insertions, 46 deletions
diff --git a/src/usr/console/ast2400.C b/src/usr/console/ast2400.C index db0bf40ae..b2b63c395 100644 --- a/src/usr/console/ast2400.C +++ b/src/usr/console/ast2400.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2014 */ +/* Contributors Listed Below - COPYRIGHT 2014,2015 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -26,80 +26,235 @@ #include <devicefw/userif.H> #include <lpc/lpcif.H> #include <errl/errlmanager.H> +#include <kernel/console.H> +#include <devicefw/driverif.H> +#include <initservice/bootconfigif.H> namespace CONSOLE { + const uint32_t VUART1_BASE = 0x1E787000; + const uint32_t VUART1_GCTRLA = VUART1_BASE + 0x20; + const uint32_t VUART1_GCTRLB = VUART1_BASE + 0x24; + const uint32_t VUART1_ADDRL = VUART1_BASE + 0x28; + const uint32_t VUART1_ADDRH = VUART1_BASE + 0x2c; -/** Overload the base class with Ast2400 specifices. - * - * In initialization we need to program the SIO device on the AST2400 to - * enable the Uart device. - */ -class Ast2400Uart : public Uart -{ - private: + const uint8_t SERIAL_IRQ = 4; + + const uint8_t SIO_ADDR_REG_2E = 0x2E; + const uint8_t SIO_DATA_REG_2F = 0x2F; + + // used to test config flags related to console outup selection + const uint8_t CONFIG_MASK = 0xC0; + /** Overload the base class with Ast2400 specifics. + * + * In initialization we need to program the SIO device on the AST2400 to + * enable the Uart device. + */ + class Ast2400Uart : public Uart + { + + public: + enum consoleConfig_t + { + NONE = 0x00, // No output selected + SELECT_SUART = 0x40, // SIO Uart + SELECT_VUART = 0x80, // SOL virtual uart + RESERVED = 0xc0, // Reserved + }; + + private: + // $TODO RTC:115576 remove these sio write functions when SIO dd code + // is completed // Perform raw LPC writes to SIO region. - errlHndl_t _writeReg(uint64_t i_addr, uint8_t i_byte) + errlHndl_t _writeReg(uint8_t i_addr, uint8_t i_byte) { size_t len = sizeof(i_byte); return deviceWrite(TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, - &i_byte, - len, - DEVICE_LPC_ADDRESS(LPC::TRANS_IO, i_addr)); + &i_byte, + len, + DEVICE_LPC_ADDRESS(LPC::TRANS_IO, i_addr)); } - public: + // write i_data to register i_reg + errlHndl_t writeSIOReg( uint8_t i_reg, uint8_t i_data ) + { + errlHndl_t l_err = NULL; + + do{ - virtual void initialize() + l_err = _writeReg( SIO_ADDR_REG_2E, i_data ); + + if(l_err) { break; } + + l_err = _writeReg( SIO_DATA_REG_2F, i_reg ); + + }while(0); + + return l_err; + } + + // Perform reads from the SIO register region. + errlHndl_t readSIOReg(uint8_t i_reg, uint8_t &o_byte) + { + errlHndl_t l_err = NULL; + + size_t len = sizeof(o_byte); + + do{ + l_err = deviceWrite( + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &i_reg, + len, + DEVICE_LPC_ADDRESS(LPC::TRANS_IO, SIO_ADDR_REG_2E)); + + if(l_err) { break; } + + l_err = deviceRead( + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &o_byte, + len, + DEVICE_LPC_ADDRESS(LPC::TRANS_IO, SIO_DATA_REG_2F)); + }while(0); + + return l_err; + } + + // setup the AHB access + errlHndl_t ahbSioAddressPrep(uint32_t reg) + { + errlHndl_t l_err = NULL; + + do{ + // Select logical device D (LPC2AHB) + l_err = writeSIOReg( 0x07, 0x0D ); + if( l_err ) { break; } + + /* Enable iLPC->AHB */ + l_err = writeSIOReg( 0x30, 0x01 ); + if( l_err ) { break; } + + /* Address */ + l_err = writeSIOReg(0xF0, (reg >> 24) & 0xff); + if( l_err ) {break; } + + l_err = writeSIOReg(0xF1, (reg >> 16) & 0xff); + if( l_err ) {break; } + + l_err = writeSIOReg(0xF2, (reg >> 8) & 0xff); + if( l_err ) {break; } + + l_err = writeSIOReg(0xF3, (reg ) & 0xff); + if( l_err ) {break; } + + /* bytes per cycle type */ + l_err = writeSIOReg(0xF8, 0x02); + if( l_err ) {break; } + + }while(0); + + return l_err; + } + + errlHndl_t ahbSioWrite(uint32_t reg, uint32_t val ) + { + errlHndl_t l_err = NULL; + + do{ + + l_err = ahbSioAddressPrep( reg); + if( l_err ) { break; } + + /* Write data */ + l_err = writeSIOReg(0xF4, val >> 24); + if( l_err ) { break; } + l_err = writeSIOReg(0xF5, val >> 16); + if( l_err ) { break; } + l_err = writeSIOReg(0xF6, val >> 8); + if( l_err ) { break; } + l_err = writeSIOReg(0xF7, val); + if( l_err ) { break; } + + /* Trigger the write with the magic number */ + l_err = writeSIOReg(0xFe, 0xcf); + + }while(0); + + return l_err; + } + + errlHndl_t ahbSioRead( uint32_t reg, uint32_t &o_data ) + { + errlHndl_t l_err = NULL; + uint8_t tmp_data = 0; + o_data = 0; + + do{ + + l_err = ahbSioAddressPrep(reg); + if(l_err){break;} + + /* Trigger the read - ignore the output data */ + l_err = readSIOReg(0xFE, tmp_data); + if(l_err){break;} + + tmp_data = 0; + + /* Read results */ + l_err = readSIOReg(0xF4, tmp_data ); + if(l_err){;break;} + o_data = tmp_data; + + l_err = readSIOReg(0xF5, tmp_data ); + if(l_err){break;} + o_data = (o_data << 8) | tmp_data; + + l_err = readSIOReg(0xF6, tmp_data ); + if(l_err){break;} + o_data = (o_data << 8) | tmp_data; + + l_err = readSIOReg(0xF7, tmp_data ); + if(l_err){break;} + o_data = (o_data << 8) | tmp_data; + + }while(0); + + return l_err; + } + + private: + + void initializeSUART() { errlHndl_t l_errl = NULL; do { - - // Unlock the SIO registers - // (write 0xA5 password to offset 0x2E two times) - l_errl = _writeReg( 0x2e, 0xA5 ); - if (l_errl) { break; } - l_errl = _writeReg( 0x2e, 0xA5 ); - if (l_errl) { break; } - - // Select logical device 2 (SUART1) in SIO - l_errl = _writeReg( 0x2e, 0x07 ); // select logical dev number - if (l_errl) { break; } - l_errl = _writeReg( 0x2f, 0x02 ); // write device 2 + // Select logical device 2 (SUART1) in SI) + l_errl = writeSIOReg( 0x07, 0x02); if (l_errl) { break; } // Disable SUART1 to change settings - l_errl = _writeReg( 0x2e, 0x30 ); // select SIO base enable - if (l_errl) { break; } - l_errl = _writeReg( 0x2f, 0x00 ); // clear enable + l_errl = writeSIOReg( 0x30, 0x00 ); if (l_errl) { break; } // Set SUART1 addr to g_uartBase - l_errl = _writeReg( 0x2e, 0x60 ); // select SIO addr[7:3] - if (l_errl) { break; } - l_errl = _writeReg( 0x2f, (g_uartBase >> 8) & 0xFF ); + l_errl = writeSIOReg( 0x60, (g_uartBase >> 8) & 0xFF ); if (l_errl) { break; } - l_errl = _writeReg( 0x2e, 0x61 ); // select SIO addr[15:8] - if (l_errl) { break; } - l_errl = _writeReg( 0x2f, (g_uartBase & 0xFF) ); + + l_errl = writeSIOReg( 61, (g_uartBase & 0xFF) ); if (l_errl) { break; } // Set the SerIRQ - l_errl = _writeReg( 0x2e, 0x70 ); + l_errl = writeSIOReg( 0x70, SERIAL_IRQ ); if (l_errl) { break; } - l_errl = _writeReg( 0x2f, 0x04 ); - if (l_errl) { break; } - l_errl = _writeReg( 0x2e, 0x71 ); + + l_errl = writeSIOReg( 0x71, 0x01 ); if (l_errl) { break; } - l_errl = _writeReg( 0x2f, 0x01 ); + // Enable SUART1 - l_errl = _writeReg( 0x2e, 0x30 ); // select SIO base enable - if (l_errl) { break; } - l_errl = _writeReg( 0x2f, 0x01 ); // write enable + l_errl = writeSIOReg( 0x30, 0x01 ); // select SIO base enable if (l_errl) { break; } //@fixme-RTC:115576 - Leaving SIO unlocked for now to allow @@ -119,8 +274,202 @@ class Ast2400Uart : public Uart Uart::initialize(); } -}; + // initialize for SOL support + void initializeVUART() + { + errlHndl_t l_err = NULL; + + do{ + uint32_t v; + + /* configure IRQ level as low */ + l_err = ahbSioRead(VUART1_GCTRLA, v); + if(l_err){break;} + v = v & ~2u; + l_err = ahbSioWrite(VUART1_GCTRLA, v); + if(l_err){break;} + + /* configure the IRQ number */ + l_err = ahbSioRead(VUART1_GCTRLB, v); + if(l_err){break;} + + v = (v & ~0xf0u) | ((SERIAL_IRQ << 4)); + l_err = ahbSioWrite(VUART1_GCTRLB,v); + if(l_err){break;} + + /* configure the address */ + l_err = ahbSioWrite(VUART1_ADDRL, g_uartBase & 0xff); + if(l_err){break;} + + l_err = ahbSioWrite(VUART1_ADDRH, g_uartBase >> 8); + + }while(0); + + if (l_err) + { + printk("VUART: config failed at\n"); + setFailed(); + errlCommit(l_err, CONSOLE_COMP_ID); + } + else + { + printk("VUART: config SUCCESS\n" ); + } + + Uart::initialize(); + } + + void disableVUART() + { + errlHndl_t l_err = NULL; + + do{ + // read the control reg, mask off the enabled bit + // and write it back + uint32_t reg_value = 0; + + l_err = ahbSioRead(VUART1_GCTRLA, reg_value ); + if(l_err){break;} + + // mask off the low order bit to mark the vuart as disabled + reg_value &= 0xFE; + l_err = ahbSioWrite(VUART1_GCTRLA, reg_value ); + if(l_err){break;} + + + + }while(0); + + if (l_err) + { + errlCommit(l_err, CONSOLE_COMP_ID); + } + }; + + void disableSUART() + { + errlHndl_t l_err = NULL; + + do{ + + // select device 2 - UART1 + l_err = writeSIOReg(0x07, 0x02); + if(l_err){break;} + + // clear the uart enable from base ctl reg + l_err = writeSIOReg(0x30, 0); + + }while(0); + + if (l_err) + { + errlCommit(l_err, CONSOLE_COMP_ID); + } + }; + + virtual void unlockSIO() + { + errlHndl_t l_err = NULL; + do{ + // Unlock the SIO registers + // (write 0xA5 password to offset 0x2E two times) + l_err = _writeReg( SIO_ADDR_REG_2E, 0xA5 ); + if (l_err) { break; } + + l_err = _writeReg( SIO_ADDR_REG_2E, 0xA5 ); + + }while(0); + + if (l_err) + { + errlCommit(l_err, CONSOLE_COMP_ID); + } + + } + + public: + + virtual void initialize() + { + // read the SIO register set by the BMC to determine uart config + const uint8_t expected_version = + INITSERVICE::BOOTCONFIG::BOOT_FLAGS_VERSION_1; + + uint8_t this_version = 0x00; + + errlHndl_t l_err = NULL; + + uint8_t uart_config = 0x00; + + do{ + // allow access to the registers + unlockSIO(); + + // verify the boot flags version from register 0x28 + l_err = readSIOReg( 0x28, this_version ); + + if (l_err) { break; } + + // is it the version we expected? + if( expected_version == this_version ) + { + l_err = readSIOReg(0x2d, uart_config); + + if (l_err) { break; } + + // determine which config has been selected + consoleConfig_t config = + static_cast<consoleConfig_t>(uart_config & CONFIG_MASK); + + switch ( config ) + { + case SELECT_SUART: + { + printk("ast2400: SUART config in process\n"); + disableVUART(); + initializeSUART(); + break; + } + case SELECT_VUART: + { + printk("ast2400: VUART config in process\n"); + disableSUART(); + initializeVUART(); + break; + } + case NONE: + { + // no config selected disable both + disableSUART(); + disableVUART(); + printk("ast2400: no config selected, " + "disable console output.\n"); + } + default: + { + printk("ast2400: invalid config data" + " default to SUART configuration\n"); + initializeSUART(); + } + } + } + else + { + // invalid version read from SIO register 0x28 + printk("ast2400: Invalid boot config version %d\n", this_version); + initializeSUART(); + } + + }while(0); + + if (l_err) + { + setFailed(); + errlCommit(l_err, CONSOLE_COMP_ID); + } + } + }; CONSOLE_UART_DEFINE_DEVICE(Ast2400Uart); -} +}; |