access.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /*
  2. * Common INTC2 register accessors
  3. *
  4. * Copyright (C) 2007, 2008 Magnus Damm
  5. * Copyright (C) 2009, 2010 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/io.h>
  12. #include "internals.h"
  13. unsigned long intc_phys_to_virt(struct intc_desc_int *d, unsigned long address)
  14. {
  15. struct intc_window *window;
  16. int k;
  17. /* scan through physical windows and convert address */
  18. for (k = 0; k < d->nr_windows; k++) {
  19. window = d->window + k;
  20. if (address < window->phys)
  21. continue;
  22. if (address >= (window->phys + window->size))
  23. continue;
  24. address -= window->phys;
  25. address += (unsigned long)window->virt;
  26. return address;
  27. }
  28. /* no windows defined, register must be 1:1 mapped virt:phys */
  29. return address;
  30. }
  31. unsigned int intc_get_reg(struct intc_desc_int *d, unsigned long address)
  32. {
  33. unsigned int k;
  34. address = intc_phys_to_virt(d, address);
  35. for (k = 0; k < d->nr_reg; k++) {
  36. if (d->reg[k] == address)
  37. return k;
  38. }
  39. BUG();
  40. return 0;
  41. }
  42. unsigned int intc_set_field_from_handle(unsigned int value,
  43. unsigned int field_value,
  44. unsigned int handle)
  45. {
  46. unsigned int width = _INTC_WIDTH(handle);
  47. unsigned int shift = _INTC_SHIFT(handle);
  48. value &= ~(((1 << width) - 1) << shift);
  49. value |= field_value << shift;
  50. return value;
  51. }
  52. unsigned long intc_get_field_from_handle(unsigned int value, unsigned int handle)
  53. {
  54. unsigned int width = _INTC_WIDTH(handle);
  55. unsigned int shift = _INTC_SHIFT(handle);
  56. unsigned int mask = ((1 << width) - 1) << shift;
  57. return (value & mask) >> shift;
  58. }
  59. static unsigned long test_8(unsigned long addr, unsigned long h,
  60. unsigned long ignore)
  61. {
  62. return intc_get_field_from_handle(__raw_readb(addr), h);
  63. }
  64. static unsigned long test_16(unsigned long addr, unsigned long h,
  65. unsigned long ignore)
  66. {
  67. return intc_get_field_from_handle(__raw_readw(addr), h);
  68. }
  69. static unsigned long test_32(unsigned long addr, unsigned long h,
  70. unsigned long ignore)
  71. {
  72. return intc_get_field_from_handle(__raw_readl(addr), h);
  73. }
  74. static unsigned long write_8(unsigned long addr, unsigned long h,
  75. unsigned long data)
  76. {
  77. __raw_writeb(intc_set_field_from_handle(0, data, h), addr);
  78. (void)__raw_readb(addr); /* Defeat write posting */
  79. return 0;
  80. }
  81. static unsigned long write_16(unsigned long addr, unsigned long h,
  82. unsigned long data)
  83. {
  84. __raw_writew(intc_set_field_from_handle(0, data, h), addr);
  85. (void)__raw_readw(addr); /* Defeat write posting */
  86. return 0;
  87. }
  88. static unsigned long write_32(unsigned long addr, unsigned long h,
  89. unsigned long data)
  90. {
  91. __raw_writel(intc_set_field_from_handle(0, data, h), addr);
  92. (void)__raw_readl(addr); /* Defeat write posting */
  93. return 0;
  94. }
  95. static unsigned long modify_8(unsigned long addr, unsigned long h,
  96. unsigned long data)
  97. {
  98. unsigned long flags;
  99. unsigned int value;
  100. local_irq_save(flags);
  101. value = intc_set_field_from_handle(__raw_readb(addr), data, h);
  102. __raw_writeb(value, addr);
  103. (void)__raw_readb(addr); /* Defeat write posting */
  104. local_irq_restore(flags);
  105. return 0;
  106. }
  107. static unsigned long modify_16(unsigned long addr, unsigned long h,
  108. unsigned long data)
  109. {
  110. unsigned long flags;
  111. unsigned int value;
  112. local_irq_save(flags);
  113. value = intc_set_field_from_handle(__raw_readw(addr), data, h);
  114. __raw_writew(value, addr);
  115. (void)__raw_readw(addr); /* Defeat write posting */
  116. local_irq_restore(flags);
  117. return 0;
  118. }
  119. static unsigned long modify_32(unsigned long addr, unsigned long h,
  120. unsigned long data)
  121. {
  122. unsigned long flags;
  123. unsigned int value;
  124. local_irq_save(flags);
  125. value = intc_set_field_from_handle(__raw_readl(addr), data, h);
  126. __raw_writel(value, addr);
  127. (void)__raw_readl(addr); /* Defeat write posting */
  128. local_irq_restore(flags);
  129. return 0;
  130. }
  131. static unsigned long intc_mode_field(unsigned long addr,
  132. unsigned long handle,
  133. unsigned long (*fn)(unsigned long,
  134. unsigned long,
  135. unsigned long),
  136. unsigned int irq)
  137. {
  138. return fn(addr, handle, ((1 << _INTC_WIDTH(handle)) - 1));
  139. }
  140. static unsigned long intc_mode_zero(unsigned long addr,
  141. unsigned long handle,
  142. unsigned long (*fn)(unsigned long,
  143. unsigned long,
  144. unsigned long),
  145. unsigned int irq)
  146. {
  147. return fn(addr, handle, 0);
  148. }
  149. static unsigned long intc_mode_prio(unsigned long addr,
  150. unsigned long handle,
  151. unsigned long (*fn)(unsigned long,
  152. unsigned long,
  153. unsigned long),
  154. unsigned int irq)
  155. {
  156. return fn(addr, handle, intc_get_prio_level(irq));
  157. }
  158. unsigned long (*intc_reg_fns[])(unsigned long addr,
  159. unsigned long h,
  160. unsigned long data) = {
  161. [REG_FN_TEST_BASE + 0] = test_8,
  162. [REG_FN_TEST_BASE + 1] = test_16,
  163. [REG_FN_TEST_BASE + 3] = test_32,
  164. [REG_FN_WRITE_BASE + 0] = write_8,
  165. [REG_FN_WRITE_BASE + 1] = write_16,
  166. [REG_FN_WRITE_BASE + 3] = write_32,
  167. [REG_FN_MODIFY_BASE + 0] = modify_8,
  168. [REG_FN_MODIFY_BASE + 1] = modify_16,
  169. [REG_FN_MODIFY_BASE + 3] = modify_32,
  170. };
  171. unsigned long (*intc_enable_fns[])(unsigned long addr,
  172. unsigned long handle,
  173. unsigned long (*fn)(unsigned long,
  174. unsigned long,
  175. unsigned long),
  176. unsigned int irq) = {
  177. [MODE_ENABLE_REG] = intc_mode_field,
  178. [MODE_MASK_REG] = intc_mode_zero,
  179. [MODE_DUAL_REG] = intc_mode_field,
  180. [MODE_PRIO_REG] = intc_mode_prio,
  181. [MODE_PCLR_REG] = intc_mode_prio,
  182. };
  183. unsigned long (*intc_disable_fns[])(unsigned long addr,
  184. unsigned long handle,
  185. unsigned long (*fn)(unsigned long,
  186. unsigned long,
  187. unsigned long),
  188. unsigned int irq) = {
  189. [MODE_ENABLE_REG] = intc_mode_zero,
  190. [MODE_MASK_REG] = intc_mode_field,
  191. [MODE_DUAL_REG] = intc_mode_field,
  192. [MODE_PRIO_REG] = intc_mode_zero,
  193. [MODE_PCLR_REG] = intc_mode_field,
  194. };
  195. unsigned long (*intc_enable_noprio_fns[])(unsigned long addr,
  196. unsigned long handle,
  197. unsigned long (*fn)(unsigned long,
  198. unsigned long,
  199. unsigned long),
  200. unsigned int irq) = {
  201. [MODE_ENABLE_REG] = intc_mode_field,
  202. [MODE_MASK_REG] = intc_mode_zero,
  203. [MODE_DUAL_REG] = intc_mode_field,
  204. [MODE_PRIO_REG] = intc_mode_field,
  205. [MODE_PCLR_REG] = intc_mode_field,
  206. };