access.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  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. void __iomem *ptr = (void __iomem *)addr;
  63. return intc_get_field_from_handle(__raw_readb(ptr), h);
  64. }
  65. static unsigned long test_16(unsigned long addr, unsigned long h,
  66. unsigned long ignore)
  67. {
  68. void __iomem *ptr = (void __iomem *)addr;
  69. return intc_get_field_from_handle(__raw_readw(ptr), h);
  70. }
  71. static unsigned long test_32(unsigned long addr, unsigned long h,
  72. unsigned long ignore)
  73. {
  74. void __iomem *ptr = (void __iomem *)addr;
  75. return intc_get_field_from_handle(__raw_readl(ptr), h);
  76. }
  77. static unsigned long write_8(unsigned long addr, unsigned long h,
  78. unsigned long data)
  79. {
  80. void __iomem *ptr = (void __iomem *)addr;
  81. __raw_writeb(intc_set_field_from_handle(0, data, h), ptr);
  82. (void)__raw_readb(ptr); /* Defeat write posting */
  83. return 0;
  84. }
  85. static unsigned long write_16(unsigned long addr, unsigned long h,
  86. unsigned long data)
  87. {
  88. void __iomem *ptr = (void __iomem *)addr;
  89. __raw_writew(intc_set_field_from_handle(0, data, h), ptr);
  90. (void)__raw_readw(ptr); /* Defeat write posting */
  91. return 0;
  92. }
  93. static unsigned long write_32(unsigned long addr, unsigned long h,
  94. unsigned long data)
  95. {
  96. void __iomem *ptr = (void __iomem *)addr;
  97. __raw_writel(intc_set_field_from_handle(0, data, h), ptr);
  98. (void)__raw_readl(ptr); /* Defeat write posting */
  99. return 0;
  100. }
  101. static unsigned long modify_8(unsigned long addr, unsigned long h,
  102. unsigned long data)
  103. {
  104. void __iomem *ptr = (void __iomem *)addr;
  105. unsigned long flags;
  106. unsigned int value;
  107. local_irq_save(flags);
  108. value = intc_set_field_from_handle(__raw_readb(ptr), data, h);
  109. __raw_writeb(value, ptr);
  110. (void)__raw_readb(ptr); /* Defeat write posting */
  111. local_irq_restore(flags);
  112. return 0;
  113. }
  114. static unsigned long modify_16(unsigned long addr, unsigned long h,
  115. unsigned long data)
  116. {
  117. void __iomem *ptr = (void __iomem *)addr;
  118. unsigned long flags;
  119. unsigned int value;
  120. local_irq_save(flags);
  121. value = intc_set_field_from_handle(__raw_readw(ptr), data, h);
  122. __raw_writew(value, ptr);
  123. (void)__raw_readw(ptr); /* Defeat write posting */
  124. local_irq_restore(flags);
  125. return 0;
  126. }
  127. static unsigned long modify_32(unsigned long addr, unsigned long h,
  128. unsigned long data)
  129. {
  130. void __iomem *ptr = (void __iomem *)addr;
  131. unsigned long flags;
  132. unsigned int value;
  133. local_irq_save(flags);
  134. value = intc_set_field_from_handle(__raw_readl(ptr), data, h);
  135. __raw_writel(value, ptr);
  136. (void)__raw_readl(ptr); /* Defeat write posting */
  137. local_irq_restore(flags);
  138. return 0;
  139. }
  140. static unsigned long intc_mode_field(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, ((1 << _INTC_WIDTH(handle)) - 1));
  148. }
  149. static unsigned long intc_mode_zero(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, 0);
  157. }
  158. static unsigned long intc_mode_prio(unsigned long addr,
  159. unsigned long handle,
  160. unsigned long (*fn)(unsigned long,
  161. unsigned long,
  162. unsigned long),
  163. unsigned int irq)
  164. {
  165. return fn(addr, handle, intc_get_prio_level(irq));
  166. }
  167. unsigned long (*intc_reg_fns[])(unsigned long addr,
  168. unsigned long h,
  169. unsigned long data) = {
  170. [REG_FN_TEST_BASE + 0] = test_8,
  171. [REG_FN_TEST_BASE + 1] = test_16,
  172. [REG_FN_TEST_BASE + 3] = test_32,
  173. [REG_FN_WRITE_BASE + 0] = write_8,
  174. [REG_FN_WRITE_BASE + 1] = write_16,
  175. [REG_FN_WRITE_BASE + 3] = write_32,
  176. [REG_FN_MODIFY_BASE + 0] = modify_8,
  177. [REG_FN_MODIFY_BASE + 1] = modify_16,
  178. [REG_FN_MODIFY_BASE + 3] = modify_32,
  179. };
  180. unsigned long (*intc_enable_fns[])(unsigned long addr,
  181. unsigned long handle,
  182. unsigned long (*fn)(unsigned long,
  183. unsigned long,
  184. unsigned long),
  185. unsigned int irq) = {
  186. [MODE_ENABLE_REG] = intc_mode_field,
  187. [MODE_MASK_REG] = intc_mode_zero,
  188. [MODE_DUAL_REG] = intc_mode_field,
  189. [MODE_PRIO_REG] = intc_mode_prio,
  190. [MODE_PCLR_REG] = intc_mode_prio,
  191. };
  192. unsigned long (*intc_disable_fns[])(unsigned long addr,
  193. unsigned long handle,
  194. unsigned long (*fn)(unsigned long,
  195. unsigned long,
  196. unsigned long),
  197. unsigned int irq) = {
  198. [MODE_ENABLE_REG] = intc_mode_zero,
  199. [MODE_MASK_REG] = intc_mode_field,
  200. [MODE_DUAL_REG] = intc_mode_field,
  201. [MODE_PRIO_REG] = intc_mode_zero,
  202. [MODE_PCLR_REG] = intc_mode_field,
  203. };
  204. unsigned long (*intc_enable_noprio_fns[])(unsigned long addr,
  205. unsigned long handle,
  206. unsigned long (*fn)(unsigned long,
  207. unsigned long,
  208. unsigned long),
  209. unsigned int irq) = {
  210. [MODE_ENABLE_REG] = intc_mode_field,
  211. [MODE_MASK_REG] = intc_mode_zero,
  212. [MODE_DUAL_REG] = intc_mode_field,
  213. [MODE_PRIO_REG] = intc_mode_field,
  214. [MODE_PCLR_REG] = intc_mode_field,
  215. };