|
| 1 | +/* IBM_PROLOG_BEGIN_TAG */ |
| 2 | +/* This is an automatically generated prolog. */ |
| 3 | +/* */ |
| 4 | +/* $Source: src/occ_405/firdata/ast_mboxdd.c $ */ |
| 5 | +/* */ |
| 6 | +/* OpenPOWER OnChipController Project */ |
| 7 | +/* */ |
| 8 | +/* Contributors Listed Below - COPYRIGHT 2017 */ |
| 9 | +/* [+] International Business Machines Corp. */ |
| 10 | +/* */ |
| 11 | +/* */ |
| 12 | +/* Licensed under the Apache License, Version 2.0 (the "License"); */ |
| 13 | +/* you may not use this file except in compliance with the License. */ |
| 14 | +/* You may obtain a copy of the License at */ |
| 15 | +/* */ |
| 16 | +/* http://www.apache.org/licenses/LICENSE-2.0 */ |
| 17 | +/* */ |
| 18 | +/* Unless required by applicable law or agreed to in writing, software */ |
| 19 | +/* distributed under the License is distributed on an "AS IS" BASIS, */ |
| 20 | +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ |
| 21 | +/* implied. See the License for the specific language governing */ |
| 22 | +/* permissions and limitations under the License. */ |
| 23 | +/* */ |
| 24 | +/* IBM_PROLOG_END_TAG */ |
| 25 | +/** |
| 26 | + * @file ast_mboxdd.C |
| 27 | + * |
| 28 | + * @brief Implementation of the PNOR Accesser using the AST MBOX protocol |
| 29 | + */ |
| 30 | + |
| 31 | +/*****************************************************************************/ |
| 32 | +// I n c l u d e s |
| 33 | +/*****************************************************************************/ |
| 34 | +#include <native.h> |
| 35 | +#include <norflash.h> |
| 36 | +#include <ast_mboxdd.h> |
| 37 | +#include <lpc.h> |
| 38 | +extern int TRACE_LPC; |
| 39 | +int TRACE_MBOX = 0; |
| 40 | + |
| 41 | +/*****************************************************************************/ |
| 42 | +/* C o n s t a n t s */ |
| 43 | +/*****************************************************************************/ |
| 44 | + |
| 45 | +/*****************************************************************************/ |
| 46 | +/* G l o b a l s */ |
| 47 | +/*****************************************************************************/ |
| 48 | + |
| 49 | +/*****************************************************************************/ |
| 50 | +/* M e t h o d s */ |
| 51 | +/*****************************************************************************/ |
| 52 | + |
| 53 | +errorHndl_t writeRegSIO(uint8_t i_regAddr, uint8_t i_data) |
| 54 | +{ |
| 55 | + errorHndl_t l_err = NO_ERROR; |
| 56 | + |
| 57 | + do { |
| 58 | + size_t reg_size = sizeof(uint8_t); |
| 59 | + |
| 60 | + /* Write out the register address */ |
| 61 | + l_err = lpc_write( LPC_TRANS_IO, SIO_ADDR_REG_2E, |
| 62 | + &i_regAddr, |
| 63 | + reg_size ); |
| 64 | + if( l_err ) { break; } |
| 65 | + |
| 66 | + /* Write out the register data */ |
| 67 | + l_err = lpc_write( LPC_TRANS_IO, SIO_DATA_REG_2F, |
| 68 | + &i_data, |
| 69 | + reg_size ); |
| 70 | + if( l_err ) { break; } |
| 71 | + |
| 72 | + } while(0); |
| 73 | + |
| 74 | + return l_err; |
| 75 | +} |
| 76 | + |
| 77 | +errorHndl_t readRegSIO(uint8_t i_regAddr, uint8_t* o_data) |
| 78 | +{ |
| 79 | + errorHndl_t l_err = NO_ERROR; |
| 80 | + |
| 81 | + do { |
| 82 | + size_t reg_size = sizeof(uint8_t); |
| 83 | + |
| 84 | + /* Write out the register address */ |
| 85 | + l_err = lpc_write( LPC_TRANS_IO, SIO_ADDR_REG_2E, |
| 86 | + &i_regAddr, |
| 87 | + reg_size ); |
| 88 | + if( l_err ) { break; } |
| 89 | + |
| 90 | + /* Read in the register data */ |
| 91 | + l_err = lpc_read( LPC_TRANS_IO, SIO_DATA_REG_2F, |
| 92 | + o_data, |
| 93 | + reg_size ); |
| 94 | + if( l_err ) { break; } |
| 95 | + |
| 96 | + } while(0); |
| 97 | + |
| 98 | + return l_err; |
| 99 | +} |
| 100 | + |
| 101 | +errorHndl_t mboxOut(uint64_t i_addr, uint8_t i_byte) |
| 102 | +{ |
| 103 | + size_t len = sizeof(i_byte); |
| 104 | + |
| 105 | + return lpc_write( LPC_TRANS_IO, |
| 106 | + i_addr + MBOX_IO_BASE, |
| 107 | + &i_byte, |
| 108 | + len ); |
| 109 | +} |
| 110 | + |
| 111 | +errorHndl_t mboxIn(uint64_t i_addr, uint8_t *o_byte) |
| 112 | +{ |
| 113 | + size_t len = sizeof(o_byte); |
| 114 | + |
| 115 | + return lpc_read( LPC_TRANS_IO, |
| 116 | + i_addr + MBOX_IO_BASE, |
| 117 | + o_byte, |
| 118 | + len ); |
| 119 | +} |
| 120 | + |
| 121 | +errorHndl_t doMessage( astMbox_t *io_mbox, mboxMessage_t *io_msg ) |
| 122 | +{ |
| 123 | + uint8_t* l_data = ((uint8_t*)((char*)&io_msg)); |
| 124 | + errorHndl_t l_err = NO_ERROR; |
| 125 | + uint8_t l_stat1; |
| 126 | + uint8_t l_flags; |
| 127 | + uint32_t l_loops = 0; |
| 128 | + bool l_prot_error = false; |
| 129 | + int i; |
| 130 | + |
| 131 | + TRAC_INFO( "doMessage(0x%02x)", io_msg->iv_cmd ); |
| 132 | + io_msg->iv_seq = io_mbox->iv_mboxMsgSeq++; |
| 133 | + |
| 134 | + do |
| 135 | + { |
| 136 | + /* Write message out */ |
| 137 | + for (i = 0; i < BMC_MBOX_DATA_REGS && !l_err; i++) |
| 138 | + { |
| 139 | + l_err = mboxOut(i, l_data[i]); |
| 140 | + } |
| 141 | + |
| 142 | + if ( l_err ) |
| 143 | + { |
| 144 | + break; |
| 145 | + } |
| 146 | + |
| 147 | + /* Clear status1 response bit as it was just set via reg write*/ |
| 148 | + l_err = mboxOut(MBOX_STATUS_1, MBOX_STATUS1_RESP); |
| 149 | + |
| 150 | + if ( l_err ) |
| 151 | + { |
| 152 | + break; |
| 153 | + } |
| 154 | + |
| 155 | + /* Ping BMC */ |
| 156 | + l_err = mboxOut(MBOX_HOST_CTRL, MBOX_CTRL_INT_SEND); |
| 157 | + |
| 158 | + if ( l_err ) |
| 159 | + { |
| 160 | + break; |
| 161 | + } |
| 162 | + |
| 163 | + TRAC_INFO( "Command sent, waiting for response..."); |
| 164 | + |
| 165 | + /* Wait for response */ |
| 166 | + while ( l_loops++ < MBOX_MAX_RESP_WAIT_US && !l_err ) |
| 167 | + { |
| 168 | + l_err = mboxIn(MBOX_STATUS_1, &l_stat1); |
| 169 | + |
| 170 | + if ( l_err ) |
| 171 | + { |
| 172 | + break; |
| 173 | + } |
| 174 | + |
| 175 | + l_err = mboxIn(MBOX_FLAG_REG, &l_flags); |
| 176 | + |
| 177 | + if ( l_err ) |
| 178 | + { |
| 179 | + break; |
| 180 | + } |
| 181 | + |
| 182 | + if ( l_stat1 & MBOX_STATUS1_RESP ) |
| 183 | + { |
| 184 | + break; |
| 185 | + } |
| 186 | + |
| 187 | + sleep(1000); |
| 188 | + } |
| 189 | + |
| 190 | + if ( l_err ) |
| 191 | + { |
| 192 | + TRAC_INFO( "Got error waiting for response !"); |
| 193 | + break; |
| 194 | + } |
| 195 | + |
| 196 | + if ( !(l_stat1 & MBOX_STATUS1_RESP) ) |
| 197 | + { |
| 198 | + TRAC_INFO( "Timeout waiting for response !"); |
| 199 | + |
| 200 | + // Don't try to interrupt the BMC anymore |
| 201 | + l_err = mboxOut(MBOX_HOST_CTRL, 0); |
| 202 | + |
| 203 | + if ( l_err) |
| 204 | + { |
| 205 | + //Note the command failed |
| 206 | + TRAC_INFO( "Error communicating with MBOX daemon"); |
| 207 | + TRAC_INFO( "Mbox status 1 reg: %x", l_stat1); |
| 208 | + TRAC_INFO( "Mbox flag reg: %x", l_flags); |
| 209 | + } |
| 210 | + |
| 211 | + // Tell the code below that we generated the error |
| 212 | + // (not an LPC error) |
| 213 | + l_prot_error = true; |
| 214 | + break; |
| 215 | + } |
| 216 | + |
| 217 | + /* Clear status */ |
| 218 | + l_err = mboxOut(MBOX_STATUS_1, MBOX_STATUS1_RESP); |
| 219 | + |
| 220 | + if (l_err) |
| 221 | + { |
| 222 | + TRAC_INFO( "Got error clearing status"); |
| 223 | + break; |
| 224 | + } |
| 225 | + |
| 226 | + // Remember some message fields before they get overwritten |
| 227 | + // by the response |
| 228 | + uint8_t old_seq = io_msg->iv_seq; |
| 229 | + |
| 230 | + // Read response |
| 231 | + TRAC_INFO( "Reading response data..."); |
| 232 | + |
| 233 | + for (i = 0; i < BMC_MBOX_DATA_REGS && !l_err; i++) |
| 234 | + { |
| 235 | + l_err = mboxIn(i, &l_data[i]); |
| 236 | + } |
| 237 | + |
| 238 | + if ( l_err ) |
| 239 | + { |
| 240 | + TRAC_INFO( "Got error reading response !"); |
| 241 | + break; |
| 242 | + } |
| 243 | + |
| 244 | + TRAC_INFO( "Message: cmd:%02x seq:%02x a:%02x %02x %02x %02x %02x..resp:%02x", |
| 245 | + io_msg->iv_cmd, io_msg->iv_seq, io_msg->iv_args[0], |
| 246 | + io_msg->iv_args[1], io_msg->iv_args[2], io_msg->iv_args[3], |
| 247 | + io_msg->iv_args[4], io_msg->iv_resp); |
| 248 | + |
| 249 | + if (old_seq != io_msg->iv_seq) |
| 250 | + { |
| 251 | + TRAC_INFO( "bad sequence number in mbox message, got %d want %d", |
| 252 | + io_msg->iv_seq, old_seq); |
| 253 | + |
| 254 | + l_err = -1; |
| 255 | + break; |
| 256 | + } |
| 257 | + |
| 258 | + if (io_msg->iv_resp != MBOX_R_SUCCESS) |
| 259 | + { |
| 260 | + TRAC_INFO( "BMC mbox command failed with err %d", |
| 261 | + io_msg->iv_resp); |
| 262 | + l_err = -1; |
| 263 | + // Tell code below that we generated the error (not an LPC error) |
| 264 | + l_prot_error = true; |
| 265 | + break; |
| 266 | + } |
| 267 | + |
| 268 | + } |
| 269 | + while(0); |
| 270 | + |
| 271 | + // If we got an LPC error, commit it and generate our own |
| 272 | + if ( l_err && !l_prot_error ) |
| 273 | + { |
| 274 | + } |
| 275 | + |
| 276 | + TRAC_INFO( "doMessage() resp=0x%02x", |
| 277 | + io_msg->iv_resp ); |
| 278 | + return l_err; |
| 279 | +} |
| 280 | + |
| 281 | +errorHndl_t initializeMbox(void) |
| 282 | +{ |
| 283 | + errorHndl_t l_errl = NO_ERROR; |
| 284 | + |
| 285 | + TRAC_INFO("initializeMBOX()"); |
| 286 | + |
| 287 | + do |
| 288 | + { |
| 289 | + size_t reg_size = sizeof(uint8_t); |
| 290 | + |
| 291 | + //First need to unlock SIO registers |
| 292 | + /* Send SuperIO password - send A5 twice to offset 0x2E */ |
| 293 | + uint8_t data = SIO_PASSWORD_REG; |
| 294 | + l_errl = lpc_write( LPC_TRANS_IO, SIO_ADDR_REG_2E, |
| 295 | + &data, reg_size ); |
| 296 | + if( l_errl ) { break; } |
| 297 | + |
| 298 | + l_errl = lpc_write( LPC_TRANS_IO, SIO_ADDR_REG_2E, |
| 299 | + &data, reg_size ); |
| 300 | + if( l_errl ) { break; } |
| 301 | + |
| 302 | + //Second need to select Mailbox SIO Device |
| 303 | + // Register 0x07 is device select reg |
| 304 | + // Device 0x0E is the sio mailbox device |
| 305 | + l_errl = writeRegSIO( SIO_DEVICE_SELECT_REG, SIO_MB ); |
| 306 | + if( l_errl ) { break; } |
| 307 | + |
| 308 | + //First disable SIO Mailbox engine to configure it |
| 309 | + // 0x30 - Enable/Disable Reg |
| 310 | + // 0x00 - Disable Device (previously selected mailbox device) |
| 311 | + l_errl = writeRegSIO( 0x30, 0x00 ); |
| 312 | + |
| 313 | + if (l_errl) |
| 314 | + { |
| 315 | + break; |
| 316 | + } |
| 317 | + |
| 318 | + // Set MBOX Base Address |
| 319 | + //Regs 0x60/0x61 are a BAR-like reg to configure the MBOX base address |
| 320 | + l_errl = writeRegSIO( 0x60, (MBOX_IO_BASE >> 8) & 0xFF ); |
| 321 | + |
| 322 | + if (l_errl) |
| 323 | + { |
| 324 | + break; |
| 325 | + } |
| 326 | + |
| 327 | + // Set other half of MBOX Base Address |
| 328 | + l_errl = writeRegSIO( 0x61, MBOX_IO_BASE & 0xFF ); |
| 329 | + |
| 330 | + if (l_errl) |
| 331 | + { |
| 332 | + break; |
| 333 | + } |
| 334 | + |
| 335 | + //Configure MBOX IRQs |
| 336 | + //Regs 0x70 / 0x71 control that |
| 337 | + l_errl = writeRegSIO( 0x70, MBOX_LPC_IRQ ); |
| 338 | + |
| 339 | + if (l_errl) |
| 340 | + { |
| 341 | + break; |
| 342 | + } |
| 343 | + |
| 344 | + //Other half of MBOX IRQ Configuration |
| 345 | + // 1 == Low level trigger |
| 346 | + l_errl = writeRegSIO( 0x71, 1 ); |
| 347 | + |
| 348 | + if (l_errl) |
| 349 | + { |
| 350 | + break; |
| 351 | + } |
| 352 | + |
| 353 | + //Re-enable Device now that base addr and IRQs are configured |
| 354 | + // 1 == Enable Device |
| 355 | + l_errl = writeRegSIO( 0x30, 0x01 ); |
| 356 | + |
| 357 | + if (l_errl) |
| 358 | + { |
| 359 | + break; |
| 360 | + } |
| 361 | + } |
| 362 | + while(0); |
| 363 | + |
| 364 | + return l_errl; |
| 365 | +} |
0 commit comments