ivpu_hw_btrs.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2020-2025 Intel Corporation
  4. */
  5. #include <linux/units.h>
  6. #include "ivpu_drv.h"
  7. #include "ivpu_hw.h"
  8. #include "ivpu_hw_btrs.h"
  9. #include "ivpu_hw_btrs_lnl_reg.h"
  10. #include "ivpu_hw_btrs_mtl_reg.h"
  11. #include "ivpu_hw_reg_io.h"
  12. #include "ivpu_pm.h"
  13. #define BTRS_MTL_IRQ_MASK ((REG_FLD(VPU_HW_BTRS_MTL_INTERRUPT_STAT, ATS_ERR)) | \
  14. (REG_FLD(VPU_HW_BTRS_MTL_INTERRUPT_STAT, UFI_ERR)))
  15. #define BTRS_LNL_IRQ_MASK ((REG_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, ATS_ERR)) | \
  16. (REG_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, CFI0_ERR)) | \
  17. (REG_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, CFI1_ERR)) | \
  18. (REG_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, IMR0_ERR)) | \
  19. (REG_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, IMR1_ERR)) | \
  20. (REG_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, SURV_ERR)))
  21. #define BTRS_MTL_ALL_IRQ_MASK (BTRS_MTL_IRQ_MASK | (REG_FLD(VPU_HW_BTRS_MTL_INTERRUPT_STAT, \
  22. FREQ_CHANGE)))
  23. #define BTRS_IRQ_DISABLE_MASK ((u32)-1)
  24. #define BTRS_LNL_ALL_IRQ_MASK ((u32)-1)
  25. #define PLL_CDYN_DEFAULT 0x80
  26. #define PLL_EPP_DEFAULT 0x80
  27. #define PLL_REF_CLK_FREQ 50000000ull
  28. #define PLL_RATIO_TO_FREQ(x) ((x) * PLL_REF_CLK_FREQ)
  29. #define PLL_TIMEOUT_US (1500 * USEC_PER_MSEC)
  30. #define IDLE_TIMEOUT_US (5 * USEC_PER_MSEC)
  31. #define TIMEOUT_US (150 * USEC_PER_MSEC)
  32. /* Work point configuration values */
  33. #define WP_CONFIG(tile, ratio) (((tile) << 8) | (ratio))
  34. #define MTL_CONFIG_1_TILE 0x01
  35. #define MTL_CONFIG_2_TILE 0x02
  36. #define MTL_PLL_RATIO_5_3 0x01
  37. #define MTL_PLL_RATIO_4_3 0x02
  38. #define BTRS_MTL_TILE_FUSE_ENABLE_BOTH 0x0
  39. #define BTRS_MTL_TILE_SKU_BOTH 0x3630
  40. #define BTRS_LNL_TILE_MAX_NUM 6
  41. #define BTRS_LNL_TILE_MAX_MASK 0x3f
  42. #define WEIGHTS_DEFAULT 0xf711f711u
  43. #define WEIGHTS_ATS_DEFAULT 0x0000f711u
  44. #define DCT_REQ 0x2
  45. #define DCT_ENABLE 0x1
  46. #define DCT_DISABLE 0x0
  47. static u32 pll_ratio_to_dpu_freq(struct ivpu_device *vdev, u32 ratio);
  48. int ivpu_hw_btrs_irqs_clear_with_0_mtl(struct ivpu_device *vdev)
  49. {
  50. REGB_WR32(VPU_HW_BTRS_MTL_INTERRUPT_STAT, BTRS_MTL_ALL_IRQ_MASK);
  51. if (REGB_RD32(VPU_HW_BTRS_MTL_INTERRUPT_STAT) == BTRS_MTL_ALL_IRQ_MASK) {
  52. /* Writing 1s does not clear the interrupt status register */
  53. REGB_WR32(VPU_HW_BTRS_MTL_INTERRUPT_STAT, 0x0);
  54. return true;
  55. }
  56. return false;
  57. }
  58. static void freq_ratios_init_mtl(struct ivpu_device *vdev)
  59. {
  60. struct ivpu_hw_info *hw = vdev->hw;
  61. u32 fmin_fuse, fmax_fuse;
  62. fmin_fuse = REGB_RD32(VPU_HW_BTRS_MTL_FMIN_FUSE);
  63. hw->pll.min_ratio = REG_GET_FLD(VPU_HW_BTRS_MTL_FMIN_FUSE, MIN_RATIO, fmin_fuse);
  64. hw->pll.pn_ratio = REG_GET_FLD(VPU_HW_BTRS_MTL_FMIN_FUSE, PN_RATIO, fmin_fuse);
  65. fmax_fuse = REGB_RD32(VPU_HW_BTRS_MTL_FMAX_FUSE);
  66. hw->pll.max_ratio = REG_GET_FLD(VPU_HW_BTRS_MTL_FMAX_FUSE, MAX_RATIO, fmax_fuse);
  67. }
  68. static void freq_ratios_init_lnl(struct ivpu_device *vdev)
  69. {
  70. struct ivpu_hw_info *hw = vdev->hw;
  71. u32 fmin_fuse, fmax_fuse;
  72. fmin_fuse = REGB_RD32(VPU_HW_BTRS_LNL_FMIN_FUSE);
  73. hw->pll.min_ratio = REG_GET_FLD(VPU_HW_BTRS_LNL_FMIN_FUSE, MIN_RATIO, fmin_fuse);
  74. hw->pll.pn_ratio = REG_GET_FLD(VPU_HW_BTRS_LNL_FMIN_FUSE, PN_RATIO, fmin_fuse);
  75. fmax_fuse = REGB_RD32(VPU_HW_BTRS_LNL_FMAX_FUSE);
  76. hw->pll.max_ratio = REG_GET_FLD(VPU_HW_BTRS_LNL_FMAX_FUSE, MAX_RATIO, fmax_fuse);
  77. }
  78. void ivpu_hw_btrs_freq_ratios_init(struct ivpu_device *vdev)
  79. {
  80. struct ivpu_hw_info *hw = vdev->hw;
  81. if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
  82. freq_ratios_init_mtl(vdev);
  83. else
  84. freq_ratios_init_lnl(vdev);
  85. hw->pll.min_ratio = clamp_t(u8, ivpu_pll_min_ratio, hw->pll.min_ratio, hw->pll.max_ratio);
  86. hw->pll.max_ratio = clamp_t(u8, ivpu_pll_max_ratio, hw->pll.min_ratio, hw->pll.max_ratio);
  87. hw->pll.pn_ratio = clamp_t(u8, hw->pll.pn_ratio, hw->pll.min_ratio, hw->pll.max_ratio);
  88. }
  89. static bool tile_disable_check(u32 config)
  90. {
  91. /* Allowed values: 0 or one bit from range 0-5 (6 tiles) */
  92. if (config == 0)
  93. return true;
  94. if (config > BIT(BTRS_LNL_TILE_MAX_NUM - 1))
  95. return false;
  96. if ((config & (config - 1)) == 0)
  97. return true;
  98. return false;
  99. }
  100. static int read_tile_config_fuse(struct ivpu_device *vdev, u32 *tile_fuse_config)
  101. {
  102. u32 fuse;
  103. u32 config;
  104. fuse = REGB_RD32(VPU_HW_BTRS_LNL_TILE_FUSE);
  105. if (!REG_TEST_FLD(VPU_HW_BTRS_LNL_TILE_FUSE, VALID, fuse)) {
  106. ivpu_err(vdev, "Fuse: invalid (0x%x)\n", fuse);
  107. return -EIO;
  108. }
  109. config = REG_GET_FLD(VPU_HW_BTRS_LNL_TILE_FUSE, CONFIG, fuse);
  110. if (!tile_disable_check(config))
  111. ivpu_warn(vdev, "More than 1 tile disabled, tile fuse config mask: 0x%x\n", config);
  112. ivpu_dbg(vdev, MISC, "Tile disable config mask: 0x%x\n", config);
  113. *tile_fuse_config = config;
  114. return 0;
  115. }
  116. static int info_init_mtl(struct ivpu_device *vdev)
  117. {
  118. struct ivpu_hw_info *hw = vdev->hw;
  119. hw->tile_fuse = BTRS_MTL_TILE_FUSE_ENABLE_BOTH;
  120. hw->sku = BTRS_MTL_TILE_SKU_BOTH;
  121. hw->config = WP_CONFIG(MTL_CONFIG_2_TILE, MTL_PLL_RATIO_4_3);
  122. return 0;
  123. }
  124. static int info_init_lnl(struct ivpu_device *vdev)
  125. {
  126. struct ivpu_hw_info *hw = vdev->hw;
  127. u32 tile_fuse_config;
  128. int ret;
  129. ret = read_tile_config_fuse(vdev, &tile_fuse_config);
  130. if (ret)
  131. return ret;
  132. hw->tile_fuse = tile_fuse_config;
  133. hw->pll.profiling_freq = PLL_PROFILING_FREQ_DEFAULT;
  134. return 0;
  135. }
  136. int ivpu_hw_btrs_info_init(struct ivpu_device *vdev)
  137. {
  138. if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
  139. return info_init_mtl(vdev);
  140. else
  141. return info_init_lnl(vdev);
  142. }
  143. static int wp_request_sync(struct ivpu_device *vdev)
  144. {
  145. if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
  146. return REGB_POLL_FLD(VPU_HW_BTRS_MTL_WP_REQ_CMD, SEND, 0, PLL_TIMEOUT_US);
  147. else
  148. return REGB_POLL_FLD(VPU_HW_BTRS_LNL_WP_REQ_CMD, SEND, 0, PLL_TIMEOUT_US);
  149. }
  150. static int wait_for_status_ready(struct ivpu_device *vdev, bool enable)
  151. {
  152. u32 exp_val = enable ? 0x1 : 0x0;
  153. if (IVPU_WA(punit_disabled))
  154. return 0;
  155. if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
  156. return REGB_POLL_FLD(VPU_HW_BTRS_MTL_VPU_STATUS, READY, exp_val, PLL_TIMEOUT_US);
  157. else
  158. return REGB_POLL_FLD(VPU_HW_BTRS_LNL_VPU_STATUS, READY, exp_val, PLL_TIMEOUT_US);
  159. }
  160. struct wp_request {
  161. u16 min;
  162. u16 max;
  163. u16 target;
  164. u16 cfg;
  165. u16 epp;
  166. u16 cdyn;
  167. };
  168. static void wp_request_mtl(struct ivpu_device *vdev, struct wp_request *wp)
  169. {
  170. u32 val;
  171. val = REGB_RD32(VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD0);
  172. val = REG_SET_FLD_NUM(VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD0, MIN_RATIO, wp->min, val);
  173. val = REG_SET_FLD_NUM(VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD0, MAX_RATIO, wp->max, val);
  174. REGB_WR32(VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD0, val);
  175. val = REGB_RD32(VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD1);
  176. val = REG_SET_FLD_NUM(VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD1, TARGET_RATIO, wp->target, val);
  177. val = REG_SET_FLD_NUM(VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD1, EPP, PLL_EPP_DEFAULT, val);
  178. REGB_WR32(VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD1, val);
  179. val = REGB_RD32(VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD2);
  180. val = REG_SET_FLD_NUM(VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD2, CONFIG, wp->cfg, val);
  181. REGB_WR32(VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD2, val);
  182. val = REGB_RD32(VPU_HW_BTRS_MTL_WP_REQ_CMD);
  183. val = REG_SET_FLD(VPU_HW_BTRS_MTL_WP_REQ_CMD, SEND, val);
  184. REGB_WR32(VPU_HW_BTRS_MTL_WP_REQ_CMD, val);
  185. }
  186. static void wp_request_lnl(struct ivpu_device *vdev, struct wp_request *wp)
  187. {
  188. u32 val;
  189. val = REGB_RD32(VPU_HW_BTRS_LNL_WP_REQ_PAYLOAD0);
  190. val = REG_SET_FLD_NUM(VPU_HW_BTRS_LNL_WP_REQ_PAYLOAD0, MIN_RATIO, wp->min, val);
  191. val = REG_SET_FLD_NUM(VPU_HW_BTRS_LNL_WP_REQ_PAYLOAD0, MAX_RATIO, wp->max, val);
  192. REGB_WR32(VPU_HW_BTRS_LNL_WP_REQ_PAYLOAD0, val);
  193. val = REGB_RD32(VPU_HW_BTRS_LNL_WP_REQ_PAYLOAD1);
  194. val = REG_SET_FLD_NUM(VPU_HW_BTRS_LNL_WP_REQ_PAYLOAD1, TARGET_RATIO, wp->target, val);
  195. val = REG_SET_FLD_NUM(VPU_HW_BTRS_LNL_WP_REQ_PAYLOAD1, EPP, wp->epp, val);
  196. REGB_WR32(VPU_HW_BTRS_LNL_WP_REQ_PAYLOAD1, val);
  197. val = REGB_RD32(VPU_HW_BTRS_LNL_WP_REQ_PAYLOAD2);
  198. val = REG_SET_FLD_NUM(VPU_HW_BTRS_LNL_WP_REQ_PAYLOAD2, CONFIG, wp->cfg, val);
  199. val = REG_SET_FLD_NUM(VPU_HW_BTRS_LNL_WP_REQ_PAYLOAD2, CDYN, wp->cdyn, val);
  200. REGB_WR32(VPU_HW_BTRS_LNL_WP_REQ_PAYLOAD2, val);
  201. val = REGB_RD32(VPU_HW_BTRS_LNL_WP_REQ_CMD);
  202. val = REG_SET_FLD(VPU_HW_BTRS_LNL_WP_REQ_CMD, SEND, val);
  203. REGB_WR32(VPU_HW_BTRS_LNL_WP_REQ_CMD, val);
  204. }
  205. static void wp_request(struct ivpu_device *vdev, struct wp_request *wp)
  206. {
  207. if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
  208. wp_request_mtl(vdev, wp);
  209. else
  210. wp_request_lnl(vdev, wp);
  211. }
  212. static int wp_request_send(struct ivpu_device *vdev, struct wp_request *wp)
  213. {
  214. int ret;
  215. ret = wp_request_sync(vdev);
  216. if (ret) {
  217. ivpu_err(vdev, "Failed to sync before workpoint request: %d\n", ret);
  218. return ret;
  219. }
  220. wp_request(vdev, wp);
  221. ret = wp_request_sync(vdev);
  222. if (ret)
  223. ivpu_err(vdev, "Failed to sync after workpoint request: %d\n", ret);
  224. return ret;
  225. }
  226. static void prepare_wp_request(struct ivpu_device *vdev, struct wp_request *wp, bool enable)
  227. {
  228. struct ivpu_hw_info *hw = vdev->hw;
  229. wp->min = hw->pll.min_ratio;
  230. wp->max = hw->pll.max_ratio;
  231. if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL) {
  232. wp->target = enable ? hw->pll.pn_ratio : 0;
  233. wp->cfg = enable ? hw->config : 0;
  234. wp->cdyn = 0;
  235. wp->epp = 0;
  236. } else {
  237. wp->target = hw->pll.pn_ratio;
  238. wp->cfg = 0;
  239. wp->cdyn = enable ? PLL_CDYN_DEFAULT : 0;
  240. wp->epp = enable ? PLL_EPP_DEFAULT : 0;
  241. }
  242. }
  243. static int wait_for_pll_lock(struct ivpu_device *vdev, bool enable)
  244. {
  245. u32 exp_val = enable ? 0x1 : 0x0;
  246. if (ivpu_hw_btrs_gen(vdev) != IVPU_HW_BTRS_MTL)
  247. return 0;
  248. if (IVPU_WA(punit_disabled))
  249. return 0;
  250. return REGB_POLL_FLD(VPU_HW_BTRS_MTL_PLL_STATUS, LOCK, exp_val, PLL_TIMEOUT_US);
  251. }
  252. static int wait_for_cdyn_deassert(struct ivpu_device *vdev)
  253. {
  254. if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
  255. return 0;
  256. return REGB_POLL_FLD(VPU_HW_BTRS_LNL_CDYN, CDYN, 0, PLL_TIMEOUT_US);
  257. }
  258. int ivpu_hw_btrs_wp_drive(struct ivpu_device *vdev, bool enable)
  259. {
  260. struct wp_request wp;
  261. int ret;
  262. if (IVPU_WA(punit_disabled)) {
  263. ivpu_dbg(vdev, PM, "Skipping workpoint request\n");
  264. return 0;
  265. }
  266. prepare_wp_request(vdev, &wp, enable);
  267. ivpu_dbg(vdev, PM, "PLL workpoint request: %lu MHz, config: 0x%x, epp: 0x%x, cdyn: 0x%x\n",
  268. pll_ratio_to_dpu_freq(vdev, wp.target) / HZ_PER_MHZ, wp.cfg, wp.epp, wp.cdyn);
  269. ret = wp_request_send(vdev, &wp);
  270. if (ret) {
  271. ivpu_err(vdev, "Failed to send workpoint request: %d\n", ret);
  272. return ret;
  273. }
  274. ret = wait_for_pll_lock(vdev, enable);
  275. if (ret) {
  276. ivpu_err(vdev, "Timed out waiting for PLL lock\n");
  277. return ret;
  278. }
  279. ret = wait_for_status_ready(vdev, enable);
  280. if (ret) {
  281. ivpu_err(vdev, "Timed out waiting for NPU ready status\n");
  282. return ret;
  283. }
  284. if (!enable) {
  285. ret = wait_for_cdyn_deassert(vdev);
  286. if (ret) {
  287. ivpu_err(vdev, "Timed out waiting for CDYN deassert\n");
  288. return ret;
  289. }
  290. }
  291. return 0;
  292. }
  293. static int d0i3_drive_mtl(struct ivpu_device *vdev, bool enable)
  294. {
  295. int ret;
  296. u32 val;
  297. ret = REGB_POLL_FLD(VPU_HW_BTRS_MTL_VPU_D0I3_CONTROL, INPROGRESS, 0, TIMEOUT_US);
  298. if (ret) {
  299. ivpu_err(vdev, "Failed to sync before D0i3 transition: %d\n", ret);
  300. return ret;
  301. }
  302. val = REGB_RD32(VPU_HW_BTRS_MTL_VPU_D0I3_CONTROL);
  303. if (enable)
  304. val = REG_SET_FLD(VPU_HW_BTRS_MTL_VPU_D0I3_CONTROL, I3, val);
  305. else
  306. val = REG_CLR_FLD(VPU_HW_BTRS_MTL_VPU_D0I3_CONTROL, I3, val);
  307. REGB_WR32(VPU_HW_BTRS_MTL_VPU_D0I3_CONTROL, val);
  308. ret = REGB_POLL_FLD(VPU_HW_BTRS_MTL_VPU_D0I3_CONTROL, INPROGRESS, 0, TIMEOUT_US);
  309. if (ret)
  310. ivpu_err(vdev, "Failed to sync after D0i3 transition: %d\n", ret);
  311. return ret;
  312. }
  313. static int d0i3_drive_lnl(struct ivpu_device *vdev, bool enable)
  314. {
  315. int ret;
  316. u32 val;
  317. ret = REGB_POLL_FLD(VPU_HW_BTRS_LNL_D0I3_CONTROL, INPROGRESS, 0, TIMEOUT_US);
  318. if (ret) {
  319. ivpu_err(vdev, "Failed to sync before D0i3 transition: %d\n", ret);
  320. return ret;
  321. }
  322. val = REGB_RD32(VPU_HW_BTRS_LNL_D0I3_CONTROL);
  323. if (enable)
  324. val = REG_SET_FLD(VPU_HW_BTRS_LNL_D0I3_CONTROL, I3, val);
  325. else
  326. val = REG_CLR_FLD(VPU_HW_BTRS_LNL_D0I3_CONTROL, I3, val);
  327. REGB_WR32(VPU_HW_BTRS_LNL_D0I3_CONTROL, val);
  328. ret = REGB_POLL_FLD(VPU_HW_BTRS_LNL_D0I3_CONTROL, INPROGRESS, 0, TIMEOUT_US);
  329. if (ret) {
  330. ivpu_err(vdev, "Failed to sync after D0i3 transition: %d\n", ret);
  331. return ret;
  332. }
  333. return 0;
  334. }
  335. static int d0i3_drive(struct ivpu_device *vdev, bool enable)
  336. {
  337. if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
  338. return d0i3_drive_mtl(vdev, enable);
  339. else
  340. return d0i3_drive_lnl(vdev, enable);
  341. }
  342. int ivpu_hw_btrs_d0i3_enable(struct ivpu_device *vdev)
  343. {
  344. int ret;
  345. if (IVPU_WA(punit_disabled))
  346. return 0;
  347. ret = d0i3_drive(vdev, true);
  348. if (ret)
  349. ivpu_err(vdev, "Failed to enable D0i3: %d\n", ret);
  350. udelay(5); /* VPU requires 5 us to complete the transition */
  351. return ret;
  352. }
  353. int ivpu_hw_btrs_d0i3_disable(struct ivpu_device *vdev)
  354. {
  355. int ret;
  356. if (IVPU_WA(punit_disabled))
  357. return 0;
  358. ret = d0i3_drive(vdev, false);
  359. if (ret)
  360. ivpu_err(vdev, "Failed to disable D0i3: %d\n", ret);
  361. return ret;
  362. }
  363. int ivpu_hw_btrs_wait_for_clock_res_own_ack(struct ivpu_device *vdev)
  364. {
  365. if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
  366. return 0;
  367. return REGB_POLL_FLD(VPU_HW_BTRS_LNL_VPU_STATUS, CLOCK_RESOURCE_OWN_ACK, 1, TIMEOUT_US);
  368. }
  369. void ivpu_hw_btrs_set_port_arbitration_weights_lnl(struct ivpu_device *vdev)
  370. {
  371. REGB_WR32(VPU_HW_BTRS_LNL_PORT_ARBITRATION_WEIGHTS, WEIGHTS_DEFAULT);
  372. REGB_WR32(VPU_HW_BTRS_LNL_PORT_ARBITRATION_WEIGHTS_ATS, WEIGHTS_ATS_DEFAULT);
  373. }
  374. static int ip_reset_mtl(struct ivpu_device *vdev)
  375. {
  376. int ret;
  377. u32 val;
  378. ret = REGB_POLL_FLD(VPU_HW_BTRS_MTL_VPU_IP_RESET, TRIGGER, 0, TIMEOUT_US);
  379. if (ret) {
  380. ivpu_err(vdev, "Timed out waiting for TRIGGER bit\n");
  381. return ret;
  382. }
  383. val = REGB_RD32(VPU_HW_BTRS_MTL_VPU_IP_RESET);
  384. val = REG_SET_FLD(VPU_HW_BTRS_MTL_VPU_IP_RESET, TRIGGER, val);
  385. REGB_WR32(VPU_HW_BTRS_MTL_VPU_IP_RESET, val);
  386. ret = REGB_POLL_FLD(VPU_HW_BTRS_MTL_VPU_IP_RESET, TRIGGER, 0, TIMEOUT_US);
  387. if (ret)
  388. ivpu_err(vdev, "Timed out waiting for RESET completion\n");
  389. return ret;
  390. }
  391. static int ip_reset_lnl(struct ivpu_device *vdev)
  392. {
  393. int ret;
  394. u32 val;
  395. ivpu_hw_btrs_clock_relinquish_disable_lnl(vdev);
  396. ret = REGB_POLL_FLD(VPU_HW_BTRS_LNL_IP_RESET, TRIGGER, 0, TIMEOUT_US);
  397. if (ret) {
  398. ivpu_err(vdev, "Wait for *_TRIGGER timed out\n");
  399. return ret;
  400. }
  401. val = REGB_RD32(VPU_HW_BTRS_LNL_IP_RESET);
  402. val = REG_SET_FLD(VPU_HW_BTRS_LNL_IP_RESET, TRIGGER, val);
  403. REGB_WR32(VPU_HW_BTRS_LNL_IP_RESET, val);
  404. ret = REGB_POLL_FLD(VPU_HW_BTRS_LNL_IP_RESET, TRIGGER, 0, TIMEOUT_US);
  405. if (ret)
  406. ivpu_err(vdev, "Timed out waiting for RESET completion\n");
  407. return ret;
  408. }
  409. int ivpu_hw_btrs_ip_reset(struct ivpu_device *vdev)
  410. {
  411. if (IVPU_WA(punit_disabled))
  412. return 0;
  413. if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
  414. return ip_reset_mtl(vdev);
  415. else
  416. return ip_reset_lnl(vdev);
  417. }
  418. void ivpu_hw_btrs_profiling_freq_reg_set_lnl(struct ivpu_device *vdev)
  419. {
  420. u32 val = REGB_RD32(VPU_HW_BTRS_LNL_VPU_STATUS);
  421. if (vdev->hw->pll.profiling_freq == PLL_PROFILING_FREQ_DEFAULT)
  422. val = REG_CLR_FLD(VPU_HW_BTRS_LNL_VPU_STATUS, PERF_CLK, val);
  423. else
  424. val = REG_SET_FLD(VPU_HW_BTRS_LNL_VPU_STATUS, PERF_CLK, val);
  425. REGB_WR32(VPU_HW_BTRS_LNL_VPU_STATUS, val);
  426. }
  427. void ivpu_hw_btrs_ats_print_lnl(struct ivpu_device *vdev)
  428. {
  429. ivpu_dbg(vdev, MISC, "Buttress ATS: %s\n",
  430. REGB_RD32(VPU_HW_BTRS_LNL_HM_ATS) ? "Enable" : "Disable");
  431. }
  432. void ivpu_hw_btrs_clock_relinquish_disable_lnl(struct ivpu_device *vdev)
  433. {
  434. u32 val = REGB_RD32(VPU_HW_BTRS_LNL_VPU_STATUS);
  435. val = REG_SET_FLD(VPU_HW_BTRS_LNL_VPU_STATUS, DISABLE_CLK_RELINQUISH, val);
  436. REGB_WR32(VPU_HW_BTRS_LNL_VPU_STATUS, val);
  437. }
  438. bool ivpu_hw_btrs_is_idle(struct ivpu_device *vdev)
  439. {
  440. u32 val;
  441. if (IVPU_WA(punit_disabled))
  442. return true;
  443. if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL) {
  444. val = REGB_RD32(VPU_HW_BTRS_MTL_VPU_STATUS);
  445. return REG_TEST_FLD(VPU_HW_BTRS_MTL_VPU_STATUS, READY, val) &&
  446. REG_TEST_FLD(VPU_HW_BTRS_MTL_VPU_STATUS, IDLE, val);
  447. } else {
  448. val = REGB_RD32(VPU_HW_BTRS_LNL_VPU_STATUS);
  449. return REG_TEST_FLD(VPU_HW_BTRS_LNL_VPU_STATUS, READY, val) &&
  450. REG_TEST_FLD(VPU_HW_BTRS_LNL_VPU_STATUS, IDLE, val);
  451. }
  452. }
  453. int ivpu_hw_btrs_wait_for_idle(struct ivpu_device *vdev)
  454. {
  455. if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
  456. return REGB_POLL_FLD(VPU_HW_BTRS_MTL_VPU_STATUS, IDLE, 0x1, IDLE_TIMEOUT_US);
  457. else
  458. return REGB_POLL_FLD(VPU_HW_BTRS_LNL_VPU_STATUS, IDLE, 0x1, IDLE_TIMEOUT_US);
  459. }
  460. static u32 pll_config_get_mtl(struct ivpu_device *vdev)
  461. {
  462. return REGB_RD32(VPU_HW_BTRS_MTL_CURRENT_PLL);
  463. }
  464. static u32 pll_config_get_lnl(struct ivpu_device *vdev)
  465. {
  466. return REGB_RD32(VPU_HW_BTRS_LNL_PLL_FREQ);
  467. }
  468. static u32 pll_ratio_to_dpu_freq_mtl(u16 ratio)
  469. {
  470. return (PLL_RATIO_TO_FREQ(ratio) * 2) / 3;
  471. }
  472. static u32 pll_ratio_to_dpu_freq_lnl(u16 ratio)
  473. {
  474. return PLL_RATIO_TO_FREQ(ratio) / 2;
  475. }
  476. static u32 pll_ratio_to_dpu_freq(struct ivpu_device *vdev, u32 ratio)
  477. {
  478. if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
  479. return pll_ratio_to_dpu_freq_mtl(ratio);
  480. else
  481. return pll_ratio_to_dpu_freq_lnl(ratio);
  482. }
  483. u32 ivpu_hw_btrs_dpu_max_freq_get(struct ivpu_device *vdev)
  484. {
  485. return pll_ratio_to_dpu_freq(vdev, vdev->hw->pll.max_ratio);
  486. }
  487. u32 ivpu_hw_btrs_dpu_freq_get(struct ivpu_device *vdev)
  488. {
  489. if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
  490. return pll_ratio_to_dpu_freq_mtl(pll_config_get_mtl(vdev));
  491. else
  492. return pll_ratio_to_dpu_freq_lnl(pll_config_get_lnl(vdev));
  493. }
  494. /* Handler for IRQs from Buttress core (irqB) */
  495. bool ivpu_hw_btrs_irq_handler_mtl(struct ivpu_device *vdev, int irq)
  496. {
  497. u32 status = REGB_RD32(VPU_HW_BTRS_MTL_INTERRUPT_STAT) & BTRS_MTL_IRQ_MASK;
  498. bool schedule_recovery = false;
  499. if (!status)
  500. return false;
  501. if (REG_TEST_FLD(VPU_HW_BTRS_MTL_INTERRUPT_STAT, FREQ_CHANGE, status)) {
  502. u32 pll = pll_config_get_mtl(vdev);
  503. ivpu_dbg(vdev, IRQ, "FREQ_CHANGE irq, wp %08x, %lu MHz",
  504. pll, pll_ratio_to_dpu_freq_mtl(pll) / HZ_PER_MHZ);
  505. }
  506. if (REG_TEST_FLD(VPU_HW_BTRS_MTL_INTERRUPT_STAT, ATS_ERR, status)) {
  507. ivpu_err(vdev, "ATS_ERR irq 0x%016llx", REGB_RD64(VPU_HW_BTRS_MTL_ATS_ERR_LOG_0));
  508. REGB_WR32(VPU_HW_BTRS_MTL_ATS_ERR_CLEAR, 0x1);
  509. schedule_recovery = true;
  510. }
  511. if (REG_TEST_FLD(VPU_HW_BTRS_MTL_INTERRUPT_STAT, UFI_ERR, status)) {
  512. u32 ufi_log = REGB_RD32(VPU_HW_BTRS_MTL_UFI_ERR_LOG);
  513. ivpu_err(vdev, "UFI_ERR irq (0x%08x) opcode: 0x%02lx axi_id: 0x%02lx cq_id: 0x%03lx",
  514. ufi_log, REG_GET_FLD(VPU_HW_BTRS_MTL_UFI_ERR_LOG, OPCODE, ufi_log),
  515. REG_GET_FLD(VPU_HW_BTRS_MTL_UFI_ERR_LOG, AXI_ID, ufi_log),
  516. REG_GET_FLD(VPU_HW_BTRS_MTL_UFI_ERR_LOG, CQ_ID, ufi_log));
  517. REGB_WR32(VPU_HW_BTRS_MTL_UFI_ERR_CLEAR, 0x1);
  518. schedule_recovery = true;
  519. }
  520. /* This must be done after interrupts are cleared at the source. */
  521. if (IVPU_WA(interrupt_clear_with_0))
  522. /*
  523. * Writing 1 triggers an interrupt, so we can't perform read update write.
  524. * Clear local interrupt status by writing 0 to all bits.
  525. */
  526. REGB_WR32(VPU_HW_BTRS_MTL_INTERRUPT_STAT, 0x0);
  527. else
  528. REGB_WR32(VPU_HW_BTRS_MTL_INTERRUPT_STAT, status);
  529. if (schedule_recovery)
  530. ivpu_pm_trigger_recovery(vdev, "Buttress IRQ");
  531. return true;
  532. }
  533. /* Handler for IRQs from Buttress core (irqB) */
  534. bool ivpu_hw_btrs_irq_handler_lnl(struct ivpu_device *vdev, int irq)
  535. {
  536. u32 status = REGB_RD32(VPU_HW_BTRS_LNL_INTERRUPT_STAT) & BTRS_LNL_IRQ_MASK;
  537. bool schedule_recovery = false;
  538. if (!status)
  539. return false;
  540. if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, SURV_ERR, status)) {
  541. ivpu_dbg(vdev, IRQ, "Survivability IRQ\n");
  542. queue_work(system_percpu_wq, &vdev->irq_dct_work);
  543. }
  544. if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, FREQ_CHANGE, status)) {
  545. u32 pll = pll_config_get_lnl(vdev);
  546. ivpu_dbg(vdev, IRQ, "FREQ_CHANGE irq, wp %08x, %lu MHz",
  547. pll, pll_ratio_to_dpu_freq_lnl(pll) / HZ_PER_MHZ);
  548. }
  549. if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, ATS_ERR, status)) {
  550. ivpu_err(vdev, "ATS_ERR LOG1 0x%08x ATS_ERR_LOG2 0x%08x\n",
  551. REGB_RD32(VPU_HW_BTRS_LNL_ATS_ERR_LOG1),
  552. REGB_RD32(VPU_HW_BTRS_LNL_ATS_ERR_LOG2));
  553. REGB_WR32(VPU_HW_BTRS_LNL_ATS_ERR_CLEAR, 0x1);
  554. schedule_recovery = true;
  555. }
  556. if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, CFI0_ERR, status)) {
  557. ivpu_err(vdev, "CFI0_ERR 0x%08x", REGB_RD32(VPU_HW_BTRS_LNL_CFI0_ERR_LOG));
  558. REGB_WR32(VPU_HW_BTRS_LNL_CFI0_ERR_CLEAR, 0x1);
  559. schedule_recovery = true;
  560. }
  561. if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, CFI1_ERR, status)) {
  562. ivpu_err(vdev, "CFI1_ERR 0x%08x", REGB_RD32(VPU_HW_BTRS_LNL_CFI1_ERR_LOG));
  563. REGB_WR32(VPU_HW_BTRS_LNL_CFI1_ERR_CLEAR, 0x1);
  564. schedule_recovery = true;
  565. }
  566. if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, IMR0_ERR, status)) {
  567. ivpu_err(vdev, "IMR_ERR_CFI0 LOW: 0x%08x HIGH: 0x%08x",
  568. REGB_RD32(VPU_HW_BTRS_LNL_IMR_ERR_CFI0_LOW),
  569. REGB_RD32(VPU_HW_BTRS_LNL_IMR_ERR_CFI0_HIGH));
  570. REGB_WR32(VPU_HW_BTRS_LNL_IMR_ERR_CFI0_CLEAR, 0x1);
  571. schedule_recovery = true;
  572. }
  573. if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, IMR1_ERR, status)) {
  574. ivpu_err(vdev, "IMR_ERR_CFI1 LOW: 0x%08x HIGH: 0x%08x",
  575. REGB_RD32(VPU_HW_BTRS_LNL_IMR_ERR_CFI1_LOW),
  576. REGB_RD32(VPU_HW_BTRS_LNL_IMR_ERR_CFI1_HIGH));
  577. REGB_WR32(VPU_HW_BTRS_LNL_IMR_ERR_CFI1_CLEAR, 0x1);
  578. schedule_recovery = true;
  579. }
  580. /* This must be done after interrupts are cleared at the source. */
  581. REGB_WR32(VPU_HW_BTRS_LNL_INTERRUPT_STAT, status);
  582. if (schedule_recovery)
  583. ivpu_pm_trigger_recovery(vdev, "Buttress IRQ");
  584. return true;
  585. }
  586. int ivpu_hw_btrs_dct_get_request(struct ivpu_device *vdev, bool *enable)
  587. {
  588. u32 val = REGB_RD32(VPU_HW_BTRS_LNL_PCODE_MAILBOX_SHADOW);
  589. u32 cmd = REG_GET_FLD(VPU_HW_BTRS_LNL_PCODE_MAILBOX_SHADOW, CMD, val);
  590. u32 param1 = REG_GET_FLD(VPU_HW_BTRS_LNL_PCODE_MAILBOX_SHADOW, PARAM1, val);
  591. if (cmd != DCT_REQ) {
  592. ivpu_err_ratelimited(vdev, "Unsupported PCODE command: 0x%x\n", cmd);
  593. return -EBADR;
  594. }
  595. switch (param1) {
  596. case DCT_ENABLE:
  597. *enable = true;
  598. return 0;
  599. case DCT_DISABLE:
  600. *enable = false;
  601. return 0;
  602. default:
  603. ivpu_err_ratelimited(vdev, "Invalid PARAM1 value: %u\n", param1);
  604. return -EINVAL;
  605. }
  606. }
  607. void ivpu_hw_btrs_dct_set_status(struct ivpu_device *vdev, bool enable, u8 active_percent)
  608. {
  609. u32 val = 0;
  610. u32 cmd = enable ? DCT_ENABLE : DCT_DISABLE;
  611. val = REG_SET_FLD_NUM(VPU_HW_BTRS_LNL_PCODE_MAILBOX_STATUS, CMD, DCT_REQ, val);
  612. val = REG_SET_FLD_NUM(VPU_HW_BTRS_LNL_PCODE_MAILBOX_STATUS, PARAM1, cmd, val);
  613. val = REG_SET_FLD_NUM(VPU_HW_BTRS_LNL_PCODE_MAILBOX_STATUS, PARAM2, active_percent, val);
  614. REGB_WR32(VPU_HW_BTRS_LNL_PCODE_MAILBOX_STATUS, val);
  615. }
  616. u32 ivpu_hw_btrs_telemetry_offset_get(struct ivpu_device *vdev)
  617. {
  618. if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
  619. return REGB_RD32(VPU_HW_BTRS_MTL_VPU_TELEMETRY_OFFSET);
  620. else
  621. return REGB_RD32(VPU_HW_BTRS_LNL_VPU_TELEMETRY_OFFSET);
  622. }
  623. u32 ivpu_hw_btrs_telemetry_size_get(struct ivpu_device *vdev)
  624. {
  625. if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
  626. return REGB_RD32(VPU_HW_BTRS_MTL_VPU_TELEMETRY_SIZE);
  627. else
  628. return REGB_RD32(VPU_HW_BTRS_LNL_VPU_TELEMETRY_SIZE);
  629. }
  630. u32 ivpu_hw_btrs_telemetry_enable_get(struct ivpu_device *vdev)
  631. {
  632. if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
  633. return REGB_RD32(VPU_HW_BTRS_MTL_VPU_TELEMETRY_ENABLE);
  634. else
  635. return REGB_RD32(VPU_HW_BTRS_LNL_VPU_TELEMETRY_ENABLE);
  636. }
  637. void ivpu_hw_btrs_global_int_disable(struct ivpu_device *vdev)
  638. {
  639. if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
  640. REGB_WR32(VPU_HW_BTRS_MTL_GLOBAL_INT_MASK, 0x1);
  641. else
  642. REGB_WR32(VPU_HW_BTRS_LNL_GLOBAL_INT_MASK, 0x1);
  643. }
  644. void ivpu_hw_btrs_global_int_enable(struct ivpu_device *vdev)
  645. {
  646. if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
  647. REGB_WR32(VPU_HW_BTRS_MTL_GLOBAL_INT_MASK, 0x0);
  648. else
  649. REGB_WR32(VPU_HW_BTRS_LNL_GLOBAL_INT_MASK, 0x0);
  650. }
  651. void ivpu_hw_btrs_irq_enable(struct ivpu_device *vdev)
  652. {
  653. if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL) {
  654. REGB_WR32(VPU_HW_BTRS_MTL_LOCAL_INT_MASK, (u32)(~BTRS_MTL_IRQ_MASK));
  655. REGB_WR32(VPU_HW_BTRS_MTL_GLOBAL_INT_MASK, 0x0);
  656. } else {
  657. REGB_WR32(VPU_HW_BTRS_LNL_LOCAL_INT_MASK, (u32)(~BTRS_LNL_IRQ_MASK));
  658. REGB_WR32(VPU_HW_BTRS_LNL_GLOBAL_INT_MASK, 0x0);
  659. }
  660. }
  661. void ivpu_hw_btrs_irq_disable(struct ivpu_device *vdev)
  662. {
  663. if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL) {
  664. REGB_WR32(VPU_HW_BTRS_MTL_GLOBAL_INT_MASK, 0x1);
  665. REGB_WR32(VPU_HW_BTRS_MTL_LOCAL_INT_MASK, BTRS_IRQ_DISABLE_MASK);
  666. } else {
  667. REGB_WR32(VPU_HW_BTRS_LNL_GLOBAL_INT_MASK, 0x1);
  668. REGB_WR32(VPU_HW_BTRS_LNL_LOCAL_INT_MASK, BTRS_IRQ_DISABLE_MASK);
  669. }
  670. }
  671. static void diagnose_failure_mtl(struct ivpu_device *vdev)
  672. {
  673. u32 reg = REGB_RD32(VPU_HW_BTRS_MTL_INTERRUPT_STAT) & BTRS_MTL_IRQ_MASK;
  674. if (REG_TEST_FLD(VPU_HW_BTRS_MTL_INTERRUPT_STAT, ATS_ERR, reg))
  675. ivpu_err(vdev, "ATS_ERR irq 0x%016llx", REGB_RD64(VPU_HW_BTRS_MTL_ATS_ERR_LOG_0));
  676. if (REG_TEST_FLD(VPU_HW_BTRS_MTL_INTERRUPT_STAT, UFI_ERR, reg)) {
  677. u32 log = REGB_RD32(VPU_HW_BTRS_MTL_UFI_ERR_LOG);
  678. ivpu_err(vdev, "UFI_ERR irq (0x%08x) opcode: 0x%02lx axi_id: 0x%02lx cq_id: 0x%03lx",
  679. log, REG_GET_FLD(VPU_HW_BTRS_MTL_UFI_ERR_LOG, OPCODE, log),
  680. REG_GET_FLD(VPU_HW_BTRS_MTL_UFI_ERR_LOG, AXI_ID, log),
  681. REG_GET_FLD(VPU_HW_BTRS_MTL_UFI_ERR_LOG, CQ_ID, log));
  682. }
  683. }
  684. static void diagnose_failure_lnl(struct ivpu_device *vdev)
  685. {
  686. u32 reg = REGB_RD32(VPU_HW_BTRS_MTL_INTERRUPT_STAT) & BTRS_LNL_IRQ_MASK;
  687. if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, ATS_ERR, reg)) {
  688. ivpu_err(vdev, "ATS_ERR_LOG1 0x%08x ATS_ERR_LOG2 0x%08x\n",
  689. REGB_RD32(VPU_HW_BTRS_LNL_ATS_ERR_LOG1),
  690. REGB_RD32(VPU_HW_BTRS_LNL_ATS_ERR_LOG2));
  691. }
  692. if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, CFI0_ERR, reg))
  693. ivpu_err(vdev, "CFI0_ERR_LOG 0x%08x\n", REGB_RD32(VPU_HW_BTRS_LNL_CFI0_ERR_LOG));
  694. if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, CFI1_ERR, reg))
  695. ivpu_err(vdev, "CFI1_ERR_LOG 0x%08x\n", REGB_RD32(VPU_HW_BTRS_LNL_CFI1_ERR_LOG));
  696. if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, IMR0_ERR, reg))
  697. ivpu_err(vdev, "IMR_ERR_CFI0 LOW: 0x%08x HIGH: 0x%08x\n",
  698. REGB_RD32(VPU_HW_BTRS_LNL_IMR_ERR_CFI0_LOW),
  699. REGB_RD32(VPU_HW_BTRS_LNL_IMR_ERR_CFI0_HIGH));
  700. if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, IMR1_ERR, reg))
  701. ivpu_err(vdev, "IMR_ERR_CFI1 LOW: 0x%08x HIGH: 0x%08x\n",
  702. REGB_RD32(VPU_HW_BTRS_LNL_IMR_ERR_CFI1_LOW),
  703. REGB_RD32(VPU_HW_BTRS_LNL_IMR_ERR_CFI1_HIGH));
  704. if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, SURV_ERR, reg))
  705. ivpu_err(vdev, "Survivability IRQ\n");
  706. }
  707. void ivpu_hw_btrs_diagnose_failure(struct ivpu_device *vdev)
  708. {
  709. if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
  710. return diagnose_failure_mtl(vdev);
  711. else
  712. return diagnose_failure_lnl(vdev);
  713. }
  714. int ivpu_hw_btrs_platform_read(struct ivpu_device *vdev)
  715. {
  716. u32 reg = REGB_RD32(VPU_HW_BTRS_LNL_VPU_STATUS);
  717. return REG_GET_FLD(VPU_HW_BTRS_LNL_VPU_STATUS, PLATFORM, reg);
  718. }