panthor_pwr.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. // SPDX-License-Identifier: GPL-2.0 or MIT
  2. /* Copyright 2025 ARM Limited. All rights reserved. */
  3. #include <linux/platform_device.h>
  4. #include <linux/interrupt.h>
  5. #include <linux/cleanup.h>
  6. #include <linux/iopoll.h>
  7. #include <linux/wait.h>
  8. #include <drm/drm_managed.h>
  9. #include <drm/drm_print.h>
  10. #include "panthor_device.h"
  11. #include "panthor_hw.h"
  12. #include "panthor_pwr.h"
  13. #include "panthor_regs.h"
  14. #define PWR_INTERRUPTS_MASK \
  15. (PWR_IRQ_POWER_CHANGED_SINGLE | \
  16. PWR_IRQ_POWER_CHANGED_ALL | \
  17. PWR_IRQ_DELEGATION_CHANGED | \
  18. PWR_IRQ_RESET_COMPLETED | \
  19. PWR_IRQ_RETRACT_COMPLETED | \
  20. PWR_IRQ_INSPECT_COMPLETED | \
  21. PWR_IRQ_COMMAND_NOT_ALLOWED | \
  22. PWR_IRQ_COMMAND_INVALID)
  23. #define PWR_ALL_CORES_MASK GENMASK_U64(63, 0)
  24. #define PWR_DOMAIN_MAX_BITS 16
  25. #define PWR_TRANSITION_TIMEOUT_US (2ULL * USEC_PER_SEC)
  26. #define PWR_RETRACT_TIMEOUT_US (2ULL * USEC_PER_MSEC)
  27. #define PWR_RESET_TIMEOUT_MS 500
  28. /**
  29. * struct panthor_pwr - PWR_CONTROL block management data.
  30. */
  31. struct panthor_pwr {
  32. /** @irq: PWR irq. */
  33. struct panthor_irq irq;
  34. /** @reqs_lock: Lock protecting access to pending_reqs. */
  35. spinlock_t reqs_lock;
  36. /** @pending_reqs: Pending PWR requests. */
  37. u32 pending_reqs;
  38. /** @reqs_acked: PWR request wait queue. */
  39. wait_queue_head_t reqs_acked;
  40. };
  41. static void panthor_pwr_irq_handler(struct panthor_device *ptdev, u32 status)
  42. {
  43. spin_lock(&ptdev->pwr->reqs_lock);
  44. gpu_write(ptdev, PWR_INT_CLEAR, status);
  45. if (unlikely(status & PWR_IRQ_COMMAND_NOT_ALLOWED))
  46. drm_err(&ptdev->base, "PWR_IRQ: COMMAND_NOT_ALLOWED");
  47. if (unlikely(status & PWR_IRQ_COMMAND_INVALID))
  48. drm_err(&ptdev->base, "PWR_IRQ: COMMAND_INVALID");
  49. if (status & ptdev->pwr->pending_reqs) {
  50. ptdev->pwr->pending_reqs &= ~status;
  51. wake_up_all(&ptdev->pwr->reqs_acked);
  52. }
  53. spin_unlock(&ptdev->pwr->reqs_lock);
  54. }
  55. PANTHOR_IRQ_HANDLER(pwr, PWR, panthor_pwr_irq_handler);
  56. static void panthor_pwr_write_command(struct panthor_device *ptdev, u32 command, u64 args)
  57. {
  58. if (args)
  59. gpu_write64(ptdev, PWR_CMDARG, args);
  60. gpu_write(ptdev, PWR_COMMAND, command);
  61. }
  62. static bool reset_irq_raised(struct panthor_device *ptdev)
  63. {
  64. return gpu_read(ptdev, PWR_INT_RAWSTAT) & PWR_IRQ_RESET_COMPLETED;
  65. }
  66. static bool reset_pending(struct panthor_device *ptdev)
  67. {
  68. return (ptdev->pwr->pending_reqs & PWR_IRQ_RESET_COMPLETED);
  69. }
  70. static int panthor_pwr_reset(struct panthor_device *ptdev, u32 reset_cmd)
  71. {
  72. scoped_guard(spinlock_irqsave, &ptdev->pwr->reqs_lock) {
  73. if (reset_pending(ptdev)) {
  74. drm_WARN(&ptdev->base, 1, "Reset already pending");
  75. } else {
  76. ptdev->pwr->pending_reqs |= PWR_IRQ_RESET_COMPLETED;
  77. gpu_write(ptdev, PWR_INT_CLEAR, PWR_IRQ_RESET_COMPLETED);
  78. panthor_pwr_write_command(ptdev, reset_cmd, 0);
  79. }
  80. }
  81. if (!wait_event_timeout(ptdev->pwr->reqs_acked, !reset_pending(ptdev),
  82. msecs_to_jiffies(PWR_RESET_TIMEOUT_MS))) {
  83. guard(spinlock_irqsave)(&ptdev->pwr->reqs_lock);
  84. if (reset_pending(ptdev) && !reset_irq_raised(ptdev)) {
  85. drm_err(&ptdev->base, "RESET timed out (0x%x)", reset_cmd);
  86. return -ETIMEDOUT;
  87. }
  88. ptdev->pwr->pending_reqs &= ~PWR_IRQ_RESET_COMPLETED;
  89. }
  90. return 0;
  91. }
  92. static const char *get_domain_name(u8 domain)
  93. {
  94. switch (domain) {
  95. case PWR_COMMAND_DOMAIN_L2:
  96. return "L2";
  97. case PWR_COMMAND_DOMAIN_TILER:
  98. return "Tiler";
  99. case PWR_COMMAND_DOMAIN_SHADER:
  100. return "Shader";
  101. case PWR_COMMAND_DOMAIN_BASE:
  102. return "Base";
  103. case PWR_COMMAND_DOMAIN_STACK:
  104. return "Stack";
  105. }
  106. return "Unknown";
  107. }
  108. static u32 get_domain_base(u8 domain)
  109. {
  110. switch (domain) {
  111. case PWR_COMMAND_DOMAIN_L2:
  112. return PWR_L2_PRESENT;
  113. case PWR_COMMAND_DOMAIN_TILER:
  114. return PWR_TILER_PRESENT;
  115. case PWR_COMMAND_DOMAIN_SHADER:
  116. return PWR_SHADER_PRESENT;
  117. case PWR_COMMAND_DOMAIN_BASE:
  118. return PWR_BASE_PRESENT;
  119. case PWR_COMMAND_DOMAIN_STACK:
  120. return PWR_STACK_PRESENT;
  121. }
  122. return 0;
  123. }
  124. static u32 get_domain_ready_reg(u32 domain)
  125. {
  126. return get_domain_base(domain) + (PWR_L2_READY - PWR_L2_PRESENT);
  127. }
  128. static u32 get_domain_pwrtrans_reg(u32 domain)
  129. {
  130. return get_domain_base(domain) + (PWR_L2_PWRTRANS - PWR_L2_PRESENT);
  131. }
  132. static bool is_valid_domain(u32 domain)
  133. {
  134. return get_domain_base(domain) != 0;
  135. }
  136. static bool has_rtu(struct panthor_device *ptdev)
  137. {
  138. return ptdev->gpu_info.gpu_features & GPU_FEATURES_RAY_TRAVERSAL;
  139. }
  140. static u8 get_domain_subdomain(struct panthor_device *ptdev, u32 domain)
  141. {
  142. if (domain == PWR_COMMAND_DOMAIN_SHADER && has_rtu(ptdev))
  143. return PWR_COMMAND_SUBDOMAIN_RTU;
  144. return 0;
  145. }
  146. static int panthor_pwr_domain_wait_transition(struct panthor_device *ptdev, u32 domain,
  147. u32 timeout_us)
  148. {
  149. u32 pwrtrans_reg = get_domain_pwrtrans_reg(domain);
  150. u64 val;
  151. int ret = 0;
  152. ret = gpu_read64_poll_timeout(ptdev, pwrtrans_reg, val, !(PWR_ALL_CORES_MASK & val), 100,
  153. timeout_us);
  154. if (ret) {
  155. drm_err(&ptdev->base, "%s domain power in transition, pwrtrans(0x%llx)",
  156. get_domain_name(domain), val);
  157. return ret;
  158. }
  159. return 0;
  160. }
  161. static void panthor_pwr_debug_info_show(struct panthor_device *ptdev)
  162. {
  163. drm_info(&ptdev->base, "GPU_FEATURES: 0x%016llx", gpu_read64(ptdev, GPU_FEATURES));
  164. drm_info(&ptdev->base, "PWR_STATUS: 0x%016llx", gpu_read64(ptdev, PWR_STATUS));
  165. drm_info(&ptdev->base, "L2_PRESENT: 0x%016llx", gpu_read64(ptdev, PWR_L2_PRESENT));
  166. drm_info(&ptdev->base, "L2_PWRTRANS: 0x%016llx", gpu_read64(ptdev, PWR_L2_PWRTRANS));
  167. drm_info(&ptdev->base, "L2_READY: 0x%016llx", gpu_read64(ptdev, PWR_L2_READY));
  168. drm_info(&ptdev->base, "TILER_PRESENT: 0x%016llx", gpu_read64(ptdev, PWR_TILER_PRESENT));
  169. drm_info(&ptdev->base, "TILER_PWRTRANS: 0x%016llx", gpu_read64(ptdev, PWR_TILER_PWRTRANS));
  170. drm_info(&ptdev->base, "TILER_READY: 0x%016llx", gpu_read64(ptdev, PWR_TILER_READY));
  171. drm_info(&ptdev->base, "SHADER_PRESENT: 0x%016llx", gpu_read64(ptdev, PWR_SHADER_PRESENT));
  172. drm_info(&ptdev->base, "SHADER_PWRTRANS: 0x%016llx", gpu_read64(ptdev, PWR_SHADER_PWRTRANS));
  173. drm_info(&ptdev->base, "SHADER_READY: 0x%016llx", gpu_read64(ptdev, PWR_SHADER_READY));
  174. }
  175. static int panthor_pwr_domain_transition(struct panthor_device *ptdev, u32 cmd, u32 domain,
  176. u64 mask, u32 timeout_us)
  177. {
  178. u32 ready_reg = get_domain_ready_reg(domain);
  179. u32 pwr_cmd = PWR_COMMAND_DEF(cmd, domain, get_domain_subdomain(ptdev, domain));
  180. u64 expected_val = 0;
  181. u64 val;
  182. int ret = 0;
  183. if (drm_WARN_ON(&ptdev->base, !is_valid_domain(domain)))
  184. return -EINVAL;
  185. switch (cmd) {
  186. case PWR_COMMAND_POWER_DOWN:
  187. expected_val = 0;
  188. break;
  189. case PWR_COMMAND_POWER_UP:
  190. expected_val = mask;
  191. break;
  192. default:
  193. drm_err(&ptdev->base, "Invalid power domain transition command (0x%x)", cmd);
  194. return -EINVAL;
  195. }
  196. ret = panthor_pwr_domain_wait_transition(ptdev, domain, timeout_us);
  197. if (ret)
  198. return ret;
  199. /* domain already in target state, return early */
  200. if ((gpu_read64(ptdev, ready_reg) & mask) == expected_val)
  201. return 0;
  202. panthor_pwr_write_command(ptdev, pwr_cmd, mask);
  203. ret = gpu_read64_poll_timeout(ptdev, ready_reg, val, (mask & val) == expected_val, 100,
  204. timeout_us);
  205. if (ret) {
  206. drm_err(&ptdev->base,
  207. "timeout waiting on %s power domain transition, cmd(0x%x), arg(0x%llx)",
  208. get_domain_name(domain), pwr_cmd, mask);
  209. panthor_pwr_debug_info_show(ptdev);
  210. return ret;
  211. }
  212. return 0;
  213. }
  214. #define panthor_pwr_domain_power_off(__ptdev, __domain, __mask, __timeout_us) \
  215. panthor_pwr_domain_transition(__ptdev, PWR_COMMAND_POWER_DOWN, __domain, __mask, \
  216. __timeout_us)
  217. #define panthor_pwr_domain_power_on(__ptdev, __domain, __mask, __timeout_us) \
  218. panthor_pwr_domain_transition(__ptdev, PWR_COMMAND_POWER_UP, __domain, __mask, __timeout_us)
  219. /**
  220. * retract_domain() - Retract control of a domain from MCU
  221. * @ptdev: Device.
  222. * @domain: Domain to retract the control
  223. *
  224. * Retracting L2 domain is not expected since it won't be delegated.
  225. *
  226. * Return: 0 on success or retracted already.
  227. * -EPERM if domain is L2.
  228. * A negative error code otherwise.
  229. */
  230. static int retract_domain(struct panthor_device *ptdev, u32 domain)
  231. {
  232. const u32 pwr_cmd = PWR_COMMAND_DEF(PWR_COMMAND_RETRACT, domain, 0);
  233. const u64 pwr_status = gpu_read64(ptdev, PWR_STATUS);
  234. const u64 delegated_mask = PWR_STATUS_DOMAIN_DELEGATED(domain);
  235. const u64 allow_mask = PWR_STATUS_DOMAIN_ALLOWED(domain);
  236. u64 val;
  237. int ret;
  238. if (drm_WARN_ON(&ptdev->base, domain == PWR_COMMAND_DOMAIN_L2))
  239. return -EPERM;
  240. ret = gpu_read64_poll_timeout(ptdev, PWR_STATUS, val, !(PWR_STATUS_RETRACT_PENDING & val),
  241. 0, PWR_RETRACT_TIMEOUT_US);
  242. if (ret) {
  243. drm_err(&ptdev->base, "%s domain retract pending", get_domain_name(domain));
  244. return ret;
  245. }
  246. if (!(pwr_status & delegated_mask)) {
  247. drm_dbg(&ptdev->base, "%s domain already retracted", get_domain_name(domain));
  248. return 0;
  249. }
  250. panthor_pwr_write_command(ptdev, pwr_cmd, 0);
  251. /*
  252. * On successful retraction
  253. * allow-flag will be set with delegated-flag being cleared.
  254. */
  255. ret = gpu_read64_poll_timeout(ptdev, PWR_STATUS, val,
  256. ((delegated_mask | allow_mask) & val) == allow_mask, 10,
  257. PWR_TRANSITION_TIMEOUT_US);
  258. if (ret) {
  259. drm_err(&ptdev->base, "Retracting %s domain timeout, cmd(0x%x)",
  260. get_domain_name(domain), pwr_cmd);
  261. return ret;
  262. }
  263. return 0;
  264. }
  265. /**
  266. * delegate_domain() - Delegate control of a domain to MCU
  267. * @ptdev: Device.
  268. * @domain: Domain to delegate the control
  269. *
  270. * Delegating L2 domain is prohibited.
  271. *
  272. * Return:
  273. * * 0 on success or delegated already.
  274. * * -EPERM if domain is L2.
  275. * * A negative error code otherwise.
  276. */
  277. static int delegate_domain(struct panthor_device *ptdev, u32 domain)
  278. {
  279. const u32 pwr_cmd = PWR_COMMAND_DEF(PWR_COMMAND_DELEGATE, domain, 0);
  280. const u64 pwr_status = gpu_read64(ptdev, PWR_STATUS);
  281. const u64 allow_mask = PWR_STATUS_DOMAIN_ALLOWED(domain);
  282. const u64 delegated_mask = PWR_STATUS_DOMAIN_DELEGATED(domain);
  283. u64 val;
  284. int ret;
  285. if (drm_WARN_ON(&ptdev->base, domain == PWR_COMMAND_DOMAIN_L2))
  286. return -EPERM;
  287. /* Already delegated, exit early */
  288. if (pwr_status & delegated_mask)
  289. return 0;
  290. /* Check if the command is allowed before delegating. */
  291. if (!(pwr_status & allow_mask)) {
  292. drm_warn(&ptdev->base, "Delegating %s domain not allowed", get_domain_name(domain));
  293. return -EPERM;
  294. }
  295. ret = panthor_pwr_domain_wait_transition(ptdev, domain, PWR_TRANSITION_TIMEOUT_US);
  296. if (ret)
  297. return ret;
  298. panthor_pwr_write_command(ptdev, pwr_cmd, 0);
  299. /*
  300. * On successful delegation
  301. * allow-flag will be cleared with delegated-flag being set.
  302. */
  303. ret = gpu_read64_poll_timeout(ptdev, PWR_STATUS, val,
  304. ((delegated_mask | allow_mask) & val) == delegated_mask,
  305. 10, PWR_TRANSITION_TIMEOUT_US);
  306. if (ret) {
  307. drm_err(&ptdev->base, "Delegating %s domain timeout, cmd(0x%x)",
  308. get_domain_name(domain), pwr_cmd);
  309. return ret;
  310. }
  311. return 0;
  312. }
  313. static int panthor_pwr_delegate_domains(struct panthor_device *ptdev)
  314. {
  315. int ret;
  316. if (!ptdev->pwr)
  317. return 0;
  318. ret = delegate_domain(ptdev, PWR_COMMAND_DOMAIN_SHADER);
  319. if (ret)
  320. return ret;
  321. ret = delegate_domain(ptdev, PWR_COMMAND_DOMAIN_TILER);
  322. if (ret)
  323. goto err_retract_shader;
  324. return 0;
  325. err_retract_shader:
  326. retract_domain(ptdev, PWR_COMMAND_DOMAIN_SHADER);
  327. return ret;
  328. }
  329. /**
  330. * panthor_pwr_domain_force_off - Forcefully power down a domain.
  331. * @ptdev: Device.
  332. * @domain: Domain to forcefully power down.
  333. *
  334. * This function will attempt to retract and power off the requested power
  335. * domain. However, if retraction fails, the operation is aborted. If power off
  336. * fails, the domain will remain retracted and under the host control.
  337. *
  338. * Return: 0 on success or a negative error code on failure.
  339. */
  340. static int panthor_pwr_domain_force_off(struct panthor_device *ptdev, u32 domain)
  341. {
  342. const u64 domain_ready = gpu_read64(ptdev, get_domain_ready_reg(domain));
  343. int ret;
  344. /* Domain already powered down, early exit. */
  345. if (!domain_ready)
  346. return 0;
  347. /* Domain has to be in host control to issue power off command. */
  348. ret = retract_domain(ptdev, domain);
  349. if (ret)
  350. return ret;
  351. return panthor_pwr_domain_power_off(ptdev, domain, domain_ready, PWR_TRANSITION_TIMEOUT_US);
  352. }
  353. void panthor_pwr_unplug(struct panthor_device *ptdev)
  354. {
  355. unsigned long flags;
  356. if (!ptdev->pwr)
  357. return;
  358. /* Make sure the IRQ handler is not running after that point. */
  359. panthor_pwr_irq_suspend(&ptdev->pwr->irq);
  360. /* Wake-up all waiters. */
  361. spin_lock_irqsave(&ptdev->pwr->reqs_lock, flags);
  362. ptdev->pwr->pending_reqs = 0;
  363. wake_up_all(&ptdev->pwr->reqs_acked);
  364. spin_unlock_irqrestore(&ptdev->pwr->reqs_lock, flags);
  365. }
  366. int panthor_pwr_init(struct panthor_device *ptdev)
  367. {
  368. struct panthor_pwr *pwr;
  369. int err, irq;
  370. if (!panthor_hw_has_pwr_ctrl(ptdev))
  371. return 0;
  372. pwr = drmm_kzalloc(&ptdev->base, sizeof(*pwr), GFP_KERNEL);
  373. if (!pwr)
  374. return -ENOMEM;
  375. spin_lock_init(&pwr->reqs_lock);
  376. init_waitqueue_head(&pwr->reqs_acked);
  377. ptdev->pwr = pwr;
  378. irq = platform_get_irq_byname(to_platform_device(ptdev->base.dev), "gpu");
  379. if (irq < 0)
  380. return irq;
  381. err = panthor_request_pwr_irq(ptdev, &pwr->irq, irq, PWR_INTERRUPTS_MASK);
  382. if (err)
  383. return err;
  384. return 0;
  385. }
  386. int panthor_pwr_reset_soft(struct panthor_device *ptdev)
  387. {
  388. if (!(gpu_read64(ptdev, PWR_STATUS) & PWR_STATUS_ALLOW_SOFT_RESET)) {
  389. drm_err(&ptdev->base, "RESET_SOFT not allowed");
  390. return -EOPNOTSUPP;
  391. }
  392. return panthor_pwr_reset(ptdev, PWR_COMMAND_RESET_SOFT);
  393. }
  394. void panthor_pwr_l2_power_off(struct panthor_device *ptdev)
  395. {
  396. const u64 l2_allow_mask = PWR_STATUS_DOMAIN_ALLOWED(PWR_COMMAND_DOMAIN_L2);
  397. const u64 pwr_status = gpu_read64(ptdev, PWR_STATUS);
  398. /* Abort if L2 power off constraints are not satisfied */
  399. if (!(pwr_status & l2_allow_mask)) {
  400. drm_warn(&ptdev->base, "Power off L2 domain not allowed");
  401. return;
  402. }
  403. /* It is expected that when halting the MCU, it would power down its
  404. * delegated domains. However, an unresponsive or hung MCU may not do
  405. * so, which is why we need to check and retract the domains back into
  406. * host control to be powered down in the right order before powering
  407. * down the L2.
  408. */
  409. if (panthor_pwr_domain_force_off(ptdev, PWR_COMMAND_DOMAIN_TILER))
  410. return;
  411. if (panthor_pwr_domain_force_off(ptdev, PWR_COMMAND_DOMAIN_SHADER))
  412. return;
  413. panthor_pwr_domain_power_off(ptdev, PWR_COMMAND_DOMAIN_L2, ptdev->gpu_info.l2_present,
  414. PWR_TRANSITION_TIMEOUT_US);
  415. }
  416. int panthor_pwr_l2_power_on(struct panthor_device *ptdev)
  417. {
  418. const u32 pwr_status = gpu_read64(ptdev, PWR_STATUS);
  419. const u32 l2_allow_mask = PWR_STATUS_DOMAIN_ALLOWED(PWR_COMMAND_DOMAIN_L2);
  420. int ret;
  421. if ((pwr_status & l2_allow_mask) == 0) {
  422. drm_warn(&ptdev->base, "Power on L2 domain not allowed");
  423. return -EPERM;
  424. }
  425. ret = panthor_pwr_domain_power_on(ptdev, PWR_COMMAND_DOMAIN_L2, ptdev->gpu_info.l2_present,
  426. PWR_TRANSITION_TIMEOUT_US);
  427. if (ret)
  428. return ret;
  429. /* Delegate control of the shader and tiler power domains to the MCU as
  430. * it can better manage which shader/tiler cores need to be powered up
  431. * or can be powered down based on currently running jobs.
  432. *
  433. * If the shader and tiler domains are already delegated to the MCU,
  434. * this call would just return early.
  435. */
  436. return panthor_pwr_delegate_domains(ptdev);
  437. }
  438. void panthor_pwr_suspend(struct panthor_device *ptdev)
  439. {
  440. if (!ptdev->pwr)
  441. return;
  442. panthor_pwr_irq_suspend(&ptdev->pwr->irq);
  443. }
  444. void panthor_pwr_resume(struct panthor_device *ptdev)
  445. {
  446. if (!ptdev->pwr)
  447. return;
  448. panthor_pwr_irq_resume(&ptdev->pwr->irq, PWR_INTERRUPTS_MASK);
  449. }