mt_sys_cirq.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878
  1. #include <linux/kernel.h>
  2. #include <linux/device.h>
  3. #include <linux/platform_device.h>
  4. #include <linux/module.h>
  5. #include <linux/interrupt.h>
  6. #include <linux/module.h>
  7. #include <linux/uaccess.h>
  8. #include <linux/slab.h>
  9. #include <linux/cpu.h>
  10. #include <linux/smp.h>
  11. #include <linux/types.h>
  12. #include <linux/irqchip/arm-gic.h>
  13. #include <linux/irqchip/mt-gic.h>
  14. /*#include <mach/irqs.h>*/
  15. #include "mt_sys_cirq.h"
  16. #include <mt-plat/sync_write.h>
  17. #include <mt-plat/mt_io.h>
  18. #ifdef CONFIG_OF
  19. #include <linux/of.h>
  20. #include <linux/of_address.h>
  21. #include <linux/of_irq.h>
  22. #endif
  23. void __iomem *SYS_CIRQ_BASE;
  24. static unsigned int CIRQ_IRQ_NUM;
  25. static unsigned int CIRQ_SPI_START;
  26. /*
  27. *Define Data Structure
  28. */
  29. struct mt_cirq_driver {
  30. struct platform_driver driver;
  31. const struct platform_device_id *id_table;
  32. };
  33. /*
  34. * Define Global Variable
  35. */
  36. static struct mt_cirq_driver mt_cirq_drv = {
  37. .driver = {
  38. .driver = {
  39. .name = "cirq",
  40. .bus = &platform_bus_type,
  41. .owner = THIS_MODULE,
  42. },
  43. },
  44. .id_table = NULL,
  45. };
  46. static unsigned long cirq_clone_flush_check_val;
  47. static unsigned long cirq_pattern_clone_flush_check_val;
  48. static unsigned long cirq_pattern_list;
  49. /*
  50. * mt_cirq_ack_all: Ack all the interrupt on SYS_CIRQ
  51. */
  52. void mt_cirq_ack_all(void)
  53. {
  54. unsigned int i;
  55. for (i = 0; i < CIRQ_CTRL_REG_NUM; i++)
  56. writel_relaxed(0xFFFFFFFF, CIRQ_ACK_BASE + (i * 4));
  57. /* make sure all cirq setting take effect before doing other things */
  58. mb();
  59. }
  60. /*
  61. * mt_cirq_get_mask: Get the specified SYS_CIRQ mask
  62. * @cirq_num: the SYS_CIRQ number to get
  63. * @return:
  64. * 1: this cirq is masked
  65. * 0: this cirq is umasked
  66. * -1: cirq num is out of range
  67. */
  68. static int mt_cirq_get_mask(unsigned int cirq_num)
  69. {
  70. unsigned int st;
  71. unsigned int bit = 1 << (cirq_num % 32);
  72. if (cirq_num >= CIRQ_IRQ_NUM) {
  73. pr_err("[CIRQ] %s: invalid cirq num %d\n", __func__, cirq_num);
  74. return -1;
  75. }
  76. st = readl(IOMEM((cirq_num / 32) * 4 + CIRQ_MASK_BASE));
  77. return !!(st & bit);
  78. }
  79. /*
  80. * mt_cirq_mask_all: Mask all interrupts on SYS_CIRQ.
  81. */
  82. void mt_cirq_mask_all(void)
  83. {
  84. unsigned int i;
  85. for (i = 0; i < CIRQ_CTRL_REG_NUM; i++)
  86. writel_relaxed(0xFFFFFFFF, CIRQ_MASK_SET_BASE + (i * 4));
  87. /* make sure all cirq setting take effect before doing other things */
  88. mb();
  89. }
  90. /*
  91. * mt_cirq_unmask_all: Unmask all interrupts on SYS_CIRQ.
  92. */
  93. void mt_cirq_unmask_all(void)
  94. {
  95. unsigned int i;
  96. for (i = 0; i < CIRQ_CTRL_REG_NUM; i++)
  97. writel_relaxed(0xFFFFFFFF, CIRQ_MASK_CLR_BASE + (i * 4));
  98. /* make sure all cirq setting take effect before doing other things */
  99. mb();
  100. }
  101. /*
  102. * mt_cirq_mask: Mask the specified SYS_CIRQ.
  103. * @cirq_num: the SYS_CIRQ number to mask
  104. * @return:
  105. * 0: mask success
  106. * -1: cirq num is out of range
  107. */
  108. static int mt_cirq_mask(unsigned int cirq_num)
  109. {
  110. unsigned int bit = 1 << (cirq_num % 32);
  111. if (cirq_num >= CIRQ_IRQ_NUM) {
  112. pr_err("[CIRQ] %s: invalid cirq num %d\n", __func__, cirq_num);
  113. return -1;
  114. }
  115. mt_reg_sync_writel(bit, (cirq_num / 32) * 4 + CIRQ_MASK_SET_BASE);
  116. return 0;
  117. }
  118. /*
  119. * mt_cirq_unmask: Unmask the specified SYS_CIRQ.
  120. * @cirq_num: the SYS_CIRQ number to unmask
  121. * @return:
  122. * 0: umask success
  123. * -1: cirq num is out of range
  124. */
  125. static int mt_cirq_unmask(unsigned int cirq_num)
  126. {
  127. unsigned int bit = 1 << (cirq_num % 32);
  128. if (cirq_num >= CIRQ_IRQ_NUM) {
  129. pr_err("[CIRQ] %s: invalid cirq num %d\n", __func__, cirq_num);
  130. return -1;
  131. }
  132. mt_reg_sync_writel(bit, (cirq_num / 32) * 4 + CIRQ_MASK_CLR_BASE);
  133. return 0;
  134. }
  135. /*
  136. * mt_cirq_get_sens: Get the specified SYS_CIRQ sensitivity
  137. * @cirq_num: the SYS_CIRQ number to get
  138. * @return:
  139. * 1: this cirq is MT_LEVEL_SENSITIVE
  140. * 0: this cirq is MT_EDGE_SENSITIVE
  141. * -1: cirq num is out of range
  142. */
  143. static int mt_cirq_get_sens(unsigned int cirq_num)
  144. {
  145. unsigned int st;
  146. unsigned int bit = 1 << (cirq_num % 32);
  147. if (cirq_num >= CIRQ_IRQ_NUM) {
  148. pr_err("[CIRQ] %s: invalid cirq num %d\n", __func__, cirq_num);
  149. return -1;
  150. }
  151. st = readl(IOMEM((cirq_num / 32) * 4 + CIRQ_SENS_BASE));
  152. return !!(st & bit);
  153. }
  154. /*
  155. * mt_cirq_set_sens: Set the sensitivity for the specified SYS_CIRQ number.
  156. * @cirq_num: the SYS_CIRQ number to set
  157. * @sens: sensitivity to set
  158. * @return:
  159. * 0: set sens success
  160. * -1: cirq num is out of range
  161. */
  162. static int mt_cirq_set_sens(unsigned int cirq_num, unsigned int sens)
  163. {
  164. void __iomem *base;
  165. unsigned int bit = 1 << (cirq_num % 32);
  166. if (cirq_num >= CIRQ_IRQ_NUM) {
  167. pr_err("[CIRQ] %s: invalid cirq num %d\n", __func__, cirq_num);
  168. return -1;
  169. }
  170. if (sens == MT_EDGE_SENSITIVE) {
  171. base = (cirq_num / 32) * 4 + CIRQ_SENS_CLR_BASE;
  172. } else if (sens == MT_LEVEL_SENSITIVE) {
  173. base = (cirq_num / 32) * 4 + CIRQ_SENS_SET_BASE;
  174. } else {
  175. pr_err("[CIRQ] set_sens invalid sensitivity value %d\n", sens);
  176. return -1;
  177. }
  178. mt_reg_sync_writel(bit, base);
  179. return 0;
  180. }
  181. /*
  182. * mt_cirq_get_pol: Get the specified SYS_CIRQ polarity
  183. * @cirq_num: the SYS_CIRQ number to get
  184. * @return:
  185. * 1: this cirq is MT_CIRQ_POL_POS
  186. * 0: this cirq is MT_CIRQ_POL_NEG
  187. * -1: cirq num is out of range
  188. */
  189. static int mt_cirq_get_pol(unsigned int cirq_num)
  190. {
  191. unsigned int st;
  192. unsigned int bit = 1 << (cirq_num % 32);
  193. if (cirq_num >= CIRQ_IRQ_NUM) {
  194. pr_err("[CIRQ] %s: invalid cirq num %d\n", __func__, cirq_num);
  195. return -1;
  196. }
  197. st = readl(IOMEM((cirq_num / 32) * 4 + CIRQ_POL_BASE));
  198. return !!(st & bit);
  199. }
  200. /*
  201. * mt_cirq_set_pol: Set the polarity for the specified SYS_CIRQ number.
  202. * @cirq_num: the SYS_CIRQ number to set
  203. * @pol: polarity to set
  204. * @return:
  205. * 0: set pol success
  206. * -1: cirq num is out of range
  207. */
  208. static int mt_cirq_set_pol(unsigned int cirq_num, unsigned int pol)
  209. {
  210. void __iomem *base;
  211. unsigned int bit = 1 << (cirq_num % 32);
  212. if (cirq_num >= CIRQ_IRQ_NUM) {
  213. pr_err("[CIRQ] %s: invalid cirq num %d\n", __func__, cirq_num);
  214. return -1;
  215. }
  216. if (pol == MT_CIRQ_POL_NEG) {
  217. base = (cirq_num / 32) * 4 + CIRQ_POL_CLR_BASE;
  218. } else if (pol == MT_CIRQ_POL_POS) {
  219. base = (cirq_num / 32) * 4 + CIRQ_POL_SET_BASE;
  220. } else {
  221. pr_err("[CIRQ] set_pol invalid polarity value %d\n", pol);
  222. return -1;
  223. }
  224. mt_reg_sync_writel(bit, base);
  225. return 0;
  226. }
  227. /*
  228. * mt_cirq_enable: Enable SYS_CIRQ
  229. */
  230. void mt_cirq_enable(void)
  231. {
  232. unsigned int st;
  233. mt_cirq_ack_all();
  234. st = readl(IOMEM(CIRQ_CON));
  235. st |=
  236. (CIRQ_CON_EN << CIRQ_CON_EN_BITS) | (CIRQ_CON_EDGE_ONLY <<
  237. CIRQ_CON_EDGE_ONLY_BITS);
  238. mt_reg_sync_writel((st & CIRQ_CON_BITS_MASK), CIRQ_CON);
  239. }
  240. EXPORT_SYMBOL(mt_cirq_enable);
  241. /*
  242. * mt_cirq_get_pending: Get the specified SYS_CIRQ pending
  243. * @cirq_num: the SYS_CIRQ number to get
  244. * @return:
  245. * 1: this cirq is pending
  246. * 0: this cirq is not pending
  247. */
  248. static bool mt_cirq_get_pending(unsigned int cirq_num)
  249. {
  250. unsigned int st;
  251. unsigned int bit = 1 << (cirq_num % 32);
  252. if (cirq_num >= CIRQ_IRQ_NUM) {
  253. pr_err("[CIRQ] %s: invalid cirq num %d\n", __func__, cirq_num);
  254. return -1;
  255. }
  256. st = readl(IOMEM((cirq_num / 32) * 4 + CIRQ_STA_BASE));
  257. st = st & bit;
  258. return st;
  259. }
  260. /*
  261. * mt_cirq_disable: Disable SYS_CIRQ
  262. */
  263. void mt_cirq_disable(void)
  264. {
  265. unsigned int st;
  266. st = readl(IOMEM(CIRQ_CON));
  267. st &= ~(CIRQ_CON_EN << CIRQ_CON_EN_BITS);
  268. mt_reg_sync_writel((st & CIRQ_CON_BITS_MASK), CIRQ_CON);
  269. }
  270. EXPORT_SYMBOL(mt_cirq_disable);
  271. /*
  272. * mt_cirq_disable: Flush interrupt from SYS_CIRQ to GIC
  273. */
  274. void mt_cirq_flush(void)
  275. {
  276. unsigned int i;
  277. unsigned char cirq_p_val = 0;
  278. unsigned char irq_p_val = 0;
  279. unsigned int irq_p = 0;
  280. unsigned char pass = 1;
  281. unsigned int first_cirq_found = 0;
  282. unsigned int first_flushed_cirq;
  283. unsigned int first_irq_flushedto;
  284. unsigned int last_fluashed_cirq;
  285. unsigned int last_irq_flushedto;
  286. if (cirq_pattern_clone_flush_check_val == 1) {
  287. if (cirq_pattern_list < CIRQ_IRQ_NUM) {
  288. mt_cirq_unmask(cirq_pattern_list);
  289. mt_cirq_set_sens(cirq_pattern_list, MT_EDGE_SENSITIVE);
  290. mt_cirq_set_pol(cirq_pattern_list, MT_CIRQ_POL_NEG);
  291. mt_cirq_set_pol(cirq_pattern_list, MT_CIRQ_POL_POS);
  292. mt_cirq_set_pol(cirq_pattern_list, MT_CIRQ_POL_NEG);
  293. } else {
  294. pr_debug
  295. ("[CIRQ] no pattern to test, input pattern first\n");
  296. }
  297. pr_debug("[CIRQ] cirq_pattern %ld, cirq_p %d,",
  298. cirq_pattern_list, mt_cirq_get_pending(cirq_pattern_list));
  299. pr_debug("cirq_s %d, cirq_con 0x%x\n",
  300. mt_cirq_get_sens(cirq_pattern_list), readl(IOMEM(CIRQ_CON)));
  301. }
  302. mt_cirq_unmask_all();
  303. for (i = 0; i < CIRQ_IRQ_NUM; i++) {
  304. cirq_p_val = mt_cirq_get_pending(i);
  305. if (cirq_p_val)
  306. mt_irq_set_pending(CIRQ_TO_IRQ_NUM(i));
  307. if (cirq_clone_flush_check_val == 1) {
  308. if (cirq_p_val == 0)
  309. continue;
  310. irq_p = CIRQ_TO_IRQ_NUM(i);
  311. irq_p_val = mt_irq_get_pending(irq_p);
  312. if (cirq_p_val != irq_p_val) {
  313. pr_err
  314. ("[CIRQ] CIRQ Flush Failed %d(cirq %d) != %d(gic %d)\n",
  315. cirq_p_val, i, irq_p_val,
  316. CIRQ_TO_IRQ_NUM(i));
  317. pass = 0;
  318. } else {
  319. pr_debug
  320. ("[CIRQ] CIRQ Flush Pass %d(cirq %d) = %d(gic %d)\n",
  321. cirq_p_val, i, irq_p_val,
  322. CIRQ_TO_IRQ_NUM(i));
  323. }
  324. if (!first_cirq_found) {
  325. first_flushed_cirq = i;
  326. first_irq_flushedto = irq_p;
  327. first_cirq_found = 1;
  328. }
  329. last_fluashed_cirq = i;
  330. last_irq_flushedto = irq_p;
  331. }
  332. }
  333. if (cirq_clone_flush_check_val == 1) {
  334. if (first_cirq_found) {
  335. pr_debug("[CIRQ] The first flush : CIRQ%d to IRQ%d\n",
  336. first_flushed_cirq, first_irq_flushedto);
  337. pr_debug("[CIRQ] The last flush : CIRQ%d to IRQ%d\n",
  338. last_fluashed_cirq, last_irq_flushedto);
  339. } else {
  340. pr_debug
  341. ("[CIRQ] There are no pending interrupt in CIRQ");
  342. pr_debug("so no flush operation happend\n");
  343. }
  344. pr_debug
  345. ("[CIRQ] The Flush Max Range : CIRQ%d to IRQ%d ~ CIRQ%d to IRQ%d\n",
  346. 0, CIRQ_TO_IRQ_NUM(0), CIRQ_IRQ_NUM - 1,
  347. CIRQ_TO_IRQ_NUM(CIRQ_IRQ_NUM - 1));
  348. pr_debug
  349. ("[CIRQ] Flush Check %s, Confirm:SPI_START_OFFSET:%d\n",
  350. pass == 1 ? "Pass" : "Failed", CIRQ_SPI_START);
  351. }
  352. mt_cirq_mask_all();
  353. mt_cirq_ack_all();
  354. return;
  355. }
  356. EXPORT_SYMBOL(mt_cirq_flush);
  357. __attribute__((weak)) u32 mt_irq_get_pol(u32 irq);
  358. /*
  359. * mt_cirq_clone_pol: Copy the polarity setting from GIC to SYS_CIRQ
  360. */
  361. void mt_cirq_clone_pol(void)
  362. {
  363. unsigned int cirq_num, irq_num;
  364. unsigned int st;
  365. unsigned int bit;
  366. for (cirq_num = 0; cirq_num < CIRQ_IRQ_NUM; cirq_num++) {
  367. irq_num = CIRQ_TO_IRQ_NUM(cirq_num);
  368. if (cirq_num == 0 || irq_num % 32 == 0) {
  369. if (mt_irq_get_pol) {
  370. st = mt_irq_get_pol(irq_num);
  371. } else {
  372. st = readl(IOMEM
  373. (INT_POL_CTL0 +
  374. ((irq_num -
  375. GIC_PRIVATE_SIGNALS) / 32 * 4)));
  376. }
  377. }
  378. bit = 0x1 << ((irq_num - GIC_PRIVATE_SIGNALS) % 32);
  379. if (st & bit)
  380. mt_cirq_set_pol(cirq_num, MT_CIRQ_POL_NEG);
  381. else
  382. mt_cirq_set_pol(cirq_num, MT_CIRQ_POL_POS);
  383. }
  384. }
  385. /*
  386. * mt_cirq_clone_sens: Copy the sensitivity setting from GIC to SYS_CIRQ
  387. */
  388. void mt_cirq_clone_sens(void)
  389. {
  390. unsigned int cirq_num, irq_num;
  391. unsigned int st;
  392. unsigned int bit;
  393. for (cirq_num = 0; cirq_num < CIRQ_IRQ_NUM; cirq_num++) {
  394. irq_num = CIRQ_TO_IRQ_NUM(cirq_num);
  395. if (cirq_num == 0 || irq_num % 16 == 0) {
  396. st = readl(IOMEM
  397. (GIC_DIST_BASE + GIC_DIST_CONFIG +
  398. (irq_num / 16 * 4)));
  399. }
  400. bit = 0x2 << ((irq_num % 16) * 2);
  401. if (st & bit)
  402. mt_cirq_set_sens(cirq_num, MT_EDGE_SENSITIVE);
  403. else
  404. mt_cirq_set_sens(cirq_num, MT_LEVEL_SENSITIVE);
  405. }
  406. }
  407. /*
  408. * mt_cirq_clone_mask: Copy the mask setting from GIC to SYS_CIRQ
  409. */
  410. void mt_cirq_clone_mask(void)
  411. {
  412. unsigned int cirq_num, irq_num;
  413. unsigned int st;
  414. unsigned int bit;
  415. for (cirq_num = 0; cirq_num < CIRQ_IRQ_NUM; cirq_num++) {
  416. irq_num = CIRQ_TO_IRQ_NUM(cirq_num);
  417. if (cirq_num == 0 || irq_num % 32 == 0) {
  418. st = readl(IOMEM
  419. (GIC_DIST_BASE + GIC_DIST_ENABLE_SET +
  420. (irq_num / 32 * 4)));
  421. }
  422. bit = 0x1 << (irq_num % 32);
  423. if (st & bit)
  424. mt_cirq_unmask(cirq_num);
  425. else
  426. mt_cirq_mask(cirq_num);
  427. }
  428. }
  429. /*
  430. * mt_cirq_clone_gic: Copy the setting from GIC to SYS_CIRQ
  431. */
  432. void mt_cirq_clone_gic(void)
  433. {
  434. mt_cirq_clone_pol();
  435. mt_cirq_clone_sens();
  436. mt_cirq_clone_mask();
  437. if (cirq_clone_flush_check_val)
  438. mt_cirq_dump_reg();
  439. }
  440. EXPORT_SYMBOL(mt_cirq_clone_gic);
  441. #if defined(LDVT)
  442. /*
  443. * cirq_dvt_show: To show usage.
  444. */
  445. static ssize_t cirq_dvt_show(struct device_driver *driver, char *buf)
  446. {
  447. return snprintf(buf, PAGE_SIZE, "==CIRQ dvt test==\n"
  448. "1.CIRQ dump regs\n"
  449. "2.CIRQ tests\n" "3.CIRQ disable\n");
  450. }
  451. /*
  452. * mci_dvt_store: To select mci test case.
  453. */
  454. static ssize_t cirq_dvt_store(struct device_driver *driver, const char *buf,
  455. size_t count)
  456. {
  457. char *p = (char *)buf;
  458. unsigned long num;
  459. int rc;
  460. rc = kstrtoul(p, 10, (unsigned long *)&num);
  461. switch (num) {
  462. case 1:
  463. mt_cirq_clone_gic();
  464. mt_cirq_dump_reg();
  465. break;
  466. case 2:
  467. mt_cirq_test();
  468. break;
  469. case 3:
  470. mt_cirq_disable();
  471. break;
  472. default:
  473. break;
  474. }
  475. return count;
  476. }
  477. DRIVER_ATTR(cirq_dvt, 0664, cirq_dvt_show, cirq_dvt_store);
  478. #endif
  479. /*
  480. * cirq_clone_flush_check_show:
  481. * To show if we do cirq clone/flush value's check.
  482. */
  483. static ssize_t cirq_clone_flush_check_show(struct device_driver *driver,
  484. char *buf)
  485. {
  486. return snprintf(buf, PAGE_SIZE, "%ld\n",
  487. cirq_clone_flush_check_val);
  488. }
  489. /*
  490. * cirq_clone_flush_check_store:
  491. * set 1 if we need to enable clone/flush value's check
  492. */
  493. static ssize_t cirq_clone_flush_check_store(struct device_driver *driver,
  494. const char *buf, size_t count)
  495. {
  496. char *p = (char *)buf;
  497. unsigned long value;
  498. int rc;
  499. rc = kstrtoul(p, 10, (unsigned long *)&value);
  500. cirq_clone_flush_check_val = value;
  501. return count;
  502. }
  503. DRIVER_ATTR(cirq_clone_flush_check, 0664, cirq_clone_flush_check_show,
  504. cirq_clone_flush_check_store);
  505. /*
  506. * cirq_pattern_clone_flush_check_show:
  507. * To show if we do need to do pattern test.
  508. */
  509. static ssize_t cirq_pattern_clone_flush_check_show(struct device_driver *driver,
  510. char *buf)
  511. {
  512. return snprintf(buf, PAGE_SIZE, "%ld\n",
  513. cirq_pattern_clone_flush_check_val);
  514. }
  515. /*
  516. * cirq_pattern_clone_flush_check_show: set 1 if we need to do pattern test.
  517. */
  518. static ssize_t cirq_pattern_clone_flush_check_store(struct device_driver
  519. *driver, const char *buf,
  520. size_t count)
  521. {
  522. char *p = (char *)buf;
  523. unsigned long value;
  524. int rc;
  525. rc = kstrtoul(p, 10, (unsigned long *)&value);
  526. cirq_pattern_clone_flush_check_val = value;
  527. return count;
  528. }
  529. DRIVER_ATTR(cirq_pattern_clone_flush_check, 0664,
  530. cirq_pattern_clone_flush_check_show,
  531. cirq_pattern_clone_flush_check_store);
  532. /*
  533. * cirq_pattern_clone_flush_check_show:
  534. * To show if we do need to do pattern test.
  535. */
  536. static ssize_t cirq_pattern_list_show(struct device_driver *driver, char *buf)
  537. {
  538. return snprintf(buf, PAGE_SIZE, "%ld\n", cirq_pattern_list);
  539. }
  540. /*
  541. * cirq_pattern_clone_flush_check_show: set 1 if we need to do pattern test.
  542. */
  543. static ssize_t cirq_pattern_list_store(struct device_driver *driver,
  544. const char *buf, size_t count)
  545. {
  546. char *p = (char *)buf;
  547. unsigned long value;
  548. int rc;
  549. rc = kstrtoul(p, 10, (unsigned long *)&value);
  550. cirq_pattern_list = value;
  551. return count;
  552. }
  553. DRIVER_ATTR(cirq_pattern_list, 0664, cirq_pattern_list_show,
  554. cirq_pattern_list_store);
  555. #if defined(__CHECK_IRQ_TYPE)
  556. #define X_DEFINE_IRQ(__name, __num, __polarity, __sensitivity) \
  557. { .num = __num, .polarity = __polarity, .sensitivity = __sensitivity, },
  558. #define L 0
  559. #define H 1
  560. #define EDGE MT_EDGE_SENSITIVE
  561. #define LEVEL MT_LEVEL_SENSITIVE
  562. struct __check_irq_type {
  563. int num;
  564. int polarity;
  565. int sensitivity;
  566. };
  567. #undef __X_DEFINE_IRQ
  568. struct __check_irq_type __check_irq_type[] = {
  569. #include <mach/x_define_irq.h>
  570. {.num = -1,},
  571. };
  572. #undef X_DEFINE_IRQ
  573. #undef L
  574. #undef H
  575. #undef EDGE
  576. #undef LEVEL
  577. #endif
  578. void mt_cirq_dump_reg(void)
  579. {
  580. int cirq_num;
  581. int pol, sens, mask;
  582. #if defined(__CHECK_IRQ_TYPE)
  583. int irq_iter;
  584. unsigned char pass = 1;
  585. #endif
  586. pr_debug("[CIRQ] IRQ:\tPOL\tSENS\tMASK\n");
  587. for (cirq_num = 0; cirq_num < CIRQ_IRQ_NUM; cirq_num++) {
  588. pol = mt_cirq_get_pol(cirq_num);
  589. sens = mt_cirq_get_sens(cirq_num);
  590. mask = mt_cirq_get_mask(cirq_num);
  591. #if defined(__CHECK_IRQ_TYPE)
  592. if (mask == 0) {
  593. pr_debug("[CIRQ] IRQ:%d\t%d\t%d\t%d\n",
  594. CIRQ_TO_IRQ_NUM(cirq_num), pol, sens, mask);
  595. irq_iter = cirq_num + 32;
  596. if (__check_irq_type[irq_iter].num ==
  597. CIRQ_TO_IRQ_NUM(cirq_num)) {
  598. if (__check_irq_type[irq_iter].sensitivity !=
  599. sens) {
  600. pr_debug
  601. ("[CIRQ] Error sens in irq:%d\n",
  602. __check_irq_type[irq_iter].num);
  603. pass = 0;
  604. }
  605. if (__check_irq_type[irq_iter].polarity
  606. != pol) {
  607. pr_debug
  608. ("[CIRQ]Err polarity in irq:%d\n",
  609. __check_irq_type[irq_iter].num);
  610. pass = 0;
  611. }
  612. } else {
  613. pr_err
  614. ("[CIRQ] Error CIRQ num %d",
  615. __check_irq_type[irq_iter].num);
  616. pr_err("Mapping to wrong GIC num %d\n",
  617. CIRQ_TO_IRQ_NUM(cirq_num));
  618. pass = 0;
  619. }
  620. }
  621. #endif
  622. }
  623. #if defined __CHECK_IRQ_TYPE
  624. pr_debug("[CIRQ] CIRQ Clone To GIC Verfication %s !\n",
  625. pass == 1 ? "Pass" : "Failed");
  626. #else
  627. pr_debug
  628. ("[CIRQ] Plz enable __CHECK_IRQ_TYE");
  629. pr_debug("and update x_define.h for enable CIRQ Clone checking\n");
  630. #endif
  631. }
  632. #ifdef LDVT
  633. int mt_cirq_test(void)
  634. {
  635. int cirq_num = 126;
  636. /*test polarity */
  637. mt_cirq_set_pol(cirq_num, MT_CIRQ_POL_NEG);
  638. if (mt_cirq_get_pol(cirq_num) != MT_CIRQ_POL_NEG)
  639. pr_debug("[CIRQ] mt_cirq_set_pol clear test failed!!\n");
  640. else
  641. pr_debug("[CIRQ] mt_cirq_set_pol clear test passed!!\n");
  642. mt_cirq_set_pol(cirq_num, MT_CIRQ_POL_POS);
  643. if (mt_cirq_get_pol(cirq_num) != MT_CIRQ_POL_POS)
  644. pr_debug("[CIRQ] mt_cirq_set_pol set test failed!!\n");
  645. else
  646. pr_debug("[CIRQ] mt_cirq_set_pol set test passed!!\n");
  647. /*test sensitivity */
  648. mt_cirq_set_sens(cirq_num, MT_EDGE_SENSITIVE);
  649. if (mt_cirq_get_sens(cirq_num) != MT_EDGE_SENSITIVE)
  650. pr_debug("[CIRQ] mt_cirq_set_sens clear test failed!!\n");
  651. else
  652. pr_debug("[CIRQ] mt_cirq_set_sens clear test passed!!\n");
  653. mt_cirq_set_sens(cirq_num, MT_LEVEL_SENSITIVE);
  654. if (mt_cirq_get_sens(cirq_num) != MT_LEVEL_SENSITIVE)
  655. pr_debug("[CIRQ] mt_cirq_set_sens set test failed!!\n");
  656. else
  657. pr_debug("[CIRQ] mt_cirq_set_sens set test passed!!\n");
  658. /*test mask */
  659. mt_cirq_mask(cirq_num);
  660. if (mt_cirq_get_mask(cirq_num) != 1)
  661. pr_debug("[CIRQ] mt_cirq_mask test failed!!\n");
  662. else
  663. pr_debug("[CIRQ] mt_cirq_mask test passed!!\n");
  664. mt_cirq_unmask(cirq_num);
  665. if (mt_cirq_get_mask(cirq_num) != 0)
  666. pr_debug("[CIRQ] mt_cirq_unmask test failed!!\n");
  667. else
  668. pr_debug("[CIRQ] mt_cirq_unmask test passed!!\n");
  669. mt_cirq_clone_gic();
  670. mt_cirq_dump_reg();
  671. return 0;
  672. }
  673. #endif
  674. /*
  675. * cirq_irq_handler: SYS_CIRQ interrupt service routine.
  676. */
  677. static irqreturn_t cirq_irq_handler(int irq, void *dev_id)
  678. {
  679. pr_debug("[CIRQ] CIRQ_Handler\n");
  680. mt_cirq_ack_all();
  681. return IRQ_HANDLED;
  682. }
  683. /*
  684. * mt_cirq_init: SYS_CIRQ init function
  685. * always return 0
  686. */
  687. int __init mt_cirq_init(void)
  688. {
  689. int ret;
  690. #ifdef CONFIG_OF
  691. struct device_node *node;
  692. unsigned int sys_cirq_num = 0;
  693. #endif
  694. pr_debug("[CIRQ] CIRQ init...\n");
  695. #ifdef CONFIG_OF
  696. node = of_find_compatible_node(NULL, NULL, "mediatek,mt6735-sys_cirq");
  697. if (!node) {
  698. pr_debug("[CIRQ] find SYS_CIRQ node failed!!!\n");
  699. return -1;
  700. }
  701. SYS_CIRQ_BASE = of_iomap(node, 0);
  702. pr_debug("[CIRQ] SYS_CIRQ_BASE = 0x%p\n", SYS_CIRQ_BASE);
  703. WARN(!SYS_CIRQ_BASE,
  704. "[CIRQ] unable to map SYS_CIRQ base registers!!!\n");
  705. if (of_property_read_u32(node, "mediatek,cirq_num", &CIRQ_IRQ_NUM))
  706. return -1;
  707. pr_debug("[CIRQ] cirq_num = %d\n", CIRQ_IRQ_NUM);
  708. if (of_property_read_u32(node, "mediatek,spi_start_offset",
  709. &CIRQ_SPI_START))
  710. return -1;
  711. pr_debug("[CIRQ] spi_start_offset = %d\n", CIRQ_SPI_START);
  712. sys_cirq_num = irq_of_parse_and_map(node, 0);
  713. pr_debug("[CIRQ] sys_cirq_num = %d\n", sys_cirq_num);
  714. #endif
  715. #ifdef CONFIG_OF
  716. ret =
  717. request_irq(sys_cirq_num, cirq_irq_handler, IRQF_TRIGGER_NONE,
  718. "CIRQ", NULL);
  719. #else
  720. ret =
  721. request_irq(SYS_CIRQ_IRQ_BIT_ID, cirq_irq_handler,
  722. IRQF_TRIGGER_LOW, "CIRQ", NULL);
  723. #endif
  724. if (ret > 0)
  725. pr_err("[CIRQ] CIRQ IRQ LINE NOT AVAILABLE!!\n");
  726. else
  727. pr_debug("[CIRQ] CIRQ handler init success.\n");
  728. ret = platform_driver_register(&mt_cirq_drv.driver);
  729. if (ret == 0)
  730. pr_debug("[CIRQ] CIRQ init done...\n");
  731. #ifdef LDVT
  732. ret = driver_create_file(&mt_cirq_drv.driver.driver,
  733. &driver_attr_cirq_dvt);
  734. if (ret == 0)
  735. pr_debug("[CIRQ] CIRQ create sysfs file for dvt done...\n");
  736. #endif
  737. ret = driver_create_file(&mt_cirq_drv.driver.driver,
  738. &driver_attr_cirq_clone_flush_check);
  739. if (ret == 0)
  740. pr_debug
  741. ("[CIRQ] sysfs file for cirq clone flush check done...\n");
  742. ret = driver_create_file(&mt_cirq_drv.driver.driver,
  743. &driver_attr_cirq_pattern_clone_flush_check);
  744. if (ret == 0)
  745. pr_debug
  746. ("[CIRQ] sysfs file for pattern clone flush check done...\n");
  747. cirq_pattern_list = CIRQ_IRQ_NUM;
  748. ret = driver_create_file(&mt_cirq_drv.driver.driver,
  749. &driver_attr_cirq_pattern_list);
  750. if (ret == 0)
  751. pr_debug
  752. ("[CIRQ] CIRQ create sysfs file for pattern list setup...\n");
  753. pr_warn("### CIRQ init done. ###\n");
  754. return 0;
  755. }
  756. arch_initcall(mt_cirq_init);