#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"
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);
}
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);
}
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);
}
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);
}