1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2026 Intel Corporation 4 */ 5 6 #include <linux/device.h> 7 #include <linux/mutex.h> 8 9 #include <drm/drm_managed.h> 10 11 #include "regs/xe_irq_regs.h" 12 #include "regs/xe_sysctrl_regs.h" 13 #include "xe_device.h" 14 #include "xe_mmio.h" 15 #include "xe_pm.h" 16 #include "xe_printk.h" 17 #include "xe_soc_remapper.h" 18 #include "xe_sysctrl.h" 19 #include "xe_sysctrl_mailbox.h" 20 #include "xe_sysctrl_mailbox_types.h" 21 #include "xe_sysctrl_types.h" 22 23 /** 24 * DOC: System Controller (sysctrl) 25 * 26 * System Controller (sysctrl) is a firmware-managed entity on Intel dGPUs 27 * responsible for selected low-level platform management functions. 28 * Communication between driver and System Controller is performed 29 * via a mailbox interface, enabling command and response exchange. 30 * 31 * This module provides initialization and support code for interacting 32 * with System Controller through the mailbox interface. 33 */ 34 35 /* Application status flags reported in xe_sysctrl_app_status_resp.flags */ 36 #define XE_SYSCTRL_APP_RESP_VALID BIT(0) 37 #define XE_SYSCTRL_APP_RESP_BOOTED BIT(1) 38 #define XE_SYSCTRL_APP_RESP_INITIALIZED BIT(2) 39 40 /* 41 * Known System Controller application identifiers, keyed by firmware 42 * application ID. 43 */ 44 enum xe_sysctrl_app_id { 45 XE_SYSCTRL_APP_OCODE = 0x0C, 46 XE_SYSCTRL_APP_DIAG = 0x0D, 47 }; 48 49 static void sysctrl_fini(void *arg) 50 { 51 struct xe_device *xe = arg; 52 struct xe_sysctrl *sc = &xe->sc; 53 54 disable_work_sync(&sc->work); 55 xe->soc_remapper.set_sysctrl_region(xe, 0); 56 } 57 58 static void xe_sysctrl_work(struct work_struct *work) 59 { 60 struct xe_sysctrl *sc = container_of(work, struct xe_sysctrl, work); 61 struct xe_device *xe = sc_to_xe(sc); 62 63 guard(xe_pm_runtime)(xe); 64 xe_sysctrl_event(sc); 65 } 66 67 /** 68 * xe_sysctrl_init() - Initialize System Controller subsystem 69 * @xe: xe device instance 70 * 71 * Entry point for System Controller initialization, called from xe_device_probe. 72 * This function checks platform support and initializes the system controller. 73 * 74 * Return: 0 on success, error code on failure 75 */ 76 int xe_sysctrl_init(struct xe_device *xe) 77 { 78 struct xe_tile *tile = xe_device_get_root_tile(xe); 79 struct xe_sysctrl *sc = &xe->sc; 80 int ret; 81 82 if (!xe->info.has_soc_remapper_sysctrl) 83 return 0; 84 85 if (!xe->info.has_sysctrl) 86 return 0; 87 88 sc->mmio = devm_kzalloc_obj(xe->drm.dev, *sc->mmio); 89 if (!sc->mmio) 90 return -ENOMEM; 91 92 xe_mmio_init(sc->mmio, tile, tile->mmio.regs, tile->mmio.regs_size); 93 sc->mmio->adj_offset = SYSCTRL_BASE; 94 sc->mmio->adj_limit = U32_MAX; 95 96 ret = devm_mutex_init(xe->drm.dev, &sc->cmd_lock); 97 if (ret) 98 return ret; 99 100 ret = devm_mutex_init(xe->drm.dev, &sc->event_lock); 101 if (ret) 102 return ret; 103 104 xe->soc_remapper.set_sysctrl_region(xe, SYSCTRL_MAILBOX_INDEX); 105 INIT_WORK(&sc->work, xe_sysctrl_work); 106 107 return devm_add_action_or_reset(xe->drm.dev, sysctrl_fini, xe); 108 } 109 110 /** 111 * xe_sysctrl_irq_handler() - Handler for System Controller interrupts 112 * @xe: xe device instance 113 * @master_ctl: interrupt register 114 * 115 * Handle interrupts generated by System Controller. 116 */ 117 void xe_sysctrl_irq_handler(struct xe_device *xe, u32 master_ctl) 118 { 119 struct xe_sysctrl *sc = &xe->sc; 120 121 if (!xe->info.has_sysctrl || !sc->work.func) 122 return; 123 124 if (master_ctl & SYSCTRL_IRQ) 125 schedule_work(&sc->work); 126 } 127 128 /** 129 * xe_sysctrl_pm_resume() - System Controller resume handler 130 * @xe: xe device instance 131 * 132 * Invoked during system resume (S3/S4 to S0) and runtime resume from D3cold. 133 * Restores SoC remapper configuration. 134 */ 135 void xe_sysctrl_pm_resume(struct xe_device *xe) 136 { 137 if (!xe->info.has_soc_remapper_sysctrl) 138 return; 139 140 if (!xe->info.has_sysctrl) 141 return; 142 143 xe->soc_remapper.set_sysctrl_region(xe, SYSCTRL_MAILBOX_INDEX); 144 } 145 146 static enum xe_sysctrl_fw_status 147 xe_sysctrl_check_app_status(struct xe_device *xe, enum xe_sysctrl_app_id app_id) 148 { 149 struct xe_sysctrl_app_status_req req = {}; 150 struct xe_sysctrl_app_status_resp resp = {}; 151 struct xe_sysctrl_mailbox_command cmd = {}; 152 size_t out_len = 0; 153 u32 flags; 154 int ret; 155 156 req.app_id = (u8)app_id; 157 158 xe_sysctrl_create_command(&cmd, XE_SYSCTRL_GROUP_CORE, XE_SYSCTRL_CMD_GET_APP_STATUS_BY_ID, 159 &req, sizeof(req), &resp, sizeof(resp)); 160 161 ret = xe_sysctrl_send_command(&xe->sc, &cmd, &out_len); 162 if (ret) 163 return XE_SYSCTRL_FIRMWARE_COMM_FAILURE; 164 165 if (out_len != sizeof(resp)) { 166 xe_err(xe, "sysctrl: unexpected get app status response length %zu (expected %zu)\n", 167 out_len, sizeof(resp)); 168 return XE_SYSCTRL_FIRMWARE_COMM_FAILURE; 169 } 170 171 flags = resp.flags; 172 173 if (!(flags & XE_SYSCTRL_APP_RESP_VALID)) 174 return XE_SYSCTRL_FIRMWARE_APP_INVALID; 175 176 if (!(flags & XE_SYSCTRL_APP_RESP_BOOTED)) 177 return XE_SYSCTRL_FIRMWARE_APP_NOT_LOADED; 178 179 if (!(flags & XE_SYSCTRL_APP_RESP_INITIALIZED)) 180 return XE_SYSCTRL_FIRMWARE_APP_BOOTED; 181 182 return XE_SYSCTRL_FIRMWARE_APP_INITIALIZED; 183 } 184 185 /** 186 * xe_sysctrl_is_oobmsm_fw_ready() - Check if oCode firmware is fully initialized 187 * @xe: xe device instance 188 * 189 * Returns true if oCode firmware has reached the initialized state, indicating 190 * it is ready to handle requests. 191 * 192 * Callers must only invoke this on platforms where System Controller is 193 * present (xe->info.has_sysctrl). 194 * 195 * Return: true if oCode firmware is initialized, false otherwise 196 */ 197 bool xe_sysctrl_is_oobmsm_fw_ready(struct xe_device *xe) 198 { 199 return xe_sysctrl_check_app_status(xe, XE_SYSCTRL_APP_OCODE) == 200 XE_SYSCTRL_FIRMWARE_APP_INITIALIZED; 201 } 202 203 /** 204 * xe_sysctrl_is_diag_fw_ready() - Check if diag firmware is fully initialized 205 * @xe: xe device instance 206 * 207 * Returns true if diag firmware has reached the initialized state, indicating 208 * it is ready to handle requests. 209 * 210 * Callers must only invoke this on platforms where System Controller is 211 * present (xe->info.has_sysctrl). 212 * 213 * Return: true if diag firmware is initialized, false otherwise 214 */ 215 bool xe_sysctrl_is_diag_fw_ready(struct xe_device *xe) 216 { 217 return xe_sysctrl_check_app_status(xe, XE_SYSCTRL_APP_DIAG) == 218 XE_SYSCTRL_FIRMWARE_APP_INITIALIZED; 219 } 220