291 lines
6.8 KiB
C
291 lines
6.8 KiB
C
/* Copyright 2013-2017 IBM Corp.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
* implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
|
|
#include <skiboot.h>
|
|
#include <fsp.h>
|
|
#include <fsp-sysparam.h>
|
|
#include <opal.h>
|
|
#include <console.h>
|
|
#include <hostservices.h>
|
|
#include <ipmi.h>
|
|
#include <debug_descriptor.h>
|
|
#include <occ.h>
|
|
|
|
#include "ibm-fsp.h"
|
|
|
|
static void map_debug_areas(void)
|
|
{
|
|
uint64_t t, i;
|
|
|
|
/* Our memcons is in a section of its own and already
|
|
* aligned to 4K. The buffers are mapped as a whole
|
|
*/
|
|
fsp_tce_map(PSI_DMA_MEMCONS, &memcons, 0x1000);
|
|
fsp_tce_map(PSI_DMA_LOG_BUF, (void*)INMEM_CON_START, INMEM_CON_LEN);
|
|
|
|
debug_descriptor.memcons_tce = PSI_DMA_MEMCONS;
|
|
t = memcons.obuf_phys - INMEM_CON_START + PSI_DMA_LOG_BUF;
|
|
debug_descriptor.memcons_obuf_tce = t;
|
|
t = memcons.ibuf_phys - INMEM_CON_START + PSI_DMA_LOG_BUF;
|
|
debug_descriptor.memcons_ibuf_tce = t;
|
|
|
|
/* We only have space in the TCE table for the trace
|
|
* areas on P8
|
|
*/
|
|
if (proc_gen != proc_gen_p8)
|
|
return;
|
|
|
|
t = PSI_DMA_TRACE_BASE;
|
|
for (i = 0; i < debug_descriptor.num_traces; i++) {
|
|
/*
|
|
* Trace buffers are misaligned by 0x10 due to the lock
|
|
* in the trace structure, and their size is also not
|
|
* completely aligned. (They are allocated so that with
|
|
* the lock included, they do cover entire multiple of
|
|
* a 4K page however).
|
|
*
|
|
* This means we have to map the lock into the TCEs and
|
|
* align everything. Not a huge deal but needs to be
|
|
* taken into account.
|
|
*
|
|
* Note: Maybe we should map them read-only...
|
|
*/
|
|
uint64_t tstart, tend, toff, tsize;
|
|
|
|
tstart = ALIGN_DOWN(debug_descriptor.trace_phys[i], 0x1000);
|
|
tend = ALIGN_UP(debug_descriptor.trace_phys[i] +
|
|
debug_descriptor.trace_size[i], 0x1000);
|
|
toff = debug_descriptor.trace_phys[i] - tstart;
|
|
tsize = tend - tstart;
|
|
|
|
fsp_tce_map(t, (void *)tstart, tsize);
|
|
debug_descriptor.trace_tce[i] = t + toff;
|
|
t += tsize;
|
|
}
|
|
}
|
|
|
|
|
|
void ibm_fsp_init(void)
|
|
{
|
|
/* Early initializations of the FSP interface */
|
|
fsp_init();
|
|
map_debug_areas();
|
|
fsp_sysparam_init();
|
|
|
|
/* Get ready to receive E0 class messages. We need to respond
|
|
* to some of these for the init sequence to make forward progress
|
|
*/
|
|
fsp_console_preinit();
|
|
|
|
/* Get ready to receive OCC related messages */
|
|
occ_fsp_init();
|
|
|
|
/* Get ready to receive Memory [Un]corretable Error messages. */
|
|
fsp_memory_err_init();
|
|
|
|
/* Initialize elog access */
|
|
fsp_elog_read_init();
|
|
fsp_elog_write_init();
|
|
|
|
/* Initiate dump service */
|
|
fsp_dump_init();
|
|
|
|
/* Start FSP/HV state controller & perform OPL */
|
|
fsp_opl();
|
|
|
|
/* Preload hostservices lids */
|
|
hservices_lid_preload();
|
|
|
|
/* Initialize SP attention area */
|
|
fsp_attn_init();
|
|
|
|
/* Initialize monitoring of TOD topology change event notification */
|
|
fsp_chiptod_init();
|
|
|
|
/* Send MDST table notification to FSP */
|
|
op_display(OP_LOG, OP_MOD_INIT, 0x0000);
|
|
fsp_mdst_table_init();
|
|
|
|
/* Initialize the panel */
|
|
op_display(OP_LOG, OP_MOD_INIT, 0x0001);
|
|
fsp_oppanel_init();
|
|
|
|
/* Start the surveillance process */
|
|
op_display(OP_LOG, OP_MOD_INIT, 0x0002);
|
|
fsp_init_surveillance();
|
|
|
|
/* IPMI */
|
|
fsp_ipmi_init();
|
|
ipmi_opal_init();
|
|
|
|
/* Initialize sensor access */
|
|
op_display(OP_LOG, OP_MOD_INIT, 0x0003);
|
|
fsp_init_sensor();
|
|
|
|
/* LED */
|
|
op_display(OP_LOG, OP_MOD_INIT, 0x0004);
|
|
fsp_led_init();
|
|
|
|
/* Monitor for DIAG events */
|
|
op_display(OP_LOG, OP_MOD_INIT, 0x0005);
|
|
fsp_init_diag();
|
|
|
|
/* Finish initializing the console */
|
|
op_display(OP_LOG, OP_MOD_INIT, 0x0006);
|
|
fsp_console_init();
|
|
|
|
/* Read our initial RTC value */
|
|
op_display(OP_LOG, OP_MOD_INIT, 0x0008);
|
|
fsp_rtc_init();
|
|
|
|
/* Initialize code update access */
|
|
op_display(OP_LOG, OP_MOD_INIT, 0x0009);
|
|
fsp_code_update_init();
|
|
|
|
/* EPOW */
|
|
op_display(OP_LOG, OP_MOD_INIT, 0x000A);
|
|
fsp_epow_init();
|
|
|
|
/* EPOW */
|
|
op_display(OP_LOG, OP_MOD_INIT, 0x000B);
|
|
fsp_dpo_init();
|
|
|
|
/* Setup console */
|
|
if (fsp_present())
|
|
fsp_console_add_nodes();
|
|
|
|
if (proc_gen >= proc_gen_p9)
|
|
prd_init();
|
|
|
|
preload_io_vpd();
|
|
}
|
|
|
|
void ibm_fsp_finalise_dt(bool is_reboot)
|
|
{
|
|
if (is_reboot)
|
|
return;
|
|
|
|
/*
|
|
* LED related SPCN commands might take a while to
|
|
* complete. Call this as late as possible to
|
|
* ensure we have all the LED information.
|
|
*/
|
|
create_led_device_nodes();
|
|
|
|
/*
|
|
* OCC takes few secs to boot. Call this as late as
|
|
* as possible to avoid delay.
|
|
*/
|
|
occ_pstates_init();
|
|
|
|
/* Wait for FW VPD data read to complete */
|
|
fsp_code_update_wait_vpd(true);
|
|
|
|
fsp_console_select_stdout();
|
|
}
|
|
|
|
void ibm_fsp_exit(void)
|
|
{
|
|
op_panel_disable_src_echo();
|
|
|
|
/* Clear SRCs on the op-panel when Linux starts */
|
|
op_panel_clear_src();
|
|
}
|
|
|
|
int64_t ibm_fsp_cec_reboot(void)
|
|
{
|
|
uint32_t cmd = FSP_CMD_REBOOT;
|
|
|
|
if (!fsp_present())
|
|
return OPAL_UNSUPPORTED;
|
|
|
|
/* Flash new firmware */
|
|
if (fsp_flash_term_hook &&
|
|
fsp_flash_term_hook() == OPAL_SUCCESS)
|
|
cmd = FSP_CMD_DEEP_REBOOT;
|
|
|
|
printf("FSP: Sending 0x%02x reboot command to FSP...\n", cmd);
|
|
|
|
/* If that failed, talk to the FSP */
|
|
if (fsp_sync_msg(fsp_mkmsg(cmd, 0), true))
|
|
return OPAL_BUSY_EVENT;
|
|
|
|
return OPAL_SUCCESS;
|
|
}
|
|
|
|
int64_t ibm_fsp_cec_power_down(uint64_t request)
|
|
{
|
|
/* Request is:
|
|
*
|
|
* 0 = normal
|
|
* 1 = immediate
|
|
* (we do not allow 2 for "pci cfg reset" just yet)
|
|
*/
|
|
|
|
if (request !=0 && request != 1)
|
|
return OPAL_PARAMETER;
|
|
|
|
if (!fsp_present())
|
|
return OPAL_UNSUPPORTED;
|
|
|
|
/* Flash new firmware */
|
|
if (fsp_flash_term_hook)
|
|
fsp_flash_term_hook();
|
|
|
|
printf("FSP: Sending shutdown command to FSP...\n");
|
|
|
|
if (fsp_sync_msg(fsp_mkmsg(FSP_CMD_POWERDOWN_NORM, 1, request), true))
|
|
return OPAL_BUSY_EVENT;
|
|
|
|
fsp_reset_links();
|
|
return OPAL_SUCCESS;
|
|
}
|
|
|
|
int64_t ibm_fsp_sensor_read(uint32_t sensor_hndl, int token,
|
|
uint64_t *sensor_data)
|
|
{
|
|
return fsp_opal_read_sensor(sensor_hndl, token, sensor_data);
|
|
}
|
|
|
|
int __attrconst fsp_heartbeat_time(void)
|
|
{
|
|
/* Same as core/timer.c HEARTBEAT_DEFAULT_MS * 10 */
|
|
return 200 * 10;
|
|
}
|
|
|
|
static void fsp_psihb_interrupt(void)
|
|
{
|
|
/* Poll the console buffers on any interrupt since we don't
|
|
* get send notifications
|
|
*/
|
|
fsp_console_poll(NULL);
|
|
}
|
|
|
|
struct platform_psi fsp_platform_psi = {
|
|
.psihb_interrupt = fsp_psihb_interrupt,
|
|
.link_established = fsp_reinit_fsp,
|
|
.fsp_interrupt = fsp_interrupt,
|
|
};
|
|
|
|
struct platform_prd fsp_platform_prd = {
|
|
.msg_response = hservice_hbrt_msg_response,
|
|
.send_error_log = hservice_send_error_log,
|
|
.send_hbrt_msg = hservice_send_hbrt_msg,
|
|
.wakeup = hservice_wakeup,
|
|
.fsp_occ_load_start_status = fsp_occ_load_start_status,
|
|
.fsp_occ_reset_status = fsp_occ_reset_status,
|
|
};
|