msm_iommu_perfmon-v0.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. /* Copyright (c) 2013, The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. */
  12. /**
  13. * This file contains the part of the IOMMUv0 PMU driver that actually touches
  14. * IOMMU PMU registers.
  15. */
  16. #include <linux/io.h>
  17. #include <linux/interrupt.h>
  18. #include <linux/module.h>
  19. #include <linux/device.h>
  20. #include <mach/iommu_hw-v0.h>
  21. #include <mach/iommu_perfmon.h>
  22. #include <mach/iommu.h>
  23. #define PM_RESET_MASK (0xF)
  24. #define PM_RESET_SHIFT (0x8)
  25. #define PM_RESET (PM_RESET_MASK << PM_RESET_SHIFT)
  26. #define PM_ENABLE_MASK (0x1)
  27. #define PM_ENABLE_SHIFT (0x0)
  28. #define PM_ENABLE (PM_ENABLE_MASK << PM_ENABLE_SHIFT)
  29. #define PM_OVFL_FLAG_MASK (0xF)
  30. #define PM_OVFL_FLAG_SHIFT (0x0)
  31. #define PM_OVFL_FLAG (PM_OVFL_FLAG_MASK << PM_OVFL_FLAG_SHIFT)
  32. #define PM_EVENT_TYPE_MASK (0x1F)
  33. #define PM_EVENT_TYPE_SHIFT (0x2)
  34. #define PM_EVENT_TYPE (PM_EVENT_TYPE_MASK << PM_EVENT_TYPE_SHIFT)
  35. #define PM_INT_EN_MASK (0x1)
  36. #define PM_INT_EN_SHIFT (0x0)
  37. #define PM_INT_EN (PM_INT_EN_MASK << PM_INT_EN_SHIFT)
  38. #define PM_INT_POL_MASK (0x1)
  39. #define PM_INT_POL_SHIFT (0x2)
  40. #define PM_INT_ACTIVE_HIGH (0x1)
  41. #define PMEVCNTR_(n) (EMC_N + n*4)
  42. #define PMEVTYPER_(n) (EMCC_N + n*4)
  43. /**
  44. * Translate between SMMUv0 event classes and standard ARM SMMU event classes
  45. */
  46. static int iommu_pm_event_class_translation_table[] = {
  47. MSM_IOMMU_PMU_NO_EVENT_CLASS,
  48. MSM_IOMMU_PMU_NO_EVENT_CLASS,
  49. MSM_IOMMU_PMU_NO_EVENT_CLASS,
  50. 0x8,
  51. 0x9,
  52. MSM_IOMMU_PMU_NO_EVENT_CLASS,
  53. 0x80,
  54. MSM_IOMMU_PMU_NO_EVENT_CLASS,
  55. 0x12,
  56. MSM_IOMMU_PMU_NO_EVENT_CLASS,
  57. MSM_IOMMU_PMU_NO_EVENT_CLASS,
  58. MSM_IOMMU_PMU_NO_EVENT_CLASS,
  59. MSM_IOMMU_PMU_NO_EVENT_CLASS,
  60. MSM_IOMMU_PMU_NO_EVENT_CLASS,
  61. MSM_IOMMU_PMU_NO_EVENT_CLASS,
  62. 0x10,
  63. };
  64. static int iommu_pm_translate_event_class(int event_class)
  65. {
  66. const unsigned int TBL_LEN =
  67. ARRAY_SIZE(iommu_pm_event_class_translation_table);
  68. unsigned int i;
  69. if (event_class < 0)
  70. return event_class;
  71. for (i = 0; i < TBL_LEN; ++i) {
  72. if (iommu_pm_event_class_translation_table[i] == event_class)
  73. return i;
  74. }
  75. return MSM_IOMMU_PMU_NO_EVENT_CLASS;
  76. }
  77. static unsigned int iommu_pm_is_hw_access_OK(const struct iommu_pmon *pmon)
  78. {
  79. /*
  80. * IOMMUv0 is in always ON domain so we don't care whether we are
  81. * attached or not. We only care whether the PMU is enabled or
  82. * not meaning clocks are turned on.
  83. */
  84. return pmon->enabled;
  85. }
  86. static void iommu_pm_grp_enable(struct iommu_info *iommu, unsigned int grp_no)
  87. {
  88. /* No group concept in v0. */
  89. }
  90. static void iommu_pm_grp_disable(struct iommu_info *iommu, unsigned int grp_no)
  91. {
  92. /* No group concept in v0. */
  93. }
  94. static void iommu_pm_set_int_active_high(const struct iommu_info *iommu)
  95. {
  96. unsigned int emmc;
  97. emmc = readl_relaxed(iommu->base + EMMC);
  98. emmc |= (PM_INT_ACTIVE_HIGH & PM_INT_POL_MASK) << PM_INT_POL_SHIFT;
  99. writel_relaxed(emmc, iommu->base + EMMC);
  100. }
  101. static void iommu_pm_enable(struct iommu_info *iommu)
  102. {
  103. unsigned int emmc;
  104. emmc = readl_relaxed(iommu->base + EMMC);
  105. emmc |= PM_ENABLE;
  106. writel_relaxed(emmc, iommu->base + EMMC);
  107. }
  108. static void iommu_pm_disable(struct iommu_info *iommu)
  109. {
  110. unsigned int emmc;
  111. emmc = readl_relaxed(iommu->base + EMMC);
  112. emmc &= ~PM_ENABLE;
  113. writel_relaxed(emmc, iommu->base + EMMC);
  114. }
  115. static void iommu_pm_reset_counters(const struct iommu_info *iommu)
  116. {
  117. unsigned int emmc;
  118. emmc = readl_relaxed(iommu->base + EMMC);
  119. emmc |= PM_RESET;
  120. writel_relaxed(emmc, iommu->base + EMMC);
  121. }
  122. static void iommu_pm_check_for_overflow(struct iommu_pmon *pmon)
  123. {
  124. struct iommu_pmon_counter *counter;
  125. struct iommu_info *iommu = &pmon->iommu;
  126. unsigned int reg_value;
  127. unsigned int j;
  128. struct iommu_pmon_cnt_group *cnt_grp = &pmon->cnt_grp[0];
  129. reg_value = readl_relaxed(iommu->base + EMCS);
  130. reg_value &= PM_OVFL_FLAG;
  131. for (j = 0; j < cnt_grp->num_counters; ++j) {
  132. counter = &cnt_grp->counters[j];
  133. if (counter->enabled) {
  134. if (reg_value & (1 << counter->absolute_counter_no))
  135. counter->overflow_count++;
  136. }
  137. }
  138. /* Clear overflow */
  139. writel_relaxed(reg_value, iommu->base + EMCS);
  140. }
  141. static irqreturn_t iommu_pm_evt_ovfl_int_handler(int irq, void *dev_id)
  142. {
  143. struct iommu_pmon *pmon = dev_id;
  144. struct iommu_info *iommu = &pmon->iommu;
  145. mutex_lock(&pmon->lock);
  146. if (!iommu_pm_is_hw_access_OK(pmon)) {
  147. mutex_unlock(&pmon->lock);
  148. goto out;
  149. }
  150. iommu->ops->iommu_lock_acquire(1);
  151. iommu_pm_check_for_overflow(pmon);
  152. iommu->ops->iommu_lock_release(1);
  153. mutex_unlock(&pmon->lock);
  154. out:
  155. return IRQ_HANDLED;
  156. }
  157. static void iommu_pm_counter_enable(struct iommu_info *iommu,
  158. struct iommu_pmon_counter *counter)
  159. {
  160. unsigned int bit_no = counter->absolute_counter_no;
  161. unsigned int reg_value;
  162. /* Clear overflow of counter */
  163. reg_value = readl_relaxed(iommu->base + EMCS);
  164. reg_value &= (1 << bit_no);
  165. writel_relaxed(reg_value, iommu->base + EMCS);
  166. /* Enable counter */
  167. counter->enabled = 1;
  168. }
  169. static void iommu_pm_counter_disable(struct iommu_info *iommu,
  170. struct iommu_pmon_counter *counter)
  171. {
  172. unsigned int bit_no = counter->absolute_counter_no;
  173. unsigned int reg_value;
  174. /* Disable counter */
  175. counter->enabled = 0;
  176. /* Clear overflow of counter */
  177. reg_value = readl_relaxed(iommu->base + EMCS);
  178. reg_value &= (1 << bit_no);
  179. writel_relaxed(reg_value, iommu->base + EMCS);
  180. }
  181. /*
  182. * Must be called after iommu_start_access() is called
  183. */
  184. static void iommu_pm_ovfl_int_enable(struct iommu_info *iommu,
  185. const struct iommu_pmon_counter *counter)
  186. {
  187. unsigned int reg_no = counter->absolute_counter_no;
  188. unsigned int reg_value;
  189. /* Enable overflow interrupt for counter */
  190. reg_value = readl_relaxed(iommu->base + PMEVTYPER_(reg_no));
  191. reg_value |= PM_INT_EN;
  192. writel_relaxed(reg_value, iommu->base + PMEVTYPER_(reg_no));
  193. }
  194. /*
  195. * Must be called after iommu_start_access() is called
  196. */
  197. static void iommu_pm_ovfl_int_disable(struct iommu_info *iommu,
  198. const struct iommu_pmon_counter *counter)
  199. {
  200. unsigned int reg_no = counter->absolute_counter_no;
  201. unsigned int reg_value;
  202. /* Disable overflow interrupt for counter */
  203. reg_value = readl_relaxed(iommu->base + PMEVTYPER_(reg_no));
  204. reg_value &= ~PM_INT_EN;
  205. writel_relaxed(reg_value, iommu->base + PMEVTYPER_(reg_no));
  206. }
  207. static void iommu_pm_set_event_class(struct iommu_pmon *pmon,
  208. unsigned int count_no,
  209. unsigned int event_class)
  210. {
  211. unsigned int reg_no = count_no;
  212. unsigned int reg_value;
  213. int event = iommu_pm_translate_event_class(event_class);
  214. if (event == MSM_IOMMU_PMU_NO_EVENT_CLASS)
  215. event = 0;
  216. reg_value = readl_relaxed(pmon->iommu.base + PMEVTYPER_(reg_no));
  217. reg_value &= ~(PM_EVENT_TYPE_MASK << PM_EVENT_TYPE_SHIFT);
  218. reg_value |= (event & PM_EVENT_TYPE_MASK) << PM_EVENT_TYPE_SHIFT;
  219. writel_relaxed(reg_value, pmon->iommu.base + PMEVTYPER_(reg_no));
  220. }
  221. static unsigned int iommu_pm_read_counter(struct iommu_pmon_counter *counter)
  222. {
  223. struct iommu_pmon *pmon = counter->cnt_group->pmon;
  224. struct iommu_info *info = &pmon->iommu;
  225. unsigned int cnt_no = counter->absolute_counter_no;
  226. return readl_relaxed(info->base + PMEVCNTR_(cnt_no));
  227. }
  228. static void iommu_pm_initialize_hw(const struct iommu_pmon *pmon)
  229. {
  230. const struct iommu_info *iommu = &pmon->iommu;
  231. struct msm_iommu_drvdata *iommu_drvdata =
  232. dev_get_drvdata(iommu->iommu_dev);
  233. /* This is called during bootup device initialization so no need
  234. * for locking here.
  235. */
  236. iommu->ops->iommu_power_on(iommu_drvdata);
  237. iommu->ops->iommu_clk_on(iommu_drvdata);
  238. iommu_pm_set_int_active_high(iommu);
  239. iommu->ops->iommu_clk_off(iommu_drvdata);
  240. iommu->ops->iommu_power_off(iommu_drvdata);
  241. }
  242. static struct iommu_pm_hw_ops iommu_pm_hw_ops = {
  243. .initialize_hw = iommu_pm_initialize_hw,
  244. .is_hw_access_OK = iommu_pm_is_hw_access_OK,
  245. .grp_enable = iommu_pm_grp_enable,
  246. .grp_disable = iommu_pm_grp_disable,
  247. .enable_pm = iommu_pm_enable,
  248. .disable_pm = iommu_pm_disable,
  249. .reset_counters = iommu_pm_reset_counters,
  250. .check_for_overflow = iommu_pm_check_for_overflow,
  251. .evt_ovfl_int_handler = iommu_pm_evt_ovfl_int_handler,
  252. .counter_enable = iommu_pm_counter_enable,
  253. .counter_disable = iommu_pm_counter_disable,
  254. .ovfl_int_enable = iommu_pm_ovfl_int_enable,
  255. .ovfl_int_disable = iommu_pm_ovfl_int_disable,
  256. .set_event_class = iommu_pm_set_event_class,
  257. .read_counter = iommu_pm_read_counter,
  258. };
  259. struct iommu_pm_hw_ops *iommu_pm_get_hw_ops_v0(void)
  260. {
  261. return &iommu_pm_hw_ops;
  262. }
  263. EXPORT_SYMBOL(iommu_pm_get_hw_ops_v0);