]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
accel/ivpu: Implement warm boot flow for NPU6 and unify boot handling
authorKarol Wachowski <karol.wachowski@linux.intel.com>
Tue, 30 Dec 2025 14:21:16 +0000 (15:21 +0100)
committerMaciej Falkowski <maciej.falkowski@linux.intel.com>
Thu, 8 Jan 2026 10:49:37 +0000 (11:49 +0100)
Starting from NPU6, the driver can pass boot parameters address through
the AON retention register and toggle between cold/warm boot types using
the boot_type parameter, while setting the cold boot entry point in both
cases.

Refactor the existing cold/warm boot handling to be consistent with the
new NPU6 boot flow requirements and still maintain compatibility with
older boot flows.

This will allow firmware to remove support for legacy warm boot starting
from NPU6.

Fixes: 550f4dd2cedd ("accel/ivpu: Add support for Nova Lake's NPU")
Signed-off-by: Karol Wachowski <karol.wachowski@linux.intel.com>
Reviewed-by: Jeff Hugo <jeff.hugo@oss.qualcomm.com>
Reviewed-by: Andrzej Kacprowski <andrzej.kacprowski@linux.intel.com>
Signed-off-by: Maciej Falkowski <maciej.falkowski@linux.intel.com>
Link: https://patch.msgid.link/20251230142116.540026-1-maciej.falkowski@linux.intel.com
drivers/accel/ivpu/ivpu_debugfs.c
drivers/accel/ivpu/ivpu_drv.c
drivers/accel/ivpu/ivpu_fw.c
drivers/accel/ivpu/ivpu_fw.h
drivers/accel/ivpu/ivpu_hw_40xx_reg.h
drivers/accel/ivpu/ivpu_hw_ip.c
drivers/accel/ivpu/ivpu_hw_ip.h
drivers/accel/ivpu/ivpu_pm.c
drivers/accel/ivpu/ivpu_pm.h

index 3bd85ee6c26b78a91b7655a3d9797cf2eed66df6..a09f54fc43020686f3c65b0cdfa8ec74ced98722 100644 (file)
@@ -20,6 +20,7 @@
 #include "ivpu_hw.h"
 #include "ivpu_jsm_msg.h"
 #include "ivpu_pm.h"
+#include "vpu_boot_api.h"
 
 static inline struct ivpu_device *seq_to_ivpu(struct seq_file *s)
 {
@@ -96,7 +97,8 @@ static int last_bootmode_show(struct seq_file *s, void *v)
 {
        struct ivpu_device *vdev = seq_to_ivpu(s);
 
-       seq_printf(s, "%s\n", (vdev->pm->is_warmboot) ? "warmboot" : "coldboot");
+       seq_printf(s, "%s\n", (vdev->fw->last_boot_mode == VPU_BOOT_TYPE_WARMBOOT) ?
+                  "warm boot" : "cold boot");
 
        return 0;
 }
index 3d6fccdefdd64fe95c560686543b5084f30e2f81..8ffda57459dfbc4664807ab4ba28b645356c968c 100644 (file)
@@ -384,6 +384,7 @@ int ivpu_boot(struct ivpu_device *vdev)
        drm_WARN_ON(&vdev->drm, !xa_empty(&vdev->submitted_jobs_xa));
 
        ivpu_fw_boot_params_setup(vdev, ivpu_bo_vaddr(vdev->fw->mem_bp));
+       vdev->fw->last_boot_mode = vdev->fw->next_boot_mode;
 
        ret = ivpu_hw_boot_fw(vdev);
        if (ret) {
@@ -396,13 +397,12 @@ int ivpu_boot(struct ivpu_device *vdev)
                ivpu_err(vdev, "Failed to boot the firmware: %d\n", ret);
                goto err_diagnose_failure;
        }
-
        ivpu_hw_irq_clear(vdev);
        enable_irq(vdev->irq);
        ivpu_hw_irq_enable(vdev);
        ivpu_ipc_enable(vdev);
 
-       if (ivpu_fw_is_cold_boot(vdev)) {
+       if (!ivpu_fw_is_warm_boot(vdev)) {
                ret = ivpu_pm_dct_init(vdev);
                if (ret)
                        goto err_disable_ipc;
index 48386d2cddbb2caf46ed5bbb493600285e08bc59..107f8ad31050051980fa7ba7a61960779577cea9 100644 (file)
@@ -300,9 +300,7 @@ static int ivpu_fw_parse(struct ivpu_device *vdev)
        fw->image_load_offset = image_load_addr - runtime_addr;
        fw->image_size = image_size;
        fw->shave_nn_size = PAGE_ALIGN(fw_hdr->shave_nn_fw_size);
-
        fw->cold_boot_entry_point = fw_hdr->entry_point;
-       fw->entry_point = fw->cold_boot_entry_point;
 
        fw->trace_level = min_t(u32, ivpu_fw_log_level, IVPU_FW_LOG_FATAL);
        fw->trace_destination_mask = VPU_TRACE_DESTINATION_VERBOSE_TRACING;
@@ -338,7 +336,7 @@ static int ivpu_fw_parse(struct ivpu_device *vdev)
                 fw->image_load_offset, fw->image_size);
        ivpu_dbg(vdev, FW_BOOT, "Read-only section: address 0x%llx, size %u\n",
                 fw->read_only_addr, fw->read_only_size);
-       ivpu_dbg(vdev, FW_BOOT, "FW entry point: 0x%llx\n", fw->entry_point);
+       ivpu_dbg(vdev, FW_BOOT, "FW cold boot entry point: 0x%llx\n", fw->cold_boot_entry_point);
        ivpu_dbg(vdev, FW_BOOT, "SHAVE NN size: %u\n", fw->shave_nn_size);
 
        return 0;
@@ -616,6 +614,7 @@ static void ivpu_fw_boot_params_print(struct ivpu_device *vdev, struct vpu_boot_
                 boot_params->power_profile);
        ivpu_dbg(vdev, FW_BOOT, "boot_params.vpu_uses_ecc_mca_signal = 0x%x\n",
                 boot_params->vpu_uses_ecc_mca_signal);
+       ivpu_dbg(vdev, FW_BOOT, "boot_params.boot_type = 0x%x\n", boot_params->boot_type);
 }
 
 void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params *boot_params)
@@ -623,7 +622,7 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params
        struct ivpu_bo *ipc_mem_rx = vdev->ipc->mem_rx;
 
        /* In case of warm boot only update variable params */
-       if (!ivpu_fw_is_cold_boot(vdev)) {
+       if (ivpu_fw_is_warm_boot(vdev)) {
                boot_params->d0i3_residency_time_us =
                        ktime_us_delta(ktime_get_boottime(), vdev->hw->d0i3_entry_host_ts);
                boot_params->d0i3_entry_vpu_ts = vdev->hw->d0i3_entry_vpu_ts;
@@ -635,16 +634,16 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params
                         boot_params->d0i3_entry_vpu_ts);
                ivpu_dbg(vdev, FW_BOOT, "boot_params.system_time_us = %llu\n",
                         boot_params->system_time_us);
+               ivpu_dbg(vdev, FW_BOOT, "boot_params.boot_type = 0x%x\n", boot_params->boot_type);
 
                boot_params->save_restore_ret_address = 0;
-               vdev->pm->is_warmboot = true;
+               boot_params->boot_type = VPU_BOOT_TYPE_WARMBOOT;
                wmb(); /* Flush WC buffers after writing save_restore_ret_address */
                return;
        }
 
        memset(boot_params, 0, sizeof(*boot_params));
-       vdev->pm->is_warmboot = false;
-
+       boot_params->boot_type = VPU_BOOT_TYPE_COLDBOOT;
        boot_params->magic = VPU_BOOT_PARAMS_MAGIC;
        boot_params->vpu_id = to_pci_dev(vdev->drm.dev)->bus->number;
 
index 00945892b55ef97009b97cdee0437ba676a197d0..d3c410912c9cb28e7831a8a9486a5a5a8ea820d0 100644 (file)
@@ -6,6 +6,7 @@
 #ifndef __IVPU_FW_H__
 #define __IVPU_FW_H__
 
+#include "vpu_boot_api.h"
 #include "vpu_jsm_api.h"
 
 #define FW_VERSION_HEADER_SIZE SZ_4K
@@ -34,8 +35,10 @@ struct ivpu_fw_info {
        u64 image_load_offset;
        u32 image_size;
        u32 shave_nn_size;
-       u64 entry_point; /* Cold or warm boot entry point for next boot */
+       u64 warm_boot_entry_point;
        u64 cold_boot_entry_point;
+       u8 last_boot_mode;
+       u8 next_boot_mode;
        u32 trace_level;
        u32 trace_destination_mask;
        u64 trace_hw_component_mask;
@@ -54,9 +57,9 @@ void ivpu_fw_fini(struct ivpu_device *vdev);
 void ivpu_fw_load(struct ivpu_device *vdev);
 void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params *boot_params);
 
-static inline bool ivpu_fw_is_cold_boot(struct ivpu_device *vdev)
+static inline bool ivpu_fw_is_warm_boot(struct ivpu_device *vdev)
 {
-       return vdev->fw->entry_point == vdev->fw->cold_boot_entry_point;
+       return vdev->fw->next_boot_mode == VPU_BOOT_TYPE_WARMBOOT;
 }
 
 static inline u32 ivpu_fw_preempt_buf_size(struct ivpu_device *vdev)
index fc0ee8d637f9689e7d50fe9d9784b11d39c5b9d6..421242acb184451c652f31745cf6791389cde91f 100644 (file)
 #define VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY                     0x0003006cu
 #define VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY_STATUS_DLY_MASK     GENMASK(7, 0)
 
+#define VPU_40XX_HOST_SS_AON_RETENTION0                                 0x0003000cu
+#define VPU_40XX_HOST_SS_AON_RETENTION1                                 0x00030010u
+#define VPU_40XX_HOST_SS_AON_RETENTION2                                 0x00030014u
+#define VPU_40XX_HOST_SS_AON_RETENTION3                                 0x00030018u
+#define VPU_40XX_HOST_SS_AON_RETENTION4                                 0x0003001cu
+
 #define VPU_40XX_HOST_SS_AON_IDLE_GEN                                  0x00030200u
 #define VPU_40XX_HOST_SS_AON_IDLE_GEN_EN_MASK                          BIT_MASK(0)
 #define VPU_40XX_HOST_SS_AON_IDLE_GEN_HW_PG_EN_MASK                    BIT_MASK(1)
index 06aa1e7dc50b17a7d4c171253924ede816be90ed..959984c54341af11c940fd56934e38fc2226b4a6 100644 (file)
@@ -5,6 +5,7 @@
 
 #include "ivpu_drv.h"
 #include "ivpu_fw.h"
+#include "ivpu_gem.h"
 #include "ivpu_hw.h"
 #include "ivpu_hw_37xx_reg.h"
 #include "ivpu_hw_40xx_reg.h"
@@ -816,6 +817,14 @@ void ivpu_hw_ip_tbu_mmu_enable(struct ivpu_device *vdev)
                return ivpu_hw_ip_tbu_mmu_enable_40xx(vdev);
 }
 
+static inline u64 get_entry_point_addr(struct ivpu_device *vdev)
+{
+       if (ivpu_fw_is_warm_boot(vdev))
+               return vdev->fw->warm_boot_entry_point;
+       else
+               return vdev->fw->cold_boot_entry_point;
+}
+
 static int soc_cpu_boot_37xx(struct ivpu_device *vdev)
 {
        u32 val;
@@ -832,15 +841,12 @@ static int soc_cpu_boot_37xx(struct ivpu_device *vdev)
        val = REG_CLR_FLD(VPU_37XX_CPU_SS_MSSCPU_CPR_LEON_RT_VEC, IRQI_RESUME0, val);
        REGV_WR32(VPU_37XX_CPU_SS_MSSCPU_CPR_LEON_RT_VEC, val);
 
-       val = vdev->fw->entry_point >> 9;
+       val = get_entry_point_addr(vdev) >> 9;
        REGV_WR32(VPU_37XX_HOST_SS_LOADING_ADDRESS_LO, val);
 
        val = REG_SET_FLD(VPU_37XX_HOST_SS_LOADING_ADDRESS_LO, DONE, val);
        REGV_WR32(VPU_37XX_HOST_SS_LOADING_ADDRESS_LO, val);
 
-       ivpu_dbg(vdev, PM, "Booting firmware, mode: %s\n",
-                vdev->fw->entry_point == vdev->fw->cold_boot_entry_point ? "cold boot" : "resume");
-
        return 0;
 }
 
@@ -894,46 +900,68 @@ static int soc_cpu_drive_40xx(struct ivpu_device *vdev, bool enable)
        return ret;
 }
 
-static int soc_cpu_enable(struct ivpu_device *vdev)
+static void soc_cpu_set_entry_point_40xx(struct ivpu_device *vdev, u64 entry_point)
 {
-       if (ivpu_hw_ip_gen(vdev) >= IVPU_HW_IP_60XX)
-               return 0;
+       u64 val64;
+       u32 val;
+
+       val64 = entry_point;
+       val64 <<= ffs(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO_IMAGE_LOCATION_MASK) - 1;
+       REGV_WR64(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO, val64);
 
-       return soc_cpu_drive_40xx(vdev, true);
+       val = REGV_RD32(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO);
+       val = REG_SET_FLD(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO, DONE, val);
+       REGV_WR32(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO, val);
 }
 
 static int soc_cpu_boot_40xx(struct ivpu_device *vdev)
 {
        int ret;
-       u32 val;
-       u64 val64;
 
-       ret = soc_cpu_enable(vdev);
+       ret = soc_cpu_drive_40xx(vdev, true);
        if (ret) {
                ivpu_err(vdev, "Failed to enable SOC CPU: %d\n", ret);
                return ret;
        }
 
-       val64 = vdev->fw->entry_point;
-       val64 <<= ffs(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO_IMAGE_LOCATION_MASK) - 1;
-       REGV_WR64(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO, val64);
+       soc_cpu_set_entry_point_40xx(vdev, get_entry_point_addr(vdev));
 
-       val = REGV_RD32(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO);
-       val = REG_SET_FLD(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO, DONE, val);
-       REGV_WR32(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO, val);
+       return 0;
+}
 
-       ivpu_dbg(vdev, PM, "Booting firmware, mode: %s\n",
-                ivpu_fw_is_cold_boot(vdev) ? "cold boot" : "resume");
+static int soc_cpu_boot_60xx(struct ivpu_device *vdev)
+{
+       REGV_WR64(VPU_40XX_HOST_SS_AON_RETENTION1, vdev->fw->mem_bp->vpu_addr);
+       soc_cpu_set_entry_point_40xx(vdev, vdev->fw->cold_boot_entry_point);
 
        return 0;
 }
 
 int ivpu_hw_ip_soc_cpu_boot(struct ivpu_device *vdev)
 {
-       if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
-               return soc_cpu_boot_37xx(vdev);
-       else
-               return soc_cpu_boot_40xx(vdev);
+       int ret;
+
+       switch (ivpu_hw_ip_gen(vdev)) {
+       case IVPU_HW_IP_37XX:
+               ret = soc_cpu_boot_37xx(vdev);
+               break;
+
+       case IVPU_HW_IP_40XX:
+       case IVPU_HW_IP_50XX:
+               ret = soc_cpu_boot_40xx(vdev);
+               break;
+
+       default:
+               ret = soc_cpu_boot_60xx(vdev);
+       }
+
+       if (ret)
+               return ret;
+
+       ivpu_dbg(vdev, PM, "Booting firmware, mode: %s\n",
+                ivpu_fw_is_warm_boot(vdev) ? "warm boot" : "cold boot");
+
+       return 0;
 }
 
 static void wdt_disable_37xx(struct ivpu_device *vdev)
index 5b1b391aa5772c6cf8b595581b3a2effd0cb34ae..dbbcdd10a5f8cc270a746e69807de62f51ef1f1f 100644 (file)
@@ -29,7 +29,6 @@ u32 ivpu_hw_ip_ipc_rx_addr_get(struct ivpu_device *vdev);
 void ivpu_hw_ip_ipc_tx_set(struct ivpu_device *vdev, u32 vpu_addr);
 void ivpu_hw_ip_irq_enable(struct ivpu_device *vdev);
 void ivpu_hw_ip_irq_disable(struct ivpu_device *vdev);
-void ivpu_hw_ip_diagnose_failure(struct ivpu_device *vdev);
 void ivpu_hw_ip_fabric_req_override_enable_50xx(struct ivpu_device *vdev);
 void ivpu_hw_ip_fabric_req_override_disable_50xx(struct ivpu_device *vdev);
 
index 480c075d87f69927243b846bdfd37084c541db9a..d20144a21e090d619d89364a86b65959ad0f6ddb 100644 (file)
@@ -47,8 +47,10 @@ static void ivpu_pm_prepare_cold_boot(struct ivpu_device *vdev)
        ivpu_ipc_reset(vdev);
        ivpu_fw_log_reset(vdev);
        ivpu_fw_load(vdev);
-       fw->entry_point = fw->cold_boot_entry_point;
        fw->last_heartbeat = 0;
+
+       ivpu_dbg(vdev, FW_BOOT, "Cold boot entry point 0x%llx", vdev->fw->cold_boot_entry_point);
+       fw->next_boot_mode = VPU_BOOT_TYPE_COLDBOOT;
 }
 
 static void ivpu_pm_prepare_warm_boot(struct ivpu_device *vdev)
@@ -56,13 +58,14 @@ static void ivpu_pm_prepare_warm_boot(struct ivpu_device *vdev)
        struct ivpu_fw_info *fw = vdev->fw;
        struct vpu_boot_params *bp = ivpu_bo_vaddr(fw->mem_bp);
 
-       if (!bp->save_restore_ret_address) {
+       fw->warm_boot_entry_point = bp->save_restore_ret_address;
+       if (!fw->warm_boot_entry_point) {
                ivpu_pm_prepare_cold_boot(vdev);
                return;
        }
 
-       ivpu_dbg(vdev, FW_BOOT, "Save/restore entry point %llx", bp->save_restore_ret_address);
-       fw->entry_point = bp->save_restore_ret_address;
+       ivpu_dbg(vdev, FW_BOOT, "Warm boot entry point 0x%llx", fw->warm_boot_entry_point);
+       fw->next_boot_mode = VPU_BOOT_TYPE_WARMBOOT;
 }
 
 static int ivpu_suspend(struct ivpu_device *vdev)
@@ -110,7 +113,7 @@ err_power_down:
        ivpu_hw_power_down(vdev);
        pci_set_power_state(to_pci_dev(vdev->drm.dev), PCI_D3hot);
 
-       if (!ivpu_fw_is_cold_boot(vdev)) {
+       if (ivpu_fw_is_warm_boot(vdev)) {
                ivpu_pm_prepare_cold_boot(vdev);
                goto retry;
        } else {
index a2aa7a27f32ef820f5a8b73dc6cc2e4e38a2a34f..00f2a01e3df66c22a92505edb045dff70c134862 100644 (file)
@@ -18,7 +18,6 @@ struct ivpu_pm_info {
        struct rw_semaphore reset_lock;
        atomic_t reset_counter;
        atomic_t reset_pending;
-       bool is_warmboot;
        u8 dct_active_percent;
 };