// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later /* Copyright 2013-2019 IBM Corp. */ #include #include #include #include #include #include #include #include #include #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 = cpu_to_be32(PSI_DMA_MEMCONS); t = be64_to_cpu(memcons.obuf_phys) - INMEM_CON_START + PSI_DMA_LOG_BUF; debug_descriptor.memcons_obuf_tce = cpu_to_be32(t); t = be64_to_cpu(memcons.ibuf_phys) - INMEM_CON_START + PSI_DMA_LOG_BUF; debug_descriptor.memcons_ibuf_tce = cpu_to_be32(t); t = PSI_DMA_TRACE_BASE; for (i = 0; i < be32_to_cpu(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; uint64_t trace_phys = be64_to_cpu(debug_descriptor.trace_phys[i]); uint32_t trace_size = be32_to_cpu(debug_descriptor.trace_size[i]); tstart = ALIGN_DOWN(trace_phys, 0x1000); tend = ALIGN_UP(trace_phys + trace_size, 0x1000); toff = trace_phys - tstart; tsize = tend - tstart; fsp_tce_map(t, (void *)tstart, tsize); debug_descriptor.trace_tce[i] = cpu_to_be32(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; /* Clear flash hook */ fsp_flash_term_hook = NULL; 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(); /* Clear flash hook */ fsp_flash_term_hook = NULL; 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, __be64 *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, };