18a27ad81SWachowski, Karol // SPDX-License-Identifier: GPL-2.0-only 28a27ad81SWachowski, Karol /* 38a27ad81SWachowski, Karol * Copyright (C) 2020 - 2024 Intel Corporation 48a27ad81SWachowski, Karol */ 58a27ad81SWachowski, Karol 68a27ad81SWachowski, Karol #include "ivpu_drv.h" 78a27ad81SWachowski, Karol #include "ivpu_hw.h" 88a27ad81SWachowski, Karol #include "ivpu_hw_btrs.h" 98a27ad81SWachowski, Karol #include "ivpu_hw_ip.h" 108a27ad81SWachowski, Karol 118a27ad81SWachowski, Karol #include <linux/dmi.h> 128a27ad81SWachowski, Karol 138a27ad81SWachowski, Karol static char *platform_to_str(u32 platform) 148a27ad81SWachowski, Karol { 158a27ad81SWachowski, Karol switch (platform) { 168a27ad81SWachowski, Karol case IVPU_PLATFORM_SILICON: 178a27ad81SWachowski, Karol return "SILICON"; 188a27ad81SWachowski, Karol case IVPU_PLATFORM_SIMICS: 198a27ad81SWachowski, Karol return "SIMICS"; 208a27ad81SWachowski, Karol case IVPU_PLATFORM_FPGA: 218a27ad81SWachowski, Karol return "FPGA"; 228a27ad81SWachowski, Karol default: 238a27ad81SWachowski, Karol return "Invalid platform"; 248a27ad81SWachowski, Karol } 258a27ad81SWachowski, Karol } 268a27ad81SWachowski, Karol 278a27ad81SWachowski, Karol static const struct dmi_system_id dmi_platform_simulation[] = { 288a27ad81SWachowski, Karol { 298a27ad81SWachowski, Karol .ident = "Intel Simics", 308a27ad81SWachowski, Karol .matches = { 318a27ad81SWachowski, Karol DMI_MATCH(DMI_BOARD_NAME, "lnlrvp"), 328a27ad81SWachowski, Karol DMI_MATCH(DMI_BOARD_VERSION, "1.0"), 338a27ad81SWachowski, Karol DMI_MATCH(DMI_BOARD_SERIAL, "123456789"), 348a27ad81SWachowski, Karol }, 358a27ad81SWachowski, Karol }, 368a27ad81SWachowski, Karol { 378a27ad81SWachowski, Karol .ident = "Intel Simics", 388a27ad81SWachowski, Karol .matches = { 398a27ad81SWachowski, Karol DMI_MATCH(DMI_BOARD_NAME, "Simics"), 408a27ad81SWachowski, Karol }, 418a27ad81SWachowski, Karol }, 428a27ad81SWachowski, Karol { } 438a27ad81SWachowski, Karol }; 448a27ad81SWachowski, Karol 458a27ad81SWachowski, Karol static void platform_init(struct ivpu_device *vdev) 468a27ad81SWachowski, Karol { 478a27ad81SWachowski, Karol if (dmi_check_system(dmi_platform_simulation)) 488a27ad81SWachowski, Karol vdev->platform = IVPU_PLATFORM_SIMICS; 498a27ad81SWachowski, Karol else 508a27ad81SWachowski, Karol vdev->platform = IVPU_PLATFORM_SILICON; 518a27ad81SWachowski, Karol 528a27ad81SWachowski, Karol ivpu_dbg(vdev, MISC, "Platform type: %s (%d)\n", 538a27ad81SWachowski, Karol platform_to_str(vdev->platform), vdev->platform); 548a27ad81SWachowski, Karol } 558a27ad81SWachowski, Karol 568a27ad81SWachowski, Karol static void wa_init(struct ivpu_device *vdev) 578a27ad81SWachowski, Karol { 588a27ad81SWachowski, Karol vdev->wa.punit_disabled = ivpu_is_fpga(vdev); 598a27ad81SWachowski, Karol vdev->wa.clear_runtime_mem = false; 608a27ad81SWachowski, Karol 618a27ad81SWachowski, Karol if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL) 628a27ad81SWachowski, Karol vdev->wa.interrupt_clear_with_0 = ivpu_hw_btrs_irqs_clear_with_0_mtl(vdev); 638a27ad81SWachowski, Karol 64*52ab5be1SWachowski, Karol if (ivpu_device_id(vdev) == PCI_DEVICE_ID_LNL && 65*52ab5be1SWachowski, Karol ivpu_revision(vdev) < IVPU_HW_IP_REV_LNL_B0) 668a27ad81SWachowski, Karol vdev->wa.disable_clock_relinquish = true; 678a27ad81SWachowski, Karol 68d9dfc4eaSWachowski, Karol if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX) 69d9dfc4eaSWachowski, Karol vdev->wa.wp0_during_power_up = true; 70d9dfc4eaSWachowski, Karol 718a27ad81SWachowski, Karol IVPU_PRINT_WA(punit_disabled); 728a27ad81SWachowski, Karol IVPU_PRINT_WA(clear_runtime_mem); 738a27ad81SWachowski, Karol IVPU_PRINT_WA(interrupt_clear_with_0); 748a27ad81SWachowski, Karol IVPU_PRINT_WA(disable_clock_relinquish); 75d9dfc4eaSWachowski, Karol IVPU_PRINT_WA(wp0_during_power_up); 768a27ad81SWachowski, Karol } 778a27ad81SWachowski, Karol 788a27ad81SWachowski, Karol static void timeouts_init(struct ivpu_device *vdev) 798a27ad81SWachowski, Karol { 808a27ad81SWachowski, Karol if (ivpu_is_fpga(vdev)) { 818a27ad81SWachowski, Karol vdev->timeout.boot = 100000; 828a27ad81SWachowski, Karol vdev->timeout.jsm = 50000; 838a27ad81SWachowski, Karol vdev->timeout.tdr = 2000000; 848a27ad81SWachowski, Karol vdev->timeout.reschedule_suspend = 1000; 858a27ad81SWachowski, Karol vdev->timeout.autosuspend = -1; 868a27ad81SWachowski, Karol vdev->timeout.d0i3_entry_msg = 500; 878a27ad81SWachowski, Karol } else if (ivpu_is_simics(vdev)) { 888a27ad81SWachowski, Karol vdev->timeout.boot = 50; 898a27ad81SWachowski, Karol vdev->timeout.jsm = 500; 908a27ad81SWachowski, Karol vdev->timeout.tdr = 10000; 918a27ad81SWachowski, Karol vdev->timeout.reschedule_suspend = 10; 928a27ad81SWachowski, Karol vdev->timeout.autosuspend = -1; 938a27ad81SWachowski, Karol vdev->timeout.d0i3_entry_msg = 100; 948a27ad81SWachowski, Karol } else { 958a27ad81SWachowski, Karol vdev->timeout.boot = 1000; 968a27ad81SWachowski, Karol vdev->timeout.jsm = 500; 978a27ad81SWachowski, Karol vdev->timeout.tdr = 2000; 988a27ad81SWachowski, Karol vdev->timeout.reschedule_suspend = 10; 998a27ad81SWachowski, Karol vdev->timeout.autosuspend = 10; 1008a27ad81SWachowski, Karol vdev->timeout.d0i3_entry_msg = 5; 1018a27ad81SWachowski, Karol } 1028a27ad81SWachowski, Karol } 1038a27ad81SWachowski, Karol 1048a27ad81SWachowski, Karol static void memory_ranges_init(struct ivpu_device *vdev) 1058a27ad81SWachowski, Karol { 1068a27ad81SWachowski, Karol if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX) { 1078a27ad81SWachowski, Karol ivpu_hw_range_init(&vdev->hw->ranges.global, 0x80000000, SZ_512M); 1088a27ad81SWachowski, Karol ivpu_hw_range_init(&vdev->hw->ranges.user, 0xc0000000, 255 * SZ_1M); 1098a27ad81SWachowski, Karol ivpu_hw_range_init(&vdev->hw->ranges.shave, 0x180000000, SZ_2G); 1108a27ad81SWachowski, Karol ivpu_hw_range_init(&vdev->hw->ranges.dma, 0x200000000, SZ_8G); 1118a27ad81SWachowski, Karol } else { 1128a27ad81SWachowski, Karol ivpu_hw_range_init(&vdev->hw->ranges.global, 0x80000000, SZ_512M); 1138a27ad81SWachowski, Karol ivpu_hw_range_init(&vdev->hw->ranges.user, 0x80000000, SZ_256M); 1148a27ad81SWachowski, Karol ivpu_hw_range_init(&vdev->hw->ranges.shave, 0x80000000 + SZ_256M, SZ_2G - SZ_256M); 1158a27ad81SWachowski, Karol ivpu_hw_range_init(&vdev->hw->ranges.dma, 0x200000000, SZ_8G); 1168a27ad81SWachowski, Karol } 1178a27ad81SWachowski, Karol } 1188a27ad81SWachowski, Karol 1198a27ad81SWachowski, Karol static int wp_enable(struct ivpu_device *vdev) 1208a27ad81SWachowski, Karol { 1218a27ad81SWachowski, Karol return ivpu_hw_btrs_wp_drive(vdev, true); 1228a27ad81SWachowski, Karol } 1238a27ad81SWachowski, Karol 1248a27ad81SWachowski, Karol static int wp_disable(struct ivpu_device *vdev) 1258a27ad81SWachowski, Karol { 1268a27ad81SWachowski, Karol return ivpu_hw_btrs_wp_drive(vdev, false); 1278a27ad81SWachowski, Karol } 1288a27ad81SWachowski, Karol 1298a27ad81SWachowski, Karol int ivpu_hw_power_up(struct ivpu_device *vdev) 1308a27ad81SWachowski, Karol { 1318a27ad81SWachowski, Karol int ret; 1328a27ad81SWachowski, Karol 133d9dfc4eaSWachowski, Karol if (IVPU_WA(wp0_during_power_up)) { 134d9dfc4eaSWachowski, Karol /* WP requests may fail when powering down, so issue WP 0 here */ 135d9dfc4eaSWachowski, Karol ret = wp_disable(vdev); 136d9dfc4eaSWachowski, Karol if (ret) 137d9dfc4eaSWachowski, Karol ivpu_warn(vdev, "Failed to disable workpoint: %d\n", ret); 138d9dfc4eaSWachowski, Karol } 139d9dfc4eaSWachowski, Karol 1408a27ad81SWachowski, Karol ret = ivpu_hw_btrs_d0i3_disable(vdev); 1418a27ad81SWachowski, Karol if (ret) 1428a27ad81SWachowski, Karol ivpu_warn(vdev, "Failed to disable D0I3: %d\n", ret); 1438a27ad81SWachowski, Karol 1448a27ad81SWachowski, Karol ret = wp_enable(vdev); 1458a27ad81SWachowski, Karol if (ret) { 1468a27ad81SWachowski, Karol ivpu_err(vdev, "Failed to enable workpoint: %d\n", ret); 1478a27ad81SWachowski, Karol return ret; 1488a27ad81SWachowski, Karol } 1498a27ad81SWachowski, Karol 1508a27ad81SWachowski, Karol if (ivpu_hw_btrs_gen(vdev) >= IVPU_HW_BTRS_LNL) { 1518a27ad81SWachowski, Karol if (IVPU_WA(disable_clock_relinquish)) 1528a27ad81SWachowski, Karol ivpu_hw_btrs_clock_relinquish_disable_lnl(vdev); 1538a27ad81SWachowski, Karol ivpu_hw_btrs_profiling_freq_reg_set_lnl(vdev); 1548a27ad81SWachowski, Karol ivpu_hw_btrs_ats_print_lnl(vdev); 1558a27ad81SWachowski, Karol } 1568a27ad81SWachowski, Karol 1578a27ad81SWachowski, Karol ret = ivpu_hw_ip_host_ss_configure(vdev); 1588a27ad81SWachowski, Karol if (ret) { 1598a27ad81SWachowski, Karol ivpu_err(vdev, "Failed to configure host SS: %d\n", ret); 1608a27ad81SWachowski, Karol return ret; 1618a27ad81SWachowski, Karol } 1628a27ad81SWachowski, Karol 1638a27ad81SWachowski, Karol ivpu_hw_ip_idle_gen_disable(vdev); 1648a27ad81SWachowski, Karol 1658a27ad81SWachowski, Karol ret = ivpu_hw_btrs_wait_for_clock_res_own_ack(vdev); 1668a27ad81SWachowski, Karol if (ret) { 1678a27ad81SWachowski, Karol ivpu_err(vdev, "Timed out waiting for clock resource own ACK\n"); 1688a27ad81SWachowski, Karol return ret; 1698a27ad81SWachowski, Karol } 1708a27ad81SWachowski, Karol 1718a27ad81SWachowski, Karol ret = ivpu_hw_ip_pwr_domain_enable(vdev); 1728a27ad81SWachowski, Karol if (ret) { 1738a27ad81SWachowski, Karol ivpu_err(vdev, "Failed to enable power domain: %d\n", ret); 1748a27ad81SWachowski, Karol return ret; 1758a27ad81SWachowski, Karol } 1768a27ad81SWachowski, Karol 1778a27ad81SWachowski, Karol ret = ivpu_hw_ip_host_ss_axi_enable(vdev); 1788a27ad81SWachowski, Karol if (ret) { 1798a27ad81SWachowski, Karol ivpu_err(vdev, "Failed to enable AXI: %d\n", ret); 1808a27ad81SWachowski, Karol return ret; 1818a27ad81SWachowski, Karol } 1828a27ad81SWachowski, Karol 1838a27ad81SWachowski, Karol if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_LNL) 1848a27ad81SWachowski, Karol ivpu_hw_btrs_set_port_arbitration_weights_lnl(vdev); 1858a27ad81SWachowski, Karol 1868a27ad81SWachowski, Karol ret = ivpu_hw_ip_top_noc_enable(vdev); 1878a27ad81SWachowski, Karol if (ret) 1888a27ad81SWachowski, Karol ivpu_err(vdev, "Failed to enable TOP NOC: %d\n", ret); 1898a27ad81SWachowski, Karol 1908a27ad81SWachowski, Karol return ret; 1918a27ad81SWachowski, Karol } 1928a27ad81SWachowski, Karol 1938a27ad81SWachowski, Karol static void save_d0i3_entry_timestamp(struct ivpu_device *vdev) 1948a27ad81SWachowski, Karol { 1958a27ad81SWachowski, Karol vdev->hw->d0i3_entry_host_ts = ktime_get_boottime(); 1968a27ad81SWachowski, Karol vdev->hw->d0i3_entry_vpu_ts = ivpu_hw_ip_read_perf_timer_counter(vdev); 1978a27ad81SWachowski, Karol } 1988a27ad81SWachowski, Karol 1998a27ad81SWachowski, Karol int ivpu_hw_reset(struct ivpu_device *vdev) 2008a27ad81SWachowski, Karol { 2018a27ad81SWachowski, Karol int ret = 0; 2028a27ad81SWachowski, Karol 2038a27ad81SWachowski, Karol if (ivpu_hw_btrs_ip_reset(vdev)) { 2048a27ad81SWachowski, Karol ivpu_err(vdev, "Failed to reset NPU IP\n"); 2058a27ad81SWachowski, Karol ret = -EIO; 2068a27ad81SWachowski, Karol } 2078a27ad81SWachowski, Karol 2088a27ad81SWachowski, Karol if (wp_disable(vdev)) { 2098a27ad81SWachowski, Karol ivpu_err(vdev, "Failed to disable workpoint\n"); 2108a27ad81SWachowski, Karol ret = -EIO; 2118a27ad81SWachowski, Karol } 2128a27ad81SWachowski, Karol 2138a27ad81SWachowski, Karol return ret; 2148a27ad81SWachowski, Karol } 2158a27ad81SWachowski, Karol 2168a27ad81SWachowski, Karol int ivpu_hw_power_down(struct ivpu_device *vdev) 2178a27ad81SWachowski, Karol { 2188a27ad81SWachowski, Karol int ret = 0; 2198a27ad81SWachowski, Karol 2208a27ad81SWachowski, Karol save_d0i3_entry_timestamp(vdev); 2218a27ad81SWachowski, Karol 2228a27ad81SWachowski, Karol if (!ivpu_hw_is_idle(vdev)) 2238a27ad81SWachowski, Karol ivpu_warn(vdev, "NPU not idle during power down\n"); 2248a27ad81SWachowski, Karol 2258a27ad81SWachowski, Karol if (ivpu_hw_reset(vdev)) { 2268a27ad81SWachowski, Karol ivpu_err(vdev, "Failed to reset NPU\n"); 2278a27ad81SWachowski, Karol ret = -EIO; 2288a27ad81SWachowski, Karol } 2298a27ad81SWachowski, Karol 2308a27ad81SWachowski, Karol if (ivpu_hw_btrs_d0i3_enable(vdev)) { 2318a27ad81SWachowski, Karol ivpu_err(vdev, "Failed to enter D0I3\n"); 2328a27ad81SWachowski, Karol ret = -EIO; 2338a27ad81SWachowski, Karol } 2348a27ad81SWachowski, Karol 2358a27ad81SWachowski, Karol return ret; 2368a27ad81SWachowski, Karol } 2378a27ad81SWachowski, Karol 2388a27ad81SWachowski, Karol int ivpu_hw_init(struct ivpu_device *vdev) 2398a27ad81SWachowski, Karol { 2408a27ad81SWachowski, Karol ivpu_hw_btrs_info_init(vdev); 2418a27ad81SWachowski, Karol ivpu_hw_btrs_freq_ratios_init(vdev); 2428a27ad81SWachowski, Karol memory_ranges_init(vdev); 2438a27ad81SWachowski, Karol platform_init(vdev); 2448a27ad81SWachowski, Karol wa_init(vdev); 2458a27ad81SWachowski, Karol timeouts_init(vdev); 2468a27ad81SWachowski, Karol 2478a27ad81SWachowski, Karol return 0; 2488a27ad81SWachowski, Karol } 2498a27ad81SWachowski, Karol 2508a27ad81SWachowski, Karol int ivpu_hw_boot_fw(struct ivpu_device *vdev) 2518a27ad81SWachowski, Karol { 2528a27ad81SWachowski, Karol int ret; 2538a27ad81SWachowski, Karol 2548a27ad81SWachowski, Karol ivpu_hw_ip_snoop_disable(vdev); 2558a27ad81SWachowski, Karol ivpu_hw_ip_tbu_mmu_enable(vdev); 2568a27ad81SWachowski, Karol ret = ivpu_hw_ip_soc_cpu_boot(vdev); 2578a27ad81SWachowski, Karol if (ret) 2588a27ad81SWachowski, Karol ivpu_err(vdev, "Failed to boot SOC CPU: %d\n", ret); 2598a27ad81SWachowski, Karol 2608a27ad81SWachowski, Karol return ret; 2618a27ad81SWachowski, Karol } 2628a27ad81SWachowski, Karol 2638a27ad81SWachowski, Karol void ivpu_hw_profiling_freq_drive(struct ivpu_device *vdev, bool enable) 2648a27ad81SWachowski, Karol { 2658a27ad81SWachowski, Karol if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX) { 2668a27ad81SWachowski, Karol vdev->hw->pll.profiling_freq = PLL_PROFILING_FREQ_DEFAULT; 2678a27ad81SWachowski, Karol return; 2688a27ad81SWachowski, Karol } 2698a27ad81SWachowski, Karol 2708a27ad81SWachowski, Karol if (enable) 2718a27ad81SWachowski, Karol vdev->hw->pll.profiling_freq = PLL_PROFILING_FREQ_HIGH; 2728a27ad81SWachowski, Karol else 2738a27ad81SWachowski, Karol vdev->hw->pll.profiling_freq = PLL_PROFILING_FREQ_DEFAULT; 2748a27ad81SWachowski, Karol } 2758a27ad81SWachowski, Karol 2768a27ad81SWachowski, Karol void ivpu_irq_handlers_init(struct ivpu_device *vdev) 2778a27ad81SWachowski, Karol { 2782f7ffb06SJacek Lawrynowicz INIT_KFIFO(vdev->hw->irq.fifo); 2792f7ffb06SJacek Lawrynowicz 2808a27ad81SWachowski, Karol if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX) 2818a27ad81SWachowski, Karol vdev->hw->irq.ip_irq_handler = ivpu_hw_ip_irq_handler_37xx; 2828a27ad81SWachowski, Karol else 2838a27ad81SWachowski, Karol vdev->hw->irq.ip_irq_handler = ivpu_hw_ip_irq_handler_40xx; 2848a27ad81SWachowski, Karol 2858a27ad81SWachowski, Karol if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL) 2868a27ad81SWachowski, Karol vdev->hw->irq.btrs_irq_handler = ivpu_hw_btrs_irq_handler_mtl; 2878a27ad81SWachowski, Karol else 2888a27ad81SWachowski, Karol vdev->hw->irq.btrs_irq_handler = ivpu_hw_btrs_irq_handler_lnl; 2898a27ad81SWachowski, Karol } 2908a27ad81SWachowski, Karol 2918a27ad81SWachowski, Karol void ivpu_hw_irq_enable(struct ivpu_device *vdev) 2928a27ad81SWachowski, Karol { 2932f7ffb06SJacek Lawrynowicz kfifo_reset(&vdev->hw->irq.fifo); 2948a27ad81SWachowski, Karol ivpu_hw_ip_irq_enable(vdev); 2958a27ad81SWachowski, Karol ivpu_hw_btrs_irq_enable(vdev); 2968a27ad81SWachowski, Karol } 2978a27ad81SWachowski, Karol 2988a27ad81SWachowski, Karol void ivpu_hw_irq_disable(struct ivpu_device *vdev) 2998a27ad81SWachowski, Karol { 3008a27ad81SWachowski, Karol ivpu_hw_btrs_irq_disable(vdev); 3018a27ad81SWachowski, Karol ivpu_hw_ip_irq_disable(vdev); 3028a27ad81SWachowski, Karol } 3038a27ad81SWachowski, Karol 3048a27ad81SWachowski, Karol irqreturn_t ivpu_hw_irq_handler(int irq, void *ptr) 3058a27ad81SWachowski, Karol { 3068a27ad81SWachowski, Karol struct ivpu_device *vdev = ptr; 3072f7ffb06SJacek Lawrynowicz bool ip_handled, btrs_handled; 3088a27ad81SWachowski, Karol 3098a27ad81SWachowski, Karol ivpu_hw_btrs_global_int_disable(vdev); 3108a27ad81SWachowski, Karol 3118a27ad81SWachowski, Karol btrs_handled = ivpu_hw_btrs_irq_handler(vdev, irq); 3128a27ad81SWachowski, Karol if (!ivpu_hw_is_idle((vdev)) || !btrs_handled) 3132f7ffb06SJacek Lawrynowicz ip_handled = ivpu_hw_ip_irq_handler(vdev, irq); 3148a27ad81SWachowski, Karol else 3158a27ad81SWachowski, Karol ip_handled = false; 3168a27ad81SWachowski, Karol 3178a27ad81SWachowski, Karol /* Re-enable global interrupts to re-trigger MSI for pending interrupts */ 3188a27ad81SWachowski, Karol ivpu_hw_btrs_global_int_enable(vdev); 3198a27ad81SWachowski, Karol 3202f7ffb06SJacek Lawrynowicz if (!kfifo_is_empty(&vdev->hw->irq.fifo)) 3218a27ad81SWachowski, Karol return IRQ_WAKE_THREAD; 3228a27ad81SWachowski, Karol if (ip_handled || btrs_handled) 3238a27ad81SWachowski, Karol return IRQ_HANDLED; 3248a27ad81SWachowski, Karol return IRQ_NONE; 3258a27ad81SWachowski, Karol } 326