chip.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /*
  2. * IRQ chip definitions for INTC IRQs.
  3. *
  4. * Copyright (C) 2007, 2008 Magnus Damm
  5. * Copyright (C) 2009 - 2012 Paul Mundt
  6. *
  7. * This file is subject to the terms and conditions of the GNU General Public
  8. * License. See the file "COPYING" in the main directory of this archive
  9. * for more details.
  10. */
  11. #include <linux/cpumask.h>
  12. #include <linux/bsearch.h>
  13. #include <linux/io.h>
  14. #include "internals.h"
  15. void _intc_enable(struct irq_data *data, unsigned long handle)
  16. {
  17. unsigned int irq = data->irq;
  18. struct intc_desc_int *d = get_intc_desc(irq);
  19. unsigned long addr;
  20. unsigned int cpu;
  21. for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
  22. #ifdef CONFIG_SMP
  23. if (!cpumask_test_cpu(cpu, irq_data_get_affinity_mask(data)))
  24. continue;
  25. #endif
  26. addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
  27. intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\
  28. [_INTC_FN(handle)], irq);
  29. }
  30. intc_balancing_enable(irq);
  31. }
  32. static void intc_enable(struct irq_data *data)
  33. {
  34. _intc_enable(data, (unsigned long)irq_data_get_irq_chip_data(data));
  35. }
  36. static void intc_disable(struct irq_data *data)
  37. {
  38. unsigned int irq = data->irq;
  39. struct intc_desc_int *d = get_intc_desc(irq);
  40. unsigned long handle = (unsigned long)irq_data_get_irq_chip_data(data);
  41. unsigned long addr;
  42. unsigned int cpu;
  43. intc_balancing_disable(irq);
  44. for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
  45. #ifdef CONFIG_SMP
  46. if (!cpumask_test_cpu(cpu, irq_data_get_affinity_mask(data)))
  47. continue;
  48. #endif
  49. addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
  50. intc_disable_fns[_INTC_MODE(handle)](addr, handle,intc_reg_fns\
  51. [_INTC_FN(handle)], irq);
  52. }
  53. }
  54. #ifdef CONFIG_SMP
  55. /*
  56. * This is held with the irq desc lock held, so we don't require any
  57. * additional locking here at the intc desc level. The affinity mask is
  58. * later tested in the enable/disable paths.
  59. */
  60. static int intc_set_affinity(struct irq_data *data,
  61. const struct cpumask *cpumask,
  62. bool force)
  63. {
  64. if (!cpumask_intersects(cpumask, cpu_online_mask))
  65. return -1;
  66. cpumask_copy(irq_data_get_affinity_mask(data), cpumask);
  67. return IRQ_SET_MASK_OK_NOCOPY;
  68. }
  69. #endif
  70. static void intc_mask_ack(struct irq_data *data)
  71. {
  72. unsigned int irq = data->irq;
  73. struct intc_desc_int *d = get_intc_desc(irq);
  74. unsigned long handle = intc_get_ack_handle(irq);
  75. void __iomem *addr;
  76. intc_disable(data);
  77. /* read register and write zero only to the associated bit */
  78. if (handle) {
  79. unsigned int value;
  80. addr = (void __iomem *)INTC_REG(d, _INTC_ADDR_D(handle), 0);
  81. value = intc_set_field_from_handle(0, 1, handle);
  82. switch (_INTC_FN(handle)) {
  83. case REG_FN_MODIFY_BASE + 0: /* 8bit */
  84. __raw_readb(addr);
  85. __raw_writeb(0xff ^ value, addr);
  86. break;
  87. case REG_FN_MODIFY_BASE + 1: /* 16bit */
  88. __raw_readw(addr);
  89. __raw_writew(0xffff ^ value, addr);
  90. break;
  91. case REG_FN_MODIFY_BASE + 3: /* 32bit */
  92. __raw_readl(addr);
  93. __raw_writel(0xffffffff ^ value, addr);
  94. break;
  95. default:
  96. BUG();
  97. break;
  98. }
  99. }
  100. }
  101. static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
  102. unsigned int nr_hp,
  103. unsigned int irq)
  104. {
  105. struct intc_handle_int key;
  106. key.irq = irq;
  107. key.handle = 0;
  108. return bsearch(&key, hp, nr_hp, sizeof(*hp), intc_handle_int_cmp);
  109. }
  110. int intc_set_priority(unsigned int irq, unsigned int prio)
  111. {
  112. struct intc_desc_int *d = get_intc_desc(irq);
  113. struct irq_data *data = irq_get_irq_data(irq);
  114. struct intc_handle_int *ihp;
  115. if (!intc_get_prio_level(irq) || prio <= 1)
  116. return -EINVAL;
  117. ihp = intc_find_irq(d->prio, d->nr_prio, irq);
  118. if (ihp) {
  119. if (prio >= (1 << _INTC_WIDTH(ihp->handle)))
  120. return -EINVAL;
  121. intc_set_prio_level(irq, prio);
  122. /*
  123. * only set secondary masking method directly
  124. * primary masking method is using intc_prio_level[irq]
  125. * priority level will be set during next enable()
  126. */
  127. if (_INTC_FN(ihp->handle) != REG_FN_ERR)
  128. _intc_enable(data, ihp->handle);
  129. }
  130. return 0;
  131. }
  132. #define SENSE_VALID_FLAG 0x80
  133. #define VALID(x) (x | SENSE_VALID_FLAG)
  134. static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
  135. [IRQ_TYPE_EDGE_FALLING] = VALID(0),
  136. [IRQ_TYPE_EDGE_RISING] = VALID(1),
  137. [IRQ_TYPE_LEVEL_LOW] = VALID(2),
  138. /* SH7706, SH7707 and SH7709 do not support high level triggered */
  139. #if !defined(CONFIG_CPU_SUBTYPE_SH7706) && \
  140. !defined(CONFIG_CPU_SUBTYPE_SH7707) && \
  141. !defined(CONFIG_CPU_SUBTYPE_SH7709)
  142. [IRQ_TYPE_LEVEL_HIGH] = VALID(3),
  143. #endif
  144. #if defined(CONFIG_ARM) /* all recent SH-Mobile / R-Mobile ARM support this */
  145. [IRQ_TYPE_EDGE_BOTH] = VALID(4),
  146. #endif
  147. };
  148. static int intc_set_type(struct irq_data *data, unsigned int type)
  149. {
  150. unsigned int irq = data->irq;
  151. struct intc_desc_int *d = get_intc_desc(irq);
  152. unsigned char value = intc_irq_sense_table[type & IRQ_TYPE_SENSE_MASK];
  153. struct intc_handle_int *ihp;
  154. unsigned long addr;
  155. if (!value)
  156. return -EINVAL;
  157. value &= ~SENSE_VALID_FLAG;
  158. ihp = intc_find_irq(d->sense, d->nr_sense, irq);
  159. if (ihp) {
  160. /* PINT has 2-bit sense registers, should fail on EDGE_BOTH */
  161. if (value >= (1 << _INTC_WIDTH(ihp->handle)))
  162. return -EINVAL;
  163. addr = INTC_REG(d, _INTC_ADDR_E(ihp->handle), 0);
  164. intc_reg_fns[_INTC_FN(ihp->handle)](addr, ihp->handle, value);
  165. }
  166. return 0;
  167. }
  168. struct irq_chip intc_irq_chip = {
  169. .irq_mask = intc_disable,
  170. .irq_unmask = intc_enable,
  171. .irq_mask_ack = intc_mask_ack,
  172. .irq_enable = intc_enable,
  173. .irq_disable = intc_disable,
  174. .irq_set_type = intc_set_type,
  175. #ifdef CONFIG_SMP
  176. .irq_set_affinity = intc_set_affinity,
  177. #endif
  178. .flags = IRQCHIP_SKIP_SET_WAKE,
  179. };