| // SPDX-License-Identifier: MIT |
| /* |
| * Copyright © 2026 Intel Corporation |
| */ |
| |
| #include <linux/device.h> |
| #include <linux/mutex.h> |
| |
| #include <drm/drm_managed.h> |
| |
| #include "regs/xe_irq_regs.h" |
| #include "regs/xe_sysctrl_regs.h" |
| #include "xe_device.h" |
| #include "xe_mmio.h" |
| #include "xe_pm.h" |
| #include "xe_soc_remapper.h" |
| #include "xe_sysctrl.h" |
| #include "xe_sysctrl_mailbox.h" |
| #include "xe_sysctrl_types.h" |
| |
| /** |
| * DOC: System Controller (sysctrl) |
| * |
| * System Controller (sysctrl) is a firmware-managed entity on Intel dGPUs |
| * responsible for selected low-level platform management functions. |
| * Communication between driver and System Controller is performed |
| * via a mailbox interface, enabling command and response exchange. |
| * |
| * This module provides initialization and support code for interacting |
| * with System Controller through the mailbox interface. |
| */ |
| static void sysctrl_fini(void *arg) |
| { |
| struct xe_device *xe = arg; |
| struct xe_sysctrl *sc = &xe->sc; |
| |
| disable_work_sync(&sc->work); |
| xe->soc_remapper.set_sysctrl_region(xe, 0); |
| } |
| |
| static void xe_sysctrl_work(struct work_struct *work) |
| { |
| struct xe_sysctrl *sc = container_of(work, struct xe_sysctrl, work); |
| struct xe_device *xe = sc_to_xe(sc); |
| |
| guard(xe_pm_runtime)(xe); |
| xe_sysctrl_event(sc); |
| } |
| |
| /** |
| * xe_sysctrl_init() - Initialize System Controller subsystem |
| * @xe: xe device instance |
| * |
| * Entry point for System Controller initialization, called from xe_device_probe. |
| * This function checks platform support and initializes the system controller. |
| * |
| * Return: 0 on success, error code on failure |
| */ |
| int xe_sysctrl_init(struct xe_device *xe) |
| { |
| struct xe_tile *tile = xe_device_get_root_tile(xe); |
| struct xe_sysctrl *sc = &xe->sc; |
| int ret; |
| |
| if (!xe->info.has_soc_remapper_sysctrl) |
| return 0; |
| |
| if (!xe->info.has_sysctrl) |
| return 0; |
| |
| sc->mmio = devm_kzalloc(xe->drm.dev, sizeof(*sc->mmio), GFP_KERNEL); |
| if (!sc->mmio) |
| return -ENOMEM; |
| |
| xe_mmio_init(sc->mmio, tile, tile->mmio.regs, tile->mmio.regs_size); |
| sc->mmio->adj_offset = SYSCTRL_BASE; |
| sc->mmio->adj_limit = U32_MAX; |
| |
| ret = devm_mutex_init(xe->drm.dev, &sc->cmd_lock); |
| if (ret) |
| return ret; |
| |
| ret = devm_mutex_init(xe->drm.dev, &sc->event_lock); |
| if (ret) |
| return ret; |
| |
| xe->soc_remapper.set_sysctrl_region(xe, SYSCTRL_MAILBOX_INDEX); |
| xe_sysctrl_mailbox_init(sc); |
| INIT_WORK(&sc->work, xe_sysctrl_work); |
| |
| return devm_add_action_or_reset(xe->drm.dev, sysctrl_fini, xe); |
| } |
| |
| /** |
| * xe_sysctrl_irq_handler() - Handler for System Controller interrupts |
| * @xe: xe device instance |
| * @master_ctl: interrupt register |
| * |
| * Handle interrupts generated by System Controller. |
| */ |
| void xe_sysctrl_irq_handler(struct xe_device *xe, u32 master_ctl) |
| { |
| struct xe_sysctrl *sc = &xe->sc; |
| |
| if (!xe->info.has_sysctrl || !sc->work.func) |
| return; |
| |
| if (master_ctl & SYSCTRL_IRQ) |
| schedule_work(&sc->work); |
| } |
| |
| /** |
| * xe_sysctrl_pm_resume() - System Controller resume handler |
| * @xe: xe device instance |
| * |
| * Invoked during system resume (S3/S4 to S0) and runtime resume from D3cold. |
| * Restores SoC remapper configuration and reinitializes mailbox interface. |
| */ |
| void xe_sysctrl_pm_resume(struct xe_device *xe) |
| { |
| struct xe_sysctrl *sc = &xe->sc; |
| |
| if (!xe->info.has_soc_remapper_sysctrl) |
| return; |
| |
| if (!xe->info.has_sysctrl) |
| return; |
| |
| xe->soc_remapper.set_sysctrl_region(xe, SYSCTRL_MAILBOX_INDEX); |
| |
| xe_sysctrl_mailbox_init(sc); |
| } |