xref: /linux/drivers/gpu/drm/xe/xe_sysctrl.c (revision 4dd10fbbeb9c33709edc89916e19c03c780a0751)
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