1c02697cbSDavid Zhang // SPDX-License-Identifier: GPL-2.0 2c02697cbSDavid Zhang /* 3c02697cbSDavid Zhang * Copyright (C) 2026, Advanced Micro Devices, Inc. 4c02697cbSDavid Zhang */ 5c02697cbSDavid Zhang 6c02697cbSDavid Zhang #include <drm/amdxdna_accel.h> 7c02697cbSDavid Zhang #include <drm/drm_managed.h> 8c02697cbSDavid Zhang #include <drm/drm_print.h> 9e69ef214SDavid Zhang #include <linux/firmware.h> 10e69ef214SDavid Zhang #include <linux/sizes.h> 11c02697cbSDavid Zhang 12ce9414d0SDavid Zhang #include "aie.h" 13ce9414d0SDavid Zhang #include "aie4_msg_priv.h" 14c02697cbSDavid Zhang #include "aie4_pci.h" 15ce9414d0SDavid Zhang #include "amdxdna_mailbox.h" 16ce9414d0SDavid Zhang #include "amdxdna_mailbox_helper.h" 17c02697cbSDavid Zhang #include "amdxdna_pci_drv.h" 18c02697cbSDavid Zhang 19c02697cbSDavid Zhang #define NO_IOHUB 0 20e69ef214SDavid Zhang #define PSP_NOTIFY_INTR 0xD007BE11 21ce9414d0SDavid Zhang #define AIE4_TOTAL_COLUMN 3 22c02697cbSDavid Zhang 23c02697cbSDavid Zhang /* 24c02697cbSDavid Zhang * The management mailbox channel is allocated by firmware. 25c02697cbSDavid Zhang * The related register and ring buffer information is on SRAM BAR. 26c02697cbSDavid Zhang * This struct is the register layout. 27c02697cbSDavid Zhang */ 28c02697cbSDavid Zhang struct mailbox_info { 29c02697cbSDavid Zhang __u32 valid; 30c02697cbSDavid Zhang __u32 protocol_major; 31c02697cbSDavid Zhang __u32 protocol_minor; 32c02697cbSDavid Zhang __u32 x2i_tail_offset; 33c02697cbSDavid Zhang __u32 x2i_head_offset; 34c02697cbSDavid Zhang __u32 x2i_buffer_addr; 35c02697cbSDavid Zhang __u32 x2i_buffer_size; 36c02697cbSDavid Zhang __u32 i2x_tail_offset; 37c02697cbSDavid Zhang __u32 i2x_head_offset; 38c02697cbSDavid Zhang __u32 i2x_buffer_addr; 39c02697cbSDavid Zhang __u32 i2x_buffer_size; 40c02697cbSDavid Zhang __u32 i2x_msi_idx; 41c02697cbSDavid Zhang __u32 reserved[4]; 42c02697cbSDavid Zhang }; 43c02697cbSDavid Zhang 44c02697cbSDavid Zhang static int aie4_fw_is_alive(struct amdxdna_dev *xdna) 45c02697cbSDavid Zhang { 46c02697cbSDavid Zhang const struct amdxdna_dev_priv *npriv = xdna->dev_info->dev_priv; 47c02697cbSDavid Zhang struct amdxdna_dev_hdl *ndev = xdna->dev_handle; 48c02697cbSDavid Zhang u32 __iomem *src; 49c02697cbSDavid Zhang u32 fw_is_valid; 50c02697cbSDavid Zhang int ret; 51c02697cbSDavid Zhang 52c02697cbSDavid Zhang src = ndev->rbuf_base + npriv->mbox_info_off; 53c02697cbSDavid Zhang 54c02697cbSDavid Zhang ret = readx_poll_timeout(readl, src + offsetof(struct mailbox_info, valid), 55c02697cbSDavid Zhang fw_is_valid, (fw_is_valid == 0x1), 56c02697cbSDavid Zhang AIE_INTERVAL, AIE_TIMEOUT); 57c02697cbSDavid Zhang if (ret) 58c02697cbSDavid Zhang XDNA_ERR(xdna, "fw_is_valid=%d after %d ms", 59c02697cbSDavid Zhang fw_is_valid, DIV_ROUND_CLOSEST(AIE_TIMEOUT, 1000000)); 60c02697cbSDavid Zhang 61c02697cbSDavid Zhang return ret; 62c02697cbSDavid Zhang } 63c02697cbSDavid Zhang 64c02697cbSDavid Zhang static void aie4_read_mbox_info(struct amdxdna_dev *xdna, 65c02697cbSDavid Zhang struct mailbox_info *mbox_info) 66c02697cbSDavid Zhang { 67c02697cbSDavid Zhang const struct amdxdna_dev_priv *npriv = xdna->dev_info->dev_priv; 68c02697cbSDavid Zhang struct amdxdna_dev_hdl *ndev = xdna->dev_handle; 69c02697cbSDavid Zhang u32 *dst = (u32 *)mbox_info; 70c02697cbSDavid Zhang u32 __iomem *src; 71c02697cbSDavid Zhang int i; 72c02697cbSDavid Zhang 73c02697cbSDavid Zhang src = ndev->rbuf_base + npriv->mbox_info_off; 74c02697cbSDavid Zhang 75c02697cbSDavid Zhang for (i = 0; i < sizeof(*mbox_info) / sizeof(u32); i++) 76c02697cbSDavid Zhang dst[i] = readl(&src[i]); 77c02697cbSDavid Zhang } 78c02697cbSDavid Zhang 79c02697cbSDavid Zhang static int aie4_mailbox_info(struct amdxdna_dev *xdna, 80c02697cbSDavid Zhang struct mailbox_info *mbox_info) 81c02697cbSDavid Zhang { 82c02697cbSDavid Zhang int ret; 83c02697cbSDavid Zhang 84c02697cbSDavid Zhang ret = aie4_fw_is_alive(xdna); 85c02697cbSDavid Zhang if (ret) 86c02697cbSDavid Zhang return ret; 87c02697cbSDavid Zhang 88c02697cbSDavid Zhang aie4_read_mbox_info(xdna, mbox_info); 89c02697cbSDavid Zhang 90c02697cbSDavid Zhang ret = aie_check_protocol(&xdna->dev_handle->aie, 91c02697cbSDavid Zhang mbox_info->protocol_major, 92c02697cbSDavid Zhang mbox_info->protocol_minor); 93c02697cbSDavid Zhang if (ret) 94c02697cbSDavid Zhang XDNA_ERR(xdna, "mailbox major.minor %d.%d is not supported", 95c02697cbSDavid Zhang mbox_info->protocol_major, mbox_info->protocol_minor); 96c02697cbSDavid Zhang 97c02697cbSDavid Zhang return ret; 98c02697cbSDavid Zhang } 99c02697cbSDavid Zhang 100c02697cbSDavid Zhang static void aie4_mailbox_fini(struct amdxdna_dev_hdl *ndev) 101c02697cbSDavid Zhang { 102c02697cbSDavid Zhang struct amdxdna_dev *xdna = ndev->aie.xdna; 103c02697cbSDavid Zhang 104c02697cbSDavid Zhang aie_destroy_chann(&ndev->aie, &ndev->aie.mgmt_chann); 105c02697cbSDavid Zhang drmm_kfree(&xdna->ddev, ndev->mbox); 106c02697cbSDavid Zhang ndev->mbox = NULL; 107c02697cbSDavid Zhang } 108c02697cbSDavid Zhang 109c02697cbSDavid Zhang static int aie4_irq_init(struct amdxdna_dev *xdna) 110c02697cbSDavid Zhang { 111c02697cbSDavid Zhang struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev); 112c02697cbSDavid Zhang int ret, nvec; 113c02697cbSDavid Zhang 114c02697cbSDavid Zhang nvec = pci_msix_vec_count(pdev); 115c02697cbSDavid Zhang XDNA_DBG(xdna, "irq vectors:%d", nvec); 116c02697cbSDavid Zhang if (nvec <= 0) { 117c02697cbSDavid Zhang XDNA_ERR(xdna, "does not get number of interrupt vector"); 118c02697cbSDavid Zhang return -EINVAL; 119c02697cbSDavid Zhang } 120c02697cbSDavid Zhang 121c02697cbSDavid Zhang ret = pci_alloc_irq_vectors(pdev, nvec, nvec, PCI_IRQ_MSIX); 122c02697cbSDavid Zhang if (ret < 0) { 123c02697cbSDavid Zhang XDNA_ERR(xdna, "failed to alloc irq vector, ret: %d", ret); 124c02697cbSDavid Zhang return ret; 125c02697cbSDavid Zhang } 126c02697cbSDavid Zhang 127c02697cbSDavid Zhang return 0; 128c02697cbSDavid Zhang } 129c02697cbSDavid Zhang 130c02697cbSDavid Zhang static int aie4_mailbox_start(struct amdxdna_dev *xdna, 131c02697cbSDavid Zhang struct mailbox_info *mbi) 132c02697cbSDavid Zhang { 133c02697cbSDavid Zhang struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev); 134c02697cbSDavid Zhang struct amdxdna_dev_hdl *ndev = xdna->dev_handle; 135c02697cbSDavid Zhang const struct amdxdna_dev_priv *npriv = xdna->dev_info->dev_priv; 136c02697cbSDavid Zhang struct xdna_mailbox_chann_res *i2x; 137c02697cbSDavid Zhang struct xdna_mailbox_chann_res *x2i; 138c02697cbSDavid Zhang int mgmt_mb_irq; 139c02697cbSDavid Zhang int ret; 140c02697cbSDavid Zhang 141c02697cbSDavid Zhang struct xdna_mailbox_res mbox_res = { 142c02697cbSDavid Zhang .ringbuf_base = ndev->rbuf_base, 143c02697cbSDavid Zhang .ringbuf_size = pci_resource_len(pdev, npriv->mbox_rbuf_bar), 144c02697cbSDavid Zhang .mbox_base = ndev->mbox_base, 145c02697cbSDavid Zhang .mbox_size = pci_resource_len(pdev, npriv->mbox_bar), 146c02697cbSDavid Zhang .name = "xdna_aie4_mailbox", 147c02697cbSDavid Zhang }; 148c02697cbSDavid Zhang 149c02697cbSDavid Zhang i2x = &ndev->aie.mgmt_i2x; 150c02697cbSDavid Zhang x2i = &ndev->aie.mgmt_x2i; 151c02697cbSDavid Zhang 152c02697cbSDavid Zhang x2i->mb_head_ptr_reg = mbi->x2i_head_offset; 153c02697cbSDavid Zhang x2i->mb_tail_ptr_reg = mbi->x2i_tail_offset; 154c02697cbSDavid Zhang x2i->rb_start_addr = mbi->x2i_buffer_addr; 155c02697cbSDavid Zhang x2i->rb_size = mbi->x2i_buffer_size; 156c02697cbSDavid Zhang 157c02697cbSDavid Zhang i2x->rb_start_addr = mbi->i2x_buffer_addr; 158c02697cbSDavid Zhang i2x->rb_size = mbi->i2x_buffer_size; 159c02697cbSDavid Zhang i2x->mb_head_ptr_reg = mbi->i2x_head_offset; 160c02697cbSDavid Zhang i2x->mb_tail_ptr_reg = mbi->i2x_tail_offset; 161c02697cbSDavid Zhang 162c02697cbSDavid Zhang ndev->aie.mgmt_chan_idx = mbi->i2x_msi_idx; 163c02697cbSDavid Zhang aie_dump_mgmt_chann_debug(&ndev->aie); 164c02697cbSDavid Zhang 165c02697cbSDavid Zhang ndev->mbox = xdnam_mailbox_create(&xdna->ddev, &mbox_res); 166c02697cbSDavid Zhang if (!ndev->mbox) { 167c02697cbSDavid Zhang XDNA_ERR(xdna, "failed to create mailbox device"); 168c02697cbSDavid Zhang return -ENODEV; 169c02697cbSDavid Zhang } 170c02697cbSDavid Zhang 171c02697cbSDavid Zhang ndev->aie.mgmt_chann = xdna_mailbox_alloc_channel(ndev->mbox); 172c02697cbSDavid Zhang if (!ndev->aie.mgmt_chann) { 173c02697cbSDavid Zhang XDNA_ERR(xdna, "failed to alloc mailbox channel"); 174c02697cbSDavid Zhang return -ENODEV; 175c02697cbSDavid Zhang } 176c02697cbSDavid Zhang 177c02697cbSDavid Zhang mgmt_mb_irq = pci_irq_vector(pdev, ndev->aie.mgmt_chan_idx); 178c02697cbSDavid Zhang if (mgmt_mb_irq < 0) { 179c02697cbSDavid Zhang XDNA_ERR(xdna, "failed to alloc irq vector, return %d", mgmt_mb_irq); 180c02697cbSDavid Zhang ret = mgmt_mb_irq; 181c02697cbSDavid Zhang goto free_channel; 182c02697cbSDavid Zhang } 183c02697cbSDavid Zhang 184c02697cbSDavid Zhang ret = xdna_mailbox_start_channel(ndev->aie.mgmt_chann, 185c02697cbSDavid Zhang &ndev->aie.mgmt_x2i, 186c02697cbSDavid Zhang &ndev->aie.mgmt_i2x, 187c02697cbSDavid Zhang NO_IOHUB, 188c02697cbSDavid Zhang mgmt_mb_irq); 189c02697cbSDavid Zhang if (ret) { 190c02697cbSDavid Zhang XDNA_ERR(xdna, "failed to start management mailbox channel"); 191c02697cbSDavid Zhang ret = -EINVAL; 192c02697cbSDavid Zhang goto free_channel; 193c02697cbSDavid Zhang } 194c02697cbSDavid Zhang 195c02697cbSDavid Zhang XDNA_DBG(xdna, "Mailbox management channel created"); 196c02697cbSDavid Zhang return 0; 197c02697cbSDavid Zhang 198c02697cbSDavid Zhang free_channel: 199c02697cbSDavid Zhang xdna_mailbox_free_channel(ndev->aie.mgmt_chann); 200c02697cbSDavid Zhang ndev->aie.mgmt_chann = NULL; 201c02697cbSDavid Zhang return ret; 202c02697cbSDavid Zhang } 203c02697cbSDavid Zhang 2047b1a245bSDavid Zhang static int aie4_mailbox_init(struct amdxdna_dev_hdl *ndev) 205c02697cbSDavid Zhang { 2067b1a245bSDavid Zhang struct amdxdna_dev *xdna = ndev->aie.xdna; 207c02697cbSDavid Zhang struct mailbox_info mbox_info; 208c02697cbSDavid Zhang int ret; 209c02697cbSDavid Zhang 210c02697cbSDavid Zhang ret = aie4_mailbox_info(xdna, &mbox_info); 211c02697cbSDavid Zhang if (ret) 212c02697cbSDavid Zhang return ret; 213c02697cbSDavid Zhang 214c02697cbSDavid Zhang return aie4_mailbox_start(xdna, &mbox_info); 215c02697cbSDavid Zhang } 216c02697cbSDavid Zhang 2177b1a245bSDavid Zhang static void aie4_fw_stop(struct amdxdna_dev_hdl *ndev) 218c02697cbSDavid Zhang { 219e69ef214SDavid Zhang aie_psp_stop(ndev->aie.psp_hdl); 22043c9a66eSDavid Zhang aie_smu_fini(ndev->aie.smu_hdl); 221c02697cbSDavid Zhang } 222c02697cbSDavid Zhang 2237b1a245bSDavid Zhang static int aie4_fw_start(struct amdxdna_dev_hdl *ndev) 224c02697cbSDavid Zhang { 22543c9a66eSDavid Zhang int ret; 22643c9a66eSDavid Zhang 22743c9a66eSDavid Zhang ret = aie_smu_init(ndev->aie.smu_hdl); 22843c9a66eSDavid Zhang if (ret) { 22943c9a66eSDavid Zhang XDNA_ERR(ndev->aie.xdna, "failed to init smu, ret %d", ret); 23043c9a66eSDavid Zhang return ret; 23143c9a66eSDavid Zhang } 23243c9a66eSDavid Zhang 23343c9a66eSDavid Zhang ret = aie_psp_start(ndev->aie.psp_hdl); 23443c9a66eSDavid Zhang if (ret) { 23543c9a66eSDavid Zhang XDNA_ERR(ndev->aie.xdna, "failed to start psp, ret %d", ret); 23643c9a66eSDavid Zhang aie_smu_fini(ndev->aie.smu_hdl); 23743c9a66eSDavid Zhang } 23843c9a66eSDavid Zhang 23943c9a66eSDavid Zhang return ret; 240c02697cbSDavid Zhang } 241c02697cbSDavid Zhang 242ce9414d0SDavid Zhang static int aie4_partition_init(struct amdxdna_dev_hdl *ndev) 243ce9414d0SDavid Zhang { 244ce9414d0SDavid Zhang DECLARE_AIE_MSG(aie4_msg_create_partition, AIE4_MSG_OP_CREATE_PARTITION); 245ce9414d0SDavid Zhang struct amdxdna_dev *xdna = ndev->aie.xdna; 246ce9414d0SDavid Zhang int ret; 247ce9414d0SDavid Zhang 248ce9414d0SDavid Zhang req.partition_col_start = 0; 249ce9414d0SDavid Zhang req.partition_col_count = AIE4_TOTAL_COLUMN; 250ce9414d0SDavid Zhang ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg); 251ce9414d0SDavid Zhang if (ret) { 252ce9414d0SDavid Zhang XDNA_ERR(xdna, "partition init failed: %d", ret); 253ce9414d0SDavid Zhang return ret; 254ce9414d0SDavid Zhang } 255ce9414d0SDavid Zhang 256ce9414d0SDavid Zhang ndev->partition_id = resp.partition_id; 257ce9414d0SDavid Zhang return 0; 258ce9414d0SDavid Zhang } 259ce9414d0SDavid Zhang 260ce9414d0SDavid Zhang static void aie4_partition_fini(struct amdxdna_dev_hdl *ndev) 261ce9414d0SDavid Zhang { 262ce9414d0SDavid Zhang DECLARE_AIE_MSG(aie4_msg_destroy_partition, AIE4_MSG_OP_DESTROY_PARTITION); 263ce9414d0SDavid Zhang struct amdxdna_dev *xdna = ndev->aie.xdna; 264ce9414d0SDavid Zhang int ret; 265ce9414d0SDavid Zhang 266ce9414d0SDavid Zhang req.partition_id = ndev->partition_id; 267ce9414d0SDavid Zhang ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg); 268ce9414d0SDavid Zhang if (ret) 269ce9414d0SDavid Zhang XDNA_ERR(xdna, "partition fini failed: %d", ret); 270ce9414d0SDavid Zhang } 271ce9414d0SDavid Zhang 2720b087e06SDavid Zhang static int aie4_query(struct amdxdna_dev_hdl *ndev) 2730b087e06SDavid Zhang { 2740b087e06SDavid Zhang return aie4_query_aie_metadata(ndev, &ndev->aie.metadata); 2750b087e06SDavid Zhang } 2760b087e06SDavid Zhang 2777b1a245bSDavid Zhang static int aie4_pf_hw_start(struct amdxdna_dev_hdl *ndev) 278c02697cbSDavid Zhang { 279c02697cbSDavid Zhang int ret; 280c02697cbSDavid Zhang 2817b1a245bSDavid Zhang ret = aie4_fw_start(ndev); 282c02697cbSDavid Zhang if (ret) 283c02697cbSDavid Zhang return ret; 284c02697cbSDavid Zhang 2857b1a245bSDavid Zhang ret = aie4_mailbox_init(ndev); 286c02697cbSDavid Zhang if (ret) 2877b1a245bSDavid Zhang goto stop_fw; 288c02697cbSDavid Zhang 289*c0069781SNishad Saraf ret = aie4_attach_work_buffer(ndev); 290*c0069781SNishad Saraf if (ret) 291*c0069781SNishad Saraf goto mbox_fini; 292*c0069781SNishad Saraf 293c02697cbSDavid Zhang return 0; 294c02697cbSDavid Zhang 295*c0069781SNishad Saraf mbox_fini: 296*c0069781SNishad Saraf aie4_mailbox_fini(ndev); 2977b1a245bSDavid Zhang stop_fw: 2987b1a245bSDavid Zhang aie4_fw_stop(ndev); 299c02697cbSDavid Zhang 300c02697cbSDavid Zhang return ret; 301c02697cbSDavid Zhang } 302c02697cbSDavid Zhang 3037b1a245bSDavid Zhang static void aie4_pf_hw_stop(struct amdxdna_dev_hdl *ndev) 304c02697cbSDavid Zhang { 3057b1a245bSDavid Zhang struct amdxdna_dev *xdna = ndev->aie.xdna; 306c02697cbSDavid Zhang 307c02697cbSDavid Zhang drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock)); 308c02697cbSDavid Zhang 3097b1a245bSDavid Zhang aie4_suspend_fw(ndev); 310c02697cbSDavid Zhang aie4_mailbox_fini(ndev); 3117b1a245bSDavid Zhang aie4_fw_stop(ndev); 3127b1a245bSDavid Zhang } 313c02697cbSDavid Zhang 3147b1a245bSDavid Zhang static int aie4_vf_hw_start(struct amdxdna_dev_hdl *ndev) 3157b1a245bSDavid Zhang { 316ce9414d0SDavid Zhang int ret; 317ce9414d0SDavid Zhang 318ce9414d0SDavid Zhang ret = aie4_mailbox_init(ndev); 319ce9414d0SDavid Zhang if (ret) 320ce9414d0SDavid Zhang return ret; 321ce9414d0SDavid Zhang 3220b087e06SDavid Zhang ret = aie4_query(ndev); 3230b087e06SDavid Zhang if (ret) 3240b087e06SDavid Zhang goto mailbox_fini; 3250b087e06SDavid Zhang 326ce9414d0SDavid Zhang ret = aie4_partition_init(ndev); 327ce9414d0SDavid Zhang if (ret) 328ce9414d0SDavid Zhang goto mailbox_fini; 329ce9414d0SDavid Zhang 330ce9414d0SDavid Zhang return 0; 331ce9414d0SDavid Zhang 332ce9414d0SDavid Zhang mailbox_fini: 333ce9414d0SDavid Zhang aie4_mailbox_fini(ndev); 334ce9414d0SDavid Zhang return ret; 3357b1a245bSDavid Zhang } 3367b1a245bSDavid Zhang 3377b1a245bSDavid Zhang static void aie4_vf_hw_stop(struct amdxdna_dev_hdl *ndev) 3387b1a245bSDavid Zhang { 3397b1a245bSDavid Zhang struct amdxdna_dev *xdna = ndev->aie.xdna; 3407b1a245bSDavid Zhang 3417b1a245bSDavid Zhang drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock)); 3427b1a245bSDavid Zhang 343ce9414d0SDavid Zhang aie4_partition_fini(ndev); 3447b1a245bSDavid Zhang aie4_mailbox_fini(ndev); 345c02697cbSDavid Zhang } 346c02697cbSDavid Zhang 347e69ef214SDavid Zhang static int aie4_request_firmware(struct amdxdna_dev_hdl *ndev, 348e69ef214SDavid Zhang const struct firmware **npufw, 349e69ef214SDavid Zhang const struct firmware **certfw) 350e69ef214SDavid Zhang { 351e69ef214SDavid Zhang struct amdxdna_dev *xdna = ndev->aie.xdna; 352e69ef214SDavid Zhang struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev); 353e69ef214SDavid Zhang char fw_name[128]; 354e69ef214SDavid Zhang int ret; 355e69ef214SDavid Zhang 356e69ef214SDavid Zhang ret = snprintf(fw_name, sizeof(fw_name), "amdnpu/%04x_%02x/%s", 357e69ef214SDavid Zhang pdev->device, pdev->revision, ndev->priv->npufw_path); 358e69ef214SDavid Zhang if (ret >= sizeof(fw_name)) { 359e69ef214SDavid Zhang XDNA_ERR(xdna, "npu firmware path is truncated"); 360e69ef214SDavid Zhang return -EINVAL; 361e69ef214SDavid Zhang } 362e69ef214SDavid Zhang 363e69ef214SDavid Zhang ret = request_firmware(npufw, fw_name, &pdev->dev); 364e69ef214SDavid Zhang if (ret) { 365e69ef214SDavid Zhang XDNA_ERR(xdna, "failed to request_firmware %s, ret %d", fw_name, ret); 366e69ef214SDavid Zhang return ret; 367e69ef214SDavid Zhang } 368e69ef214SDavid Zhang 369e69ef214SDavid Zhang ret = snprintf(fw_name, sizeof(fw_name), "amdnpu/%04x_%02x/%s", 370e69ef214SDavid Zhang pdev->device, pdev->revision, ndev->priv->certfw_path); 371e69ef214SDavid Zhang if (ret >= sizeof(fw_name)) { 372e69ef214SDavid Zhang XDNA_ERR(xdna, "cert firmware path is truncated"); 373e69ef214SDavid Zhang ret = -EINVAL; 374e69ef214SDavid Zhang goto release_npufw; 375e69ef214SDavid Zhang } 376e69ef214SDavid Zhang 377e69ef214SDavid Zhang ret = request_firmware(certfw, fw_name, &pdev->dev); 378e69ef214SDavid Zhang if (ret) { 379e69ef214SDavid Zhang XDNA_ERR(xdna, "failed to request_firmware %s, ret %d", fw_name, ret); 380e69ef214SDavid Zhang goto release_npufw; 381e69ef214SDavid Zhang } 382e69ef214SDavid Zhang 383e69ef214SDavid Zhang return 0; 384e69ef214SDavid Zhang 385e69ef214SDavid Zhang release_npufw: 386e69ef214SDavid Zhang release_firmware(*npufw); 387e69ef214SDavid Zhang 388e69ef214SDavid Zhang return ret; 389e69ef214SDavid Zhang } 390e69ef214SDavid Zhang 391e69ef214SDavid Zhang static void aie4_release_firmware(struct amdxdna_dev_hdl *ndev, 392e69ef214SDavid Zhang const struct firmware *npufw, 393e69ef214SDavid Zhang const struct firmware *certfw) 394e69ef214SDavid Zhang { 395e69ef214SDavid Zhang release_firmware(certfw); 396e69ef214SDavid Zhang release_firmware(npufw); 397e69ef214SDavid Zhang } 398e69ef214SDavid Zhang 399e69ef214SDavid Zhang static int aie4_prepare_firmware(struct amdxdna_dev_hdl *ndev, 400e69ef214SDavid Zhang const struct firmware *npufw, 401e69ef214SDavid Zhang const struct firmware *certfw, 402e69ef214SDavid Zhang void __iomem *tbl[PCI_NUM_RESOURCES]) 403e69ef214SDavid Zhang { 404e69ef214SDavid Zhang struct amdxdna_dev *xdna = ndev->aie.xdna; 405e69ef214SDavid Zhang struct psp_config psp_conf; 40643c9a66eSDavid Zhang struct smu_config smu_conf; 407e69ef214SDavid Zhang int i; 408e69ef214SDavid Zhang 409e69ef214SDavid Zhang psp_conf.fw_size = npufw->size; 410e69ef214SDavid Zhang psp_conf.fw_buf = npufw->data; 411e69ef214SDavid Zhang psp_conf.certfw_size = certfw->size; 412e69ef214SDavid Zhang psp_conf.certfw_buf = certfw->data; 413e69ef214SDavid Zhang psp_conf.arg2_mask = ~0; 414e69ef214SDavid Zhang psp_conf.notify_val = PSP_NOTIFY_INTR; 415e69ef214SDavid Zhang for (i = 0; i < PSP_MAX_REGS; i++) 416e69ef214SDavid Zhang psp_conf.psp_regs[i] = tbl[PSP_REG_BAR(ndev, i)] + PSP_REG_OFF(ndev, i); 417e69ef214SDavid Zhang ndev->aie.psp_hdl = aiem_psp_create(&xdna->ddev, &psp_conf); 418e69ef214SDavid Zhang if (!ndev->aie.psp_hdl) { 419e69ef214SDavid Zhang XDNA_ERR(xdna, "failed to create psp"); 420e69ef214SDavid Zhang return -ENOMEM; 421e69ef214SDavid Zhang } 422e69ef214SDavid Zhang 42343c9a66eSDavid Zhang for (i = 0; i < SMU_MAX_REGS; i++) 42443c9a66eSDavid Zhang smu_conf.smu_regs[i] = tbl[SMU_REG_BAR(ndev, i)] + SMU_REG_OFF(ndev, i); 42543c9a66eSDavid Zhang ndev->aie.smu_hdl = aiem_smu_create(&xdna->ddev, &smu_conf); 42643c9a66eSDavid Zhang if (!ndev->aie.smu_hdl) { 42743c9a66eSDavid Zhang XDNA_ERR(xdna, "failed to create smu"); 42843c9a66eSDavid Zhang return -ENOMEM; 42943c9a66eSDavid Zhang } 43043c9a66eSDavid Zhang 431e69ef214SDavid Zhang return 0; 432e69ef214SDavid Zhang } 433e69ef214SDavid Zhang 4347b1a245bSDavid Zhang static int aie4_load_fw(struct amdxdna_dev_hdl *ndev, 4357b1a245bSDavid Zhang void __iomem *tbl[PCI_NUM_RESOURCES]) 436c02697cbSDavid Zhang { 437e69ef214SDavid Zhang const struct firmware *npufw, *certfw; 4387b1a245bSDavid Zhang int ret; 4397b1a245bSDavid Zhang 4407b1a245bSDavid Zhang if (!ndev->priv->npufw_path && !ndev->priv->certfw_path) 4417b1a245bSDavid Zhang return 0; 4427b1a245bSDavid Zhang 4437b1a245bSDavid Zhang ret = aie4_request_firmware(ndev, &npufw, &certfw); 4447b1a245bSDavid Zhang if (ret) 4457b1a245bSDavid Zhang return ret; 4467b1a245bSDavid Zhang 4477b1a245bSDavid Zhang ret = aie4_prepare_firmware(ndev, npufw, certfw, tbl); 4487b1a245bSDavid Zhang aie4_release_firmware(ndev, npufw, certfw); 4497b1a245bSDavid Zhang 4507b1a245bSDavid Zhang return ret; 4517b1a245bSDavid Zhang } 4527b1a245bSDavid Zhang 4537b1a245bSDavid Zhang static int aie4m_pcidev_init(struct amdxdna_dev *xdna) 4547b1a245bSDavid Zhang { 4557b1a245bSDavid Zhang struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev); 4567b1a245bSDavid Zhang struct amdxdna_dev_hdl *ndev; 4577b1a245bSDavid Zhang void __iomem *tbl[PCI_NUM_RESOURCES] = {0}; 458c02697cbSDavid Zhang unsigned long bars = 0; 459c02697cbSDavid Zhang int ret, i; 460c02697cbSDavid Zhang 4617b1a245bSDavid Zhang ndev = drmm_kzalloc(&xdna->ddev, sizeof(*ndev), GFP_KERNEL); 4627b1a245bSDavid Zhang if (!ndev) 4637b1a245bSDavid Zhang return -ENOMEM; 4647b1a245bSDavid Zhang 4657b1a245bSDavid Zhang ndev->priv = xdna->dev_info->dev_priv; 4667b1a245bSDavid Zhang ndev->aie.xdna = xdna; 4677b1a245bSDavid Zhang xdna->dev_handle = ndev; 4687b1a245bSDavid Zhang 46919361279SDavid Zhang xa_init_flags(&ndev->cert_comp_xa, XA_FLAGS_ALLOC); 47019361279SDavid Zhang mutex_init(&ndev->cert_comp_lock); 47119361279SDavid Zhang 472c02697cbSDavid Zhang /* Enable managed PCI device */ 473c02697cbSDavid Zhang ret = pcim_enable_device(pdev); 474c02697cbSDavid Zhang if (ret) { 475c02697cbSDavid Zhang XDNA_ERR(xdna, "pcim enable device failed, ret %d", ret); 476c02697cbSDavid Zhang return ret; 477c02697cbSDavid Zhang } 478c02697cbSDavid Zhang 479c02697cbSDavid Zhang ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 480c02697cbSDavid Zhang if (ret) { 481c02697cbSDavid Zhang XDNA_ERR(xdna, "failed to set DMA mask to 64:%d", ret); 482c02697cbSDavid Zhang return ret; 483c02697cbSDavid Zhang } 484c02697cbSDavid Zhang 485e69ef214SDavid Zhang for (i = 0; i < PSP_MAX_REGS; i++) 486e69ef214SDavid Zhang set_bit(PSP_REG_BAR(ndev, i), &bars); 48743c9a66eSDavid Zhang for (i = 0; i < SMU_MAX_REGS; i++) 48843c9a66eSDavid Zhang set_bit(SMU_REG_BAR(ndev, i), &bars); 489c02697cbSDavid Zhang set_bit(xdna->dev_info->mbox_bar, &bars); 490c02697cbSDavid Zhang set_bit(xdna->dev_info->sram_bar, &bars); 491c02697cbSDavid Zhang 492c02697cbSDavid Zhang for (i = 0; i < PCI_NUM_RESOURCES; i++) { 493c02697cbSDavid Zhang if (!test_bit(i, &bars)) 494c02697cbSDavid Zhang continue; 495c02697cbSDavid Zhang tbl[i] = pcim_iomap(pdev, i, 0); 496c02697cbSDavid Zhang if (!tbl[i]) { 497c02697cbSDavid Zhang XDNA_ERR(xdna, "map bar %d failed", i); 498c02697cbSDavid Zhang return -ENOMEM; 499c02697cbSDavid Zhang } 500c02697cbSDavid Zhang } 501c02697cbSDavid Zhang 502c02697cbSDavid Zhang ndev->mbox_base = tbl[xdna->dev_info->mbox_bar]; 503c02697cbSDavid Zhang ndev->rbuf_base = tbl[xdna->dev_info->sram_bar]; 504c02697cbSDavid Zhang 505c02697cbSDavid Zhang pci_set_master(pdev); 506c02697cbSDavid Zhang 5077b1a245bSDavid Zhang ret = aie4_load_fw(ndev, tbl); 508e69ef214SDavid Zhang if (ret) 5097b1a245bSDavid Zhang return ret; 510e69ef214SDavid Zhang 511c02697cbSDavid Zhang ret = aie4_irq_init(xdna); 512c02697cbSDavid Zhang if (ret) 513c02697cbSDavid Zhang return ret; 514c02697cbSDavid Zhang 515d8c33b9cSMax Zhen amdxdna_vbnv_init(xdna); 5167b1a245bSDavid Zhang XDNA_DBG(xdna, "init finished"); 5177b1a245bSDavid Zhang 518c02697cbSDavid Zhang return 0; 519c02697cbSDavid Zhang } 520c02697cbSDavid Zhang 52191f4da82SDavid Zhang static int aie4_doorbell_mmap(struct amdxdna_client *client, struct vm_area_struct *vma) 52291f4da82SDavid Zhang { 52391f4da82SDavid Zhang struct amdxdna_dev *xdna = client->xdna; 52491f4da82SDavid Zhang struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev); 52591f4da82SDavid Zhang const struct amdxdna_dev_priv *npriv = xdna->dev_info->dev_priv; 52691f4da82SDavid Zhang phys_addr_t res_start; 52791f4da82SDavid Zhang unsigned long pfn; 52891f4da82SDavid Zhang int ret; 52991f4da82SDavid Zhang 53091f4da82SDavid Zhang if (!aie4_hwctx_valid_doorbell(client, vma->vm_pgoff)) { 53191f4da82SDavid Zhang XDNA_ERR(xdna, "Invalid doorbell page offset 0x%lx", vma->vm_pgoff); 53291f4da82SDavid Zhang return -EINVAL; 53391f4da82SDavid Zhang } 53491f4da82SDavid Zhang 53591f4da82SDavid Zhang if (vma_pages(vma) != 1) { 53691f4da82SDavid Zhang XDNA_ERR(xdna, "can only map one page, got %ld", vma_pages(vma)); 53791f4da82SDavid Zhang return -EINVAL; 53891f4da82SDavid Zhang } 53991f4da82SDavid Zhang 54091f4da82SDavid Zhang res_start = pci_resource_start(pdev, xdna->dev_info->doorbell_bar) + npriv->doorbell_off; 54191f4da82SDavid Zhang pfn = PHYS_PFN(res_start) + vma->vm_pgoff; 54291f4da82SDavid Zhang vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 54391f4da82SDavid Zhang vm_flags_set(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP); 54491f4da82SDavid Zhang ret = io_remap_pfn_range(vma, vma->vm_start, 54591f4da82SDavid Zhang pfn, 54691f4da82SDavid Zhang PAGE_SIZE, 54791f4da82SDavid Zhang vma->vm_page_prot); 54891f4da82SDavid Zhang 54991f4da82SDavid Zhang XDNA_DBG(xdna, "doorbell ret %d", ret); 55091f4da82SDavid Zhang return ret; 55191f4da82SDavid Zhang } 55291f4da82SDavid Zhang 5530b087e06SDavid Zhang static int aie4_get_info(struct amdxdna_client *client, struct amdxdna_drm_get_info *args) 5540b087e06SDavid Zhang { 5550b087e06SDavid Zhang struct amdxdna_dev *xdna = client->xdna; 5560b087e06SDavid Zhang struct amdxdna_dev_hdl *ndev = xdna->dev_handle; 5570b087e06SDavid Zhang int ret; 5580b087e06SDavid Zhang 5590b087e06SDavid Zhang switch (args->param) { 5600b087e06SDavid Zhang case DRM_AMDXDNA_QUERY_AIE_METADATA: 5610b087e06SDavid Zhang ret = amdxdna_get_metadata(&ndev->aie, client, args); 5620b087e06SDavid Zhang break; 5630b087e06SDavid Zhang default: 5640b087e06SDavid Zhang XDNA_ERR(xdna, "Not supported request parameter %u", args->param); 5650b087e06SDavid Zhang ret = -EOPNOTSUPP; 5660b087e06SDavid Zhang } 5670b087e06SDavid Zhang 5680b087e06SDavid Zhang XDNA_DBG(xdna, "Got param %d", args->param); 5690b087e06SDavid Zhang 5700b087e06SDavid Zhang return ret; 5710b087e06SDavid Zhang } 5720b087e06SDavid Zhang 573*c0069781SNishad Saraf static int aie4_alloc_work_buffer(struct amdxdna_dev_hdl *ndev) 574*c0069781SNishad Saraf { 575*c0069781SNishad Saraf struct amdxdna_dev *xdna = ndev->aie.xdna; 576*c0069781SNishad Saraf u32 buf_size = AIE4_WORK_BUFFER_MIN_SIZE; 577*c0069781SNishad Saraf 578*c0069781SNishad Saraf ndev->work_buf = amdxdna_alloc_msg_buffer(xdna, &buf_size, 579*c0069781SNishad Saraf &ndev->work_buf_addr); 580*c0069781SNishad Saraf if (IS_ERR(ndev->work_buf)) { 581*c0069781SNishad Saraf int ret = PTR_ERR(ndev->work_buf); 582*c0069781SNishad Saraf 583*c0069781SNishad Saraf XDNA_ERR(xdna, "Failed to alloc work buffer, size 0x%x", 584*c0069781SNishad Saraf AIE4_WORK_BUFFER_MIN_SIZE); 585*c0069781SNishad Saraf ndev->work_buf = NULL; 586*c0069781SNishad Saraf return ret; 587*c0069781SNishad Saraf } 588*c0069781SNishad Saraf 589*c0069781SNishad Saraf ndev->work_buf_size = buf_size; 590*c0069781SNishad Saraf XDNA_DBG(xdna, "Work buffer allocated: size 0x%x", buf_size); 591*c0069781SNishad Saraf 592*c0069781SNishad Saraf return 0; 593*c0069781SNishad Saraf } 594*c0069781SNishad Saraf 595*c0069781SNishad Saraf static void aie4_free_work_buffer(struct amdxdna_dev_hdl *ndev) 596*c0069781SNishad Saraf { 597*c0069781SNishad Saraf struct amdxdna_dev *xdna = ndev->aie.xdna; 598*c0069781SNishad Saraf 599*c0069781SNishad Saraf if (!ndev->work_buf) 600*c0069781SNishad Saraf return; 601*c0069781SNishad Saraf 602*c0069781SNishad Saraf amdxdna_free_msg_buffer(xdna, ndev->work_buf_size, ndev->work_buf, 603*c0069781SNishad Saraf ndev->work_buf_addr); 604*c0069781SNishad Saraf ndev->work_buf = NULL; 605*c0069781SNishad Saraf } 606*c0069781SNishad Saraf 6077b1a245bSDavid Zhang static int aie4_pf_init(struct amdxdna_dev *xdna) 6087b1a245bSDavid Zhang { 6097b1a245bSDavid Zhang int ret; 6107b1a245bSDavid Zhang 6117b1a245bSDavid Zhang ret = aie4m_pcidev_init(xdna); 6127b1a245bSDavid Zhang if (ret) 6137b1a245bSDavid Zhang return ret; 6147b1a245bSDavid Zhang 615*c0069781SNishad Saraf ret = aie4_alloc_work_buffer(xdna->dev_handle); 616*c0069781SNishad Saraf if (ret) 617*c0069781SNishad Saraf return ret; 618*c0069781SNishad Saraf 619*c0069781SNishad Saraf ret = aie4_pf_hw_start(xdna->dev_handle); 620*c0069781SNishad Saraf if (ret) 621*c0069781SNishad Saraf goto free_work_buf; 622*c0069781SNishad Saraf 623*c0069781SNishad Saraf return 0; 624*c0069781SNishad Saraf 625*c0069781SNishad Saraf free_work_buf: 626*c0069781SNishad Saraf aie4_free_work_buffer(xdna->dev_handle); 627*c0069781SNishad Saraf return ret; 6287b1a245bSDavid Zhang } 6297b1a245bSDavid Zhang 6307b1a245bSDavid Zhang static int aie4_vf_init(struct amdxdna_dev *xdna) 6317b1a245bSDavid Zhang { 6327b1a245bSDavid Zhang int ret; 6337b1a245bSDavid Zhang 6347b1a245bSDavid Zhang ret = aie4m_pcidev_init(xdna); 6357b1a245bSDavid Zhang if (ret) 6367b1a245bSDavid Zhang return ret; 6377b1a245bSDavid Zhang 6387b1a245bSDavid Zhang return aie4_vf_hw_start(xdna->dev_handle); 6397b1a245bSDavid Zhang } 6407b1a245bSDavid Zhang 6417b1a245bSDavid Zhang static void aie4_pf_fini(struct amdxdna_dev *xdna) 6427b1a245bSDavid Zhang { 6437b1a245bSDavid Zhang aie4_sriov_stop(xdna->dev_handle); 6447b1a245bSDavid Zhang aie4_pf_hw_stop(xdna->dev_handle); 645*c0069781SNishad Saraf aie4_free_work_buffer(xdna->dev_handle); 6467b1a245bSDavid Zhang } 6477b1a245bSDavid Zhang 6487b1a245bSDavid Zhang static void aie4_vf_fini(struct amdxdna_dev *xdna) 6497b1a245bSDavid Zhang { 6507b1a245bSDavid Zhang aie4_vf_hw_stop(xdna->dev_handle); 6517b1a245bSDavid Zhang } 6527b1a245bSDavid Zhang 6537b1a245bSDavid Zhang const struct amdxdna_dev_ops aie4_pf_ops = { 6547b1a245bSDavid Zhang .init = aie4_pf_init, 6557b1a245bSDavid Zhang .fini = aie4_pf_fini, 656c02697cbSDavid Zhang .sriov_configure = aie4_sriov_configure, 657c02697cbSDavid Zhang }; 6587b1a245bSDavid Zhang 6597b1a245bSDavid Zhang const struct amdxdna_dev_ops aie4_vf_ops = { 6607b1a245bSDavid Zhang .init = aie4_vf_init, 6617b1a245bSDavid Zhang .fini = aie4_vf_fini, 66219361279SDavid Zhang .hwctx_init = aie4_hwctx_init, 66319361279SDavid Zhang .hwctx_fini = aie4_hwctx_fini, 66491f4da82SDavid Zhang .mmap = aie4_doorbell_mmap, 66591f4da82SDavid Zhang .cmd_wait = aie4_cmd_wait, 6660b087e06SDavid Zhang .get_aie_info = aie4_get_info, 6677b1a245bSDavid Zhang }; 668