| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright (C) 2022-2024, Advanced Micro Devices, Inc.
- */
- #include <drm/drm_device.h>
- #include <drm/drm_gem_shmem_helper.h>
- #include <drm/drm_print.h>
- #include <drm/gpu_scheduler.h>
- #include <linux/iopoll.h>
- #include "aie2_pci.h"
- #include "amdxdna_pci_drv.h"
- #define SMU_RESULT_OK 1
- /* SMU commands */
- #define AIE2_SMU_POWER_ON 0x3
- #define AIE2_SMU_POWER_OFF 0x4
- #define AIE2_SMU_SET_MPNPUCLK_FREQ 0x5
- #define AIE2_SMU_SET_HCLK_FREQ 0x6
- #define AIE2_SMU_SET_SOFT_DPMLEVEL 0x7
- #define AIE2_SMU_SET_HARD_DPMLEVEL 0x8
- #define NPU4_DPM_TOPS(ndev, dpm_level) \
- ({ \
- typeof(ndev) _ndev = ndev; \
- (4096 * (_ndev)->total_col * \
- (_ndev)->priv->dpm_clk_tbl[dpm_level].hclk / 1000000); \
- })
- static int aie2_smu_exec(struct amdxdna_dev_hdl *ndev, u32 reg_cmd,
- u32 reg_arg, u32 *out)
- {
- u32 resp;
- int ret;
- writel(0, SMU_REG(ndev, SMU_RESP_REG));
- writel(reg_arg, SMU_REG(ndev, SMU_ARG_REG));
- writel(reg_cmd, SMU_REG(ndev, SMU_CMD_REG));
- /* Clear and set SMU_INTR_REG to kick off */
- writel(0, SMU_REG(ndev, SMU_INTR_REG));
- writel(1, SMU_REG(ndev, SMU_INTR_REG));
- ret = readx_poll_timeout(readl, SMU_REG(ndev, SMU_RESP_REG), resp,
- resp, AIE2_INTERVAL, AIE2_TIMEOUT);
- if (ret) {
- XDNA_ERR(ndev->xdna, "smu cmd %d timed out", reg_cmd);
- return ret;
- }
- if (out)
- *out = readl(SMU_REG(ndev, SMU_OUT_REG));
- if (resp != SMU_RESULT_OK) {
- XDNA_ERR(ndev->xdna, "smu cmd %d failed, 0x%x", reg_cmd, resp);
- return -EINVAL;
- }
- return 0;
- }
- int npu1_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level)
- {
- u32 freq;
- int ret;
- ret = aie2_smu_exec(ndev, AIE2_SMU_SET_MPNPUCLK_FREQ,
- ndev->priv->dpm_clk_tbl[dpm_level].npuclk, &freq);
- if (ret) {
- XDNA_ERR(ndev->xdna, "Set npu clock to %d failed, ret %d\n",
- ndev->priv->dpm_clk_tbl[dpm_level].npuclk, ret);
- return ret;
- }
- ndev->npuclk_freq = freq;
- ret = aie2_smu_exec(ndev, AIE2_SMU_SET_HCLK_FREQ,
- ndev->priv->dpm_clk_tbl[dpm_level].hclk, &freq);
- if (ret) {
- XDNA_ERR(ndev->xdna, "Set h clock to %d failed, ret %d\n",
- ndev->priv->dpm_clk_tbl[dpm_level].hclk, ret);
- return ret;
- }
- ndev->hclk_freq = freq;
- ndev->max_tops = 2 * ndev->total_col;
- ndev->curr_tops = ndev->max_tops * freq / 1028;
- XDNA_DBG(ndev->xdna, "MP-NPU clock %d, H clock %d\n",
- ndev->npuclk_freq, ndev->hclk_freq);
- return 0;
- }
- int npu4_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level)
- {
- int ret;
- ret = aie2_smu_exec(ndev, AIE2_SMU_SET_HARD_DPMLEVEL, dpm_level, NULL);
- if (ret) {
- XDNA_ERR(ndev->xdna, "Set hard dpm level %d failed, ret %d ",
- dpm_level, ret);
- return ret;
- }
- ret = aie2_smu_exec(ndev, AIE2_SMU_SET_SOFT_DPMLEVEL, dpm_level, NULL);
- if (ret) {
- XDNA_ERR(ndev->xdna, "Set soft dpm level %d failed, ret %d",
- dpm_level, ret);
- return ret;
- }
- ndev->npuclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].npuclk;
- ndev->hclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].hclk;
- ndev->max_tops = NPU4_DPM_TOPS(ndev, ndev->max_dpm_level);
- ndev->curr_tops = NPU4_DPM_TOPS(ndev, dpm_level);
- XDNA_DBG(ndev->xdna, "MP-NPU clock %d, H clock %d\n",
- ndev->npuclk_freq, ndev->hclk_freq);
- return 0;
- }
- int aie2_smu_init(struct amdxdna_dev_hdl *ndev)
- {
- int ret;
- /*
- * Failing to set power off indicates an unrecoverable hardware or
- * firmware error.
- */
- ret = aie2_smu_exec(ndev, AIE2_SMU_POWER_OFF, 0, NULL);
- if (ret) {
- XDNA_ERR(ndev->xdna, "Access power failed, ret %d", ret);
- return ret;
- }
- ret = aie2_smu_exec(ndev, AIE2_SMU_POWER_ON, 0, NULL);
- if (ret) {
- XDNA_ERR(ndev->xdna, "Power on failed, ret %d", ret);
- return ret;
- }
- return 0;
- }
- void aie2_smu_fini(struct amdxdna_dev_hdl *ndev)
- {
- int ret;
- ndev->priv->hw_ops.set_dpm(ndev, 0);
- ret = aie2_smu_exec(ndev, AIE2_SMU_POWER_OFF, 0, NULL);
- if (ret)
- XDNA_ERR(ndev->xdna, "Power off failed, ret %d", ret);
- }
|