intr_hw.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Tegra host1x Interrupt Management
  4. *
  5. * Copyright (C) 2010 Google, Inc.
  6. * Copyright (c) 2010-2013, NVIDIA Corporation.
  7. */
  8. #include <linux/io.h>
  9. #include "../intr.h"
  10. #include "../dev.h"
  11. static irqreturn_t syncpt_thresh_isr(int irq, void *dev_id)
  12. {
  13. struct host1x_intr_irq_data *irq_data = dev_id;
  14. struct host1x *host = irq_data->host;
  15. unsigned long reg;
  16. unsigned int i, id;
  17. for (i = irq_data->offset; i < DIV_ROUND_UP(host->info->nb_pts, 32);
  18. i += host->num_syncpt_irqs) {
  19. reg = host1x_sync_readl(host,
  20. HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i));
  21. host1x_sync_writel(host, reg,
  22. HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(i));
  23. host1x_sync_writel(host, reg,
  24. HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i));
  25. for_each_set_bit(id, &reg, 32)
  26. host1x_intr_handle_interrupt(host, i * 32 + id);
  27. }
  28. return IRQ_HANDLED;
  29. }
  30. static void host1x_intr_disable_all_syncpt_intrs(struct host1x *host)
  31. {
  32. unsigned int i;
  33. for (i = 0; i < DIV_ROUND_UP(host->info->nb_pts, 32); ++i) {
  34. host1x_sync_writel(host, 0xffffffffu,
  35. HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(i));
  36. host1x_sync_writel(host, 0xffffffffu,
  37. HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i));
  38. }
  39. }
  40. static int
  41. host1x_intr_init_host_sync(struct host1x *host, u32 cpm)
  42. {
  43. #if HOST1X_HW < 6
  44. /* disable the ip_busy_timeout. this prevents write drops */
  45. host1x_sync_writel(host, 0, HOST1X_SYNC_IP_BUSY_TIMEOUT);
  46. /*
  47. * increase the auto-ack timout to the maximum value. 2d will hang
  48. * otherwise on Tegra2.
  49. */
  50. host1x_sync_writel(host, 0xff, HOST1X_SYNC_CTXSW_TIMEOUT_CFG);
  51. /* update host clocks per usec */
  52. host1x_sync_writel(host, cpm, HOST1X_SYNC_USEC_CLK);
  53. #endif
  54. #if HOST1X_HW >= 8
  55. u32 id;
  56. /*
  57. * Program threshold interrupt destination among 8 lines per VM,
  58. * per syncpoint. For each group of 32 syncpoints (corresponding to one
  59. * interrupt status register), direct to one interrupt line, going
  60. * around in a round robin fashion.
  61. */
  62. for (id = 0; id < host->info->nb_pts; id++) {
  63. u32 reg_offset = id / 32;
  64. u32 irq_index = reg_offset % host->num_syncpt_irqs;
  65. host1x_sync_writel(host, irq_index, HOST1X_SYNC_SYNCPT_INTR_DEST(id));
  66. }
  67. #endif
  68. return 0;
  69. }
  70. static void host1x_intr_set_syncpt_threshold(struct host1x *host,
  71. unsigned int id,
  72. u32 thresh)
  73. {
  74. host1x_sync_writel(host, thresh, HOST1X_SYNC_SYNCPT_INT_THRESH(id));
  75. }
  76. static void host1x_intr_enable_syncpt_intr(struct host1x *host,
  77. unsigned int id)
  78. {
  79. host1x_sync_writel(host, BIT(id % 32),
  80. HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(id / 32));
  81. }
  82. static void host1x_intr_disable_syncpt_intr(struct host1x *host,
  83. unsigned int id)
  84. {
  85. host1x_sync_writel(host, BIT(id % 32),
  86. HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(id / 32));
  87. host1x_sync_writel(host, BIT(id % 32),
  88. HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(id / 32));
  89. }
  90. static const struct host1x_intr_ops host1x_intr_ops = {
  91. .init_host_sync = host1x_intr_init_host_sync,
  92. .set_syncpt_threshold = host1x_intr_set_syncpt_threshold,
  93. .enable_syncpt_intr = host1x_intr_enable_syncpt_intr,
  94. .disable_syncpt_intr = host1x_intr_disable_syncpt_intr,
  95. .disable_all_syncpt_intrs = host1x_intr_disable_all_syncpt_intrs,
  96. .isr = syncpt_thresh_isr,
  97. };