1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2020 - 2024 Intel Corporation 4 */ 5 6 #include "ivpu_drv.h" 7 #include "ivpu_hw.h" 8 #include "ivpu_hw_btrs.h" 9 #include "ivpu_hw_ip.h" 10 11 #include <linux/dmi.h> 12 13 static char *platform_to_str(u32 platform) 14 { 15 switch (platform) { 16 case IVPU_PLATFORM_SILICON: 17 return "SILICON"; 18 case IVPU_PLATFORM_SIMICS: 19 return "SIMICS"; 20 case IVPU_PLATFORM_FPGA: 21 return "FPGA"; 22 default: 23 return "Invalid platform"; 24 } 25 } 26 27 static const struct dmi_system_id dmi_platform_simulation[] = { 28 { 29 .ident = "Intel Simics", 30 .matches = { 31 DMI_MATCH(DMI_BOARD_NAME, "lnlrvp"), 32 DMI_MATCH(DMI_BOARD_VERSION, "1.0"), 33 DMI_MATCH(DMI_BOARD_SERIAL, "123456789"), 34 }, 35 }, 36 { 37 .ident = "Intel Simics", 38 .matches = { 39 DMI_MATCH(DMI_BOARD_NAME, "Simics"), 40 }, 41 }, 42 { } 43 }; 44 45 static void platform_init(struct ivpu_device *vdev) 46 { 47 if (dmi_check_system(dmi_platform_simulation)) 48 vdev->platform = IVPU_PLATFORM_SIMICS; 49 else 50 vdev->platform = IVPU_PLATFORM_SILICON; 51 52 ivpu_dbg(vdev, MISC, "Platform type: %s (%d)\n", 53 platform_to_str(vdev->platform), vdev->platform); 54 } 55 56 static void wa_init(struct ivpu_device *vdev) 57 { 58 vdev->wa.punit_disabled = ivpu_is_fpga(vdev); 59 vdev->wa.clear_runtime_mem = false; 60 61 if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL) 62 vdev->wa.interrupt_clear_with_0 = ivpu_hw_btrs_irqs_clear_with_0_mtl(vdev); 63 64 if (ivpu_device_id(vdev) == PCI_DEVICE_ID_LNL && 65 ivpu_revision(vdev) < IVPU_HW_IP_REV_LNL_B0) 66 vdev->wa.disable_clock_relinquish = true; 67 68 if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX) 69 vdev->wa.wp0_during_power_up = true; 70 71 IVPU_PRINT_WA(punit_disabled); 72 IVPU_PRINT_WA(clear_runtime_mem); 73 IVPU_PRINT_WA(interrupt_clear_with_0); 74 IVPU_PRINT_WA(disable_clock_relinquish); 75 IVPU_PRINT_WA(wp0_during_power_up); 76 } 77 78 static void timeouts_init(struct ivpu_device *vdev) 79 { 80 if (ivpu_test_mode & IVPU_TEST_MODE_DISABLE_TIMEOUTS) { 81 vdev->timeout.boot = -1; 82 vdev->timeout.jsm = -1; 83 vdev->timeout.tdr = -1; 84 vdev->timeout.autosuspend = -1; 85 vdev->timeout.d0i3_entry_msg = -1; 86 } else if (ivpu_is_fpga(vdev)) { 87 vdev->timeout.boot = 100000; 88 vdev->timeout.jsm = 50000; 89 vdev->timeout.tdr = 2000000; 90 vdev->timeout.autosuspend = -1; 91 vdev->timeout.d0i3_entry_msg = 500; 92 } else if (ivpu_is_simics(vdev)) { 93 vdev->timeout.boot = 50; 94 vdev->timeout.jsm = 500; 95 vdev->timeout.tdr = 10000; 96 vdev->timeout.autosuspend = -1; 97 vdev->timeout.d0i3_entry_msg = 100; 98 } else { 99 vdev->timeout.boot = 1000; 100 vdev->timeout.jsm = 500; 101 vdev->timeout.tdr = 2000; 102 if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX) 103 vdev->timeout.autosuspend = 10; 104 else 105 vdev->timeout.autosuspend = 100; 106 vdev->timeout.d0i3_entry_msg = 5; 107 } 108 } 109 110 static void memory_ranges_init(struct ivpu_device *vdev) 111 { 112 if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX) { 113 ivpu_hw_range_init(&vdev->hw->ranges.global, 0x80000000, SZ_512M); 114 ivpu_hw_range_init(&vdev->hw->ranges.user, 0xc0000000, 255 * SZ_1M); 115 ivpu_hw_range_init(&vdev->hw->ranges.shave, 0x180000000, SZ_2G); 116 ivpu_hw_range_init(&vdev->hw->ranges.dma, 0x200000000, SZ_8G); 117 } else { 118 ivpu_hw_range_init(&vdev->hw->ranges.global, 0x80000000, SZ_512M); 119 ivpu_hw_range_init(&vdev->hw->ranges.user, 0x80000000, SZ_256M); 120 ivpu_hw_range_init(&vdev->hw->ranges.shave, 0x80000000 + SZ_256M, SZ_2G - SZ_256M); 121 ivpu_hw_range_init(&vdev->hw->ranges.dma, 0x200000000, SZ_8G); 122 } 123 } 124 125 static int wp_enable(struct ivpu_device *vdev) 126 { 127 return ivpu_hw_btrs_wp_drive(vdev, true); 128 } 129 130 static int wp_disable(struct ivpu_device *vdev) 131 { 132 return ivpu_hw_btrs_wp_drive(vdev, false); 133 } 134 135 int ivpu_hw_power_up(struct ivpu_device *vdev) 136 { 137 int ret; 138 139 if (IVPU_WA(wp0_during_power_up)) { 140 /* WP requests may fail when powering down, so issue WP 0 here */ 141 ret = wp_disable(vdev); 142 if (ret) 143 ivpu_warn(vdev, "Failed to disable workpoint: %d\n", ret); 144 } 145 146 ret = ivpu_hw_btrs_d0i3_disable(vdev); 147 if (ret) 148 ivpu_warn(vdev, "Failed to disable D0I3: %d\n", ret); 149 150 ret = wp_enable(vdev); 151 if (ret) { 152 ivpu_err(vdev, "Failed to enable workpoint: %d\n", ret); 153 return ret; 154 } 155 156 if (ivpu_hw_btrs_gen(vdev) >= IVPU_HW_BTRS_LNL) { 157 if (IVPU_WA(disable_clock_relinquish)) 158 ivpu_hw_btrs_clock_relinquish_disable_lnl(vdev); 159 ivpu_hw_btrs_profiling_freq_reg_set_lnl(vdev); 160 ivpu_hw_btrs_ats_print_lnl(vdev); 161 } 162 163 ret = ivpu_hw_ip_host_ss_configure(vdev); 164 if (ret) { 165 ivpu_err(vdev, "Failed to configure host SS: %d\n", ret); 166 return ret; 167 } 168 169 ivpu_hw_ip_idle_gen_disable(vdev); 170 171 ret = ivpu_hw_btrs_wait_for_clock_res_own_ack(vdev); 172 if (ret) { 173 ivpu_err(vdev, "Timed out waiting for clock resource own ACK\n"); 174 return ret; 175 } 176 177 ret = ivpu_hw_ip_pwr_domain_enable(vdev); 178 if (ret) { 179 ivpu_err(vdev, "Failed to enable power domain: %d\n", ret); 180 return ret; 181 } 182 183 ret = ivpu_hw_ip_host_ss_axi_enable(vdev); 184 if (ret) { 185 ivpu_err(vdev, "Failed to enable AXI: %d\n", ret); 186 return ret; 187 } 188 189 if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_LNL) 190 ivpu_hw_btrs_set_port_arbitration_weights_lnl(vdev); 191 192 ret = ivpu_hw_ip_top_noc_enable(vdev); 193 if (ret) 194 ivpu_err(vdev, "Failed to enable TOP NOC: %d\n", ret); 195 196 return ret; 197 } 198 199 static void save_d0i3_entry_timestamp(struct ivpu_device *vdev) 200 { 201 vdev->hw->d0i3_entry_host_ts = ktime_get_boottime(); 202 vdev->hw->d0i3_entry_vpu_ts = ivpu_hw_ip_read_perf_timer_counter(vdev); 203 } 204 205 int ivpu_hw_reset(struct ivpu_device *vdev) 206 { 207 int ret = 0; 208 209 if (ivpu_hw_btrs_ip_reset(vdev)) { 210 ivpu_err(vdev, "Failed to reset NPU IP\n"); 211 ret = -EIO; 212 } 213 214 if (wp_disable(vdev)) { 215 ivpu_err(vdev, "Failed to disable workpoint\n"); 216 ret = -EIO; 217 } 218 219 return ret; 220 } 221 222 int ivpu_hw_power_down(struct ivpu_device *vdev) 223 { 224 int ret = 0; 225 226 save_d0i3_entry_timestamp(vdev); 227 228 if (!ivpu_hw_is_idle(vdev)) 229 ivpu_warn(vdev, "NPU not idle during power down\n"); 230 231 if (ivpu_hw_reset(vdev)) { 232 ivpu_err(vdev, "Failed to reset NPU\n"); 233 ret = -EIO; 234 } 235 236 if (ivpu_hw_btrs_d0i3_enable(vdev)) { 237 ivpu_err(vdev, "Failed to enter D0I3\n"); 238 ret = -EIO; 239 } 240 241 return ret; 242 } 243 244 int ivpu_hw_init(struct ivpu_device *vdev) 245 { 246 ivpu_hw_btrs_info_init(vdev); 247 ivpu_hw_btrs_freq_ratios_init(vdev); 248 memory_ranges_init(vdev); 249 platform_init(vdev); 250 wa_init(vdev); 251 timeouts_init(vdev); 252 atomic_set(&vdev->hw->firewall_irq_counter, 0); 253 254 return 0; 255 } 256 257 int ivpu_hw_boot_fw(struct ivpu_device *vdev) 258 { 259 int ret; 260 261 ivpu_hw_ip_snoop_disable(vdev); 262 ivpu_hw_ip_tbu_mmu_enable(vdev); 263 ret = ivpu_hw_ip_soc_cpu_boot(vdev); 264 if (ret) 265 ivpu_err(vdev, "Failed to boot SOC CPU: %d\n", ret); 266 267 return ret; 268 } 269 270 void ivpu_hw_profiling_freq_drive(struct ivpu_device *vdev, bool enable) 271 { 272 if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX) { 273 vdev->hw->pll.profiling_freq = PLL_PROFILING_FREQ_DEFAULT; 274 return; 275 } 276 277 if (enable) 278 vdev->hw->pll.profiling_freq = PLL_PROFILING_FREQ_HIGH; 279 else 280 vdev->hw->pll.profiling_freq = PLL_PROFILING_FREQ_DEFAULT; 281 } 282 283 void ivpu_irq_handlers_init(struct ivpu_device *vdev) 284 { 285 INIT_KFIFO(vdev->hw->irq.fifo); 286 287 if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX) 288 vdev->hw->irq.ip_irq_handler = ivpu_hw_ip_irq_handler_37xx; 289 else 290 vdev->hw->irq.ip_irq_handler = ivpu_hw_ip_irq_handler_40xx; 291 292 if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL) 293 vdev->hw->irq.btrs_irq_handler = ivpu_hw_btrs_irq_handler_mtl; 294 else 295 vdev->hw->irq.btrs_irq_handler = ivpu_hw_btrs_irq_handler_lnl; 296 } 297 298 void ivpu_hw_irq_enable(struct ivpu_device *vdev) 299 { 300 kfifo_reset(&vdev->hw->irq.fifo); 301 ivpu_hw_ip_irq_enable(vdev); 302 ivpu_hw_btrs_irq_enable(vdev); 303 } 304 305 void ivpu_hw_irq_disable(struct ivpu_device *vdev) 306 { 307 ivpu_hw_btrs_irq_disable(vdev); 308 ivpu_hw_ip_irq_disable(vdev); 309 } 310 311 irqreturn_t ivpu_hw_irq_handler(int irq, void *ptr) 312 { 313 struct ivpu_device *vdev = ptr; 314 bool ip_handled, btrs_handled; 315 316 ivpu_hw_btrs_global_int_disable(vdev); 317 318 btrs_handled = ivpu_hw_btrs_irq_handler(vdev, irq); 319 if (!ivpu_hw_is_idle((vdev)) || !btrs_handled) 320 ip_handled = ivpu_hw_ip_irq_handler(vdev, irq); 321 else 322 ip_handled = false; 323 324 /* Re-enable global interrupts to re-trigger MSI for pending interrupts */ 325 ivpu_hw_btrs_global_int_enable(vdev); 326 327 if (!kfifo_is_empty(&vdev->hw->irq.fifo)) 328 return IRQ_WAKE_THREAD; 329 if (ip_handled || btrs_handled) 330 return IRQ_HANDLED; 331 return IRQ_NONE; 332 } 333