1*81673325SDavid Zhang // SPDX-License-Identifier: GPL-2.0 2*81673325SDavid Zhang /* 3*81673325SDavid Zhang * Copyright (C) 2026, Advanced Micro Devices, Inc. 4*81673325SDavid Zhang */ 5*81673325SDavid Zhang 6*81673325SDavid Zhang #include "drm/amdxdna_accel.h" 7*81673325SDavid Zhang #include <drm/drm_device.h> 8*81673325SDavid Zhang #include <drm/drm_managed.h> 9*81673325SDavid Zhang #include <drm/drm_print.h> 10*81673325SDavid Zhang #include <drm/gpu_scheduler.h> 11*81673325SDavid Zhang #include <linux/iopoll.h> 12*81673325SDavid Zhang 13*81673325SDavid Zhang #include "aie.h" 14*81673325SDavid Zhang 15*81673325SDavid Zhang #define SMU_RESULT_OK 1 16*81673325SDavid Zhang 17*81673325SDavid Zhang /* SMU commands */ 18*81673325SDavid Zhang #define AIE_SMU_POWER_ON 0x3 19*81673325SDavid Zhang #define AIE_SMU_POWER_OFF 0x4 20*81673325SDavid Zhang #define AIE_SMU_SET_MPNPUCLK_FREQ 0x5 21*81673325SDavid Zhang #define AIE_SMU_SET_HCLK_FREQ 0x6 22*81673325SDavid Zhang #define AIE_SMU_SET_SOFT_DPMLEVEL 0x7 23*81673325SDavid Zhang #define AIE_SMU_SET_HARD_DPMLEVEL 0x8 24*81673325SDavid Zhang 25*81673325SDavid Zhang #define SMU_REG(s, reg) ((s)->smu_regs[reg]) 26*81673325SDavid Zhang 27*81673325SDavid Zhang struct smu_device { 28*81673325SDavid Zhang struct drm_device *ddev; 29*81673325SDavid Zhang struct smu_config conf; 30*81673325SDavid Zhang void __iomem *smu_regs[SMU_MAX_REGS]; 31*81673325SDavid Zhang }; 32*81673325SDavid Zhang 33*81673325SDavid Zhang static int aie_smu_exec(struct smu_device *smu, u32 reg_cmd, u32 reg_arg, u32 *out) 34*81673325SDavid Zhang { 35*81673325SDavid Zhang u32 resp; 36*81673325SDavid Zhang int ret; 37*81673325SDavid Zhang 38*81673325SDavid Zhang writel(0, SMU_REG(smu, SMU_RESP_REG)); 39*81673325SDavid Zhang writel(reg_arg, SMU_REG(smu, SMU_ARG_REG)); 40*81673325SDavid Zhang writel(reg_cmd, SMU_REG(smu, SMU_CMD_REG)); 41*81673325SDavid Zhang 42*81673325SDavid Zhang /* Clear and set SMU_INTR_REG to kick off */ 43*81673325SDavid Zhang writel(0, SMU_REG(smu, SMU_INTR_REG)); 44*81673325SDavid Zhang writel(1, SMU_REG(smu, SMU_INTR_REG)); 45*81673325SDavid Zhang 46*81673325SDavid Zhang ret = readx_poll_timeout(readl, SMU_REG(smu, SMU_RESP_REG), resp, 47*81673325SDavid Zhang resp, AIE_INTERVAL, AIE_TIMEOUT); 48*81673325SDavid Zhang if (ret) { 49*81673325SDavid Zhang drm_err(smu->ddev, "smu cmd %d timed out", reg_cmd); 50*81673325SDavid Zhang return ret; 51*81673325SDavid Zhang } 52*81673325SDavid Zhang 53*81673325SDavid Zhang if (out) 54*81673325SDavid Zhang *out = readl(SMU_REG(smu, SMU_OUT_REG)); 55*81673325SDavid Zhang 56*81673325SDavid Zhang if (resp != SMU_RESULT_OK) { 57*81673325SDavid Zhang drm_err(smu->ddev, "smu cmd %d failed, 0x%x", reg_cmd, resp); 58*81673325SDavid Zhang return -EINVAL; 59*81673325SDavid Zhang } 60*81673325SDavid Zhang 61*81673325SDavid Zhang return 0; 62*81673325SDavid Zhang } 63*81673325SDavid Zhang 64*81673325SDavid Zhang int aie_smu_init(struct smu_device *smu) 65*81673325SDavid Zhang { 66*81673325SDavid Zhang int ret; 67*81673325SDavid Zhang 68*81673325SDavid Zhang /* 69*81673325SDavid Zhang * Failing to set power off indicates an unrecoverable hardware or 70*81673325SDavid Zhang * firmware error. 71*81673325SDavid Zhang */ 72*81673325SDavid Zhang ret = aie_smu_exec(smu, AIE_SMU_POWER_OFF, 0, NULL); 73*81673325SDavid Zhang if (ret) { 74*81673325SDavid Zhang drm_err(smu->ddev, "Access power failed, ret %d", ret); 75*81673325SDavid Zhang return ret; 76*81673325SDavid Zhang } 77*81673325SDavid Zhang 78*81673325SDavid Zhang ret = aie_smu_exec(smu, AIE_SMU_POWER_ON, 0, NULL); 79*81673325SDavid Zhang if (ret) { 80*81673325SDavid Zhang drm_err(smu->ddev, "Power on failed, ret %d", ret); 81*81673325SDavid Zhang return ret; 82*81673325SDavid Zhang } 83*81673325SDavid Zhang 84*81673325SDavid Zhang return 0; 85*81673325SDavid Zhang } 86*81673325SDavid Zhang 87*81673325SDavid Zhang void aie_smu_fini(struct smu_device *smu) 88*81673325SDavid Zhang { 89*81673325SDavid Zhang int ret; 90*81673325SDavid Zhang 91*81673325SDavid Zhang ret = aie_smu_exec(smu, AIE_SMU_POWER_OFF, 0, NULL); 92*81673325SDavid Zhang if (ret) 93*81673325SDavid Zhang drm_err(smu->ddev, "Power off failed, ret %d", ret); 94*81673325SDavid Zhang } 95*81673325SDavid Zhang 96*81673325SDavid Zhang int aie_smu_set_clocks(struct smu_device *smu, u32 *npuclk, u32 *hclk) 97*81673325SDavid Zhang { 98*81673325SDavid Zhang int ret; 99*81673325SDavid Zhang 100*81673325SDavid Zhang if (npuclk) { 101*81673325SDavid Zhang ret = aie_smu_exec(smu, AIE_SMU_SET_MPNPUCLK_FREQ, *npuclk, npuclk); 102*81673325SDavid Zhang if (ret) { 103*81673325SDavid Zhang drm_err(smu->ddev, "Set mpnpu clock to %d failed, ret %d", *npuclk, ret); 104*81673325SDavid Zhang return ret; 105*81673325SDavid Zhang } 106*81673325SDavid Zhang } 107*81673325SDavid Zhang 108*81673325SDavid Zhang if (hclk) { 109*81673325SDavid Zhang ret = aie_smu_exec(smu, AIE_SMU_SET_HCLK_FREQ, *hclk, hclk); 110*81673325SDavid Zhang if (ret) { 111*81673325SDavid Zhang drm_err(smu->ddev, "Set hclock to %d failed, ret %d", 112*81673325SDavid Zhang *hclk, ret); 113*81673325SDavid Zhang return ret; 114*81673325SDavid Zhang } 115*81673325SDavid Zhang } 116*81673325SDavid Zhang 117*81673325SDavid Zhang return 0; 118*81673325SDavid Zhang } 119*81673325SDavid Zhang 120*81673325SDavid Zhang int aie_smu_set_dpm(struct smu_device *smu, u32 dpm_level) 121*81673325SDavid Zhang { 122*81673325SDavid Zhang int ret; 123*81673325SDavid Zhang 124*81673325SDavid Zhang ret = aie_smu_exec(smu, AIE_SMU_SET_HARD_DPMLEVEL, dpm_level, NULL); 125*81673325SDavid Zhang if (ret) { 126*81673325SDavid Zhang drm_err(smu->ddev, "Set hard dpm level %d failed, ret %d", 127*81673325SDavid Zhang dpm_level, ret); 128*81673325SDavid Zhang return ret; 129*81673325SDavid Zhang } 130*81673325SDavid Zhang 131*81673325SDavid Zhang ret = aie_smu_exec(smu, AIE_SMU_SET_SOFT_DPMLEVEL, dpm_level, NULL); 132*81673325SDavid Zhang if (ret) { 133*81673325SDavid Zhang drm_err(smu->ddev, "Set soft dpm level %d failed, ret %d", 134*81673325SDavid Zhang dpm_level, ret); 135*81673325SDavid Zhang return ret; 136*81673325SDavid Zhang } 137*81673325SDavid Zhang 138*81673325SDavid Zhang return 0; 139*81673325SDavid Zhang } 140*81673325SDavid Zhang 141*81673325SDavid Zhang struct smu_device *aiem_smu_create(struct drm_device *ddev, struct smu_config *conf) 142*81673325SDavid Zhang { 143*81673325SDavid Zhang struct smu_device *smu; 144*81673325SDavid Zhang 145*81673325SDavid Zhang smu = drmm_kzalloc(ddev, sizeof(*smu), GFP_KERNEL); 146*81673325SDavid Zhang if (!smu) 147*81673325SDavid Zhang return NULL; 148*81673325SDavid Zhang 149*81673325SDavid Zhang smu->ddev = ddev; 150*81673325SDavid Zhang memcpy(smu->smu_regs, conf->smu_regs, sizeof(smu->smu_regs)); 151*81673325SDavid Zhang 152*81673325SDavid Zhang return smu; 153*81673325SDavid Zhang } 154