Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
access.c
Go to the documentation of this file.
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 
14 unsigned long intc_phys_to_virt(struct intc_desc_int *d, unsigned long address)
15 {
16  struct intc_window *window;
17  int k;
18 
19  /* scan through physical windows and convert address */
20  for (k = 0; k < d->nr_windows; k++) {
21  window = d->window + k;
22 
24  continue;
25 
26  if (address >= (window->phys + window->size))
27  continue;
28 
29  address -= window->phys;
30  address += (unsigned long)window->virt;
31 
32  return address;
33  }
34 
35  /* no windows defined, register must be 1:1 mapped virt:phys */
36  return address;
37 }
38 
39 unsigned int intc_get_reg(struct intc_desc_int *d, unsigned long address)
40 {
41  unsigned int k;
42 
43  address = intc_phys_to_virt(d, address);
44 
45  for (k = 0; k < d->nr_reg; k++) {
46  if (d->reg[k] == address)
47  return k;
48  }
49 
50  BUG();
51  return 0;
52 }
53 
54 unsigned int intc_set_field_from_handle(unsigned int value,
55  unsigned int field_value,
56  unsigned int handle)
57 {
58  unsigned int width = _INTC_WIDTH(handle);
59  unsigned int shift = _INTC_SHIFT(handle);
60 
61  value &= ~(((1 << width) - 1) << shift);
62  value |= field_value << shift;
63  return value;
64 }
65 
66 unsigned long intc_get_field_from_handle(unsigned int value, unsigned int handle)
67 {
68  unsigned int width = _INTC_WIDTH(handle);
69  unsigned int shift = _INTC_SHIFT(handle);
70  unsigned int mask = ((1 << width) - 1) << shift;
71 
72  return (value & mask) >> shift;
73 }
74 
75 static unsigned long test_8(unsigned long addr, unsigned long h,
76  unsigned long ignore)
77 {
78  void __iomem *ptr = (void __iomem *)addr;
80 }
81 
82 static unsigned long test_16(unsigned long addr, unsigned long h,
83  unsigned long ignore)
84 {
85  void __iomem *ptr = (void __iomem *)addr;
87 }
88 
89 static unsigned long test_32(unsigned long addr, unsigned long h,
90  unsigned long ignore)
91 {
92  void __iomem *ptr = (void __iomem *)addr;
94 }
95 
96 static unsigned long write_8(unsigned long addr, unsigned long h,
97  unsigned long data)
98 {
99  void __iomem *ptr = (void __iomem *)addr;
100  __raw_writeb(intc_set_field_from_handle(0, data, h), ptr);
101  (void)__raw_readb(ptr); /* Defeat write posting */
102  return 0;
103 }
104 
105 static unsigned long write_16(unsigned long addr, unsigned long h,
106  unsigned long data)
107 {
108  void __iomem *ptr = (void __iomem *)addr;
109  __raw_writew(intc_set_field_from_handle(0, data, h), ptr);
110  (void)__raw_readw(ptr); /* Defeat write posting */
111  return 0;
112 }
113 
114 static unsigned long write_32(unsigned long addr, unsigned long h,
115  unsigned long data)
116 {
117  void __iomem *ptr = (void __iomem *)addr;
118  __raw_writel(intc_set_field_from_handle(0, data, h), ptr);
119  (void)__raw_readl(ptr); /* Defeat write posting */
120  return 0;
121 }
122 
123 static unsigned long modify_8(unsigned long addr, unsigned long h,
124  unsigned long data)
125 {
126  void __iomem *ptr = (void __iomem *)addr;
127  unsigned long flags;
128  unsigned int value;
129  local_irq_save(flags);
130  value = intc_set_field_from_handle(__raw_readb(ptr), data, h);
131  __raw_writeb(value, ptr);
132  (void)__raw_readb(ptr); /* Defeat write posting */
133  local_irq_restore(flags);
134  return 0;
135 }
136 
137 static unsigned long modify_16(unsigned long addr, unsigned long h,
138  unsigned long data)
139 {
140  void __iomem *ptr = (void __iomem *)addr;
141  unsigned long flags;
142  unsigned int value;
143  local_irq_save(flags);
144  value = intc_set_field_from_handle(__raw_readw(ptr), data, h);
145  __raw_writew(value, ptr);
146  (void)__raw_readw(ptr); /* Defeat write posting */
147  local_irq_restore(flags);
148  return 0;
149 }
150 
151 static unsigned long modify_32(unsigned long addr, unsigned long h,
152  unsigned long data)
153 {
154  void __iomem *ptr = (void __iomem *)addr;
155  unsigned long flags;
156  unsigned int value;
157  local_irq_save(flags);
158  value = intc_set_field_from_handle(__raw_readl(ptr), data, h);
159  __raw_writel(value, ptr);
160  (void)__raw_readl(ptr); /* Defeat write posting */
161  local_irq_restore(flags);
162  return 0;
163 }
164 
165 static unsigned long intc_mode_field(unsigned long addr,
166  unsigned long handle,
167  unsigned long (*fn)(unsigned long,
168  unsigned long,
169  unsigned long),
170  unsigned int irq)
171 {
172  return fn(addr, handle, ((1 << _INTC_WIDTH(handle)) - 1));
173 }
174 
175 static unsigned long intc_mode_zero(unsigned long addr,
176  unsigned long handle,
177  unsigned long (*fn)(unsigned long,
178  unsigned long,
179  unsigned long),
180  unsigned int irq)
181 {
182  return fn(addr, handle, 0);
183 }
184 
185 static unsigned long intc_mode_prio(unsigned long addr,
186  unsigned long handle,
187  unsigned long (*fn)(unsigned long,
188  unsigned long,
189  unsigned long),
190  unsigned int irq)
191 {
192  return fn(addr, handle, intc_get_prio_level(irq));
193 }
194 
195 unsigned long (*intc_reg_fns[])(unsigned long addr,
196  unsigned long h,
197  unsigned long data) = {
198  [REG_FN_TEST_BASE + 0] = test_8,
199  [REG_FN_TEST_BASE + 1] = test_16,
200  [REG_FN_TEST_BASE + 3] = test_32,
201  [REG_FN_WRITE_BASE + 0] = write_8,
202  [REG_FN_WRITE_BASE + 1] = write_16,
203  [REG_FN_WRITE_BASE + 3] = write_32,
204  [REG_FN_MODIFY_BASE + 0] = modify_8,
205  [REG_FN_MODIFY_BASE + 1] = modify_16,
206  [REG_FN_MODIFY_BASE + 3] = modify_32,
207 };
208 
209 unsigned long (*intc_enable_fns[])(unsigned long addr,
210  unsigned long handle,
211  unsigned long (*fn)(unsigned long,
212  unsigned long,
213  unsigned long),
214  unsigned int irq) = {
215  [MODE_ENABLE_REG] = intc_mode_field,
216  [MODE_MASK_REG] = intc_mode_zero,
217  [MODE_DUAL_REG] = intc_mode_field,
218  [MODE_PRIO_REG] = intc_mode_prio,
219  [MODE_PCLR_REG] = intc_mode_prio,
220 };
221 
222 unsigned long (*intc_disable_fns[])(unsigned long addr,
223  unsigned long handle,
224  unsigned long (*fn)(unsigned long,
225  unsigned long,
226  unsigned long),
227  unsigned int irq) = {
228  [MODE_ENABLE_REG] = intc_mode_zero,
229  [MODE_MASK_REG] = intc_mode_field,
230  [MODE_DUAL_REG] = intc_mode_field,
231  [MODE_PRIO_REG] = intc_mode_zero,
232  [MODE_PCLR_REG] = intc_mode_field,
233 };
234 
235 unsigned long (*intc_enable_noprio_fns[])(unsigned long addr,
236  unsigned long handle,
237  unsigned long (*fn)(unsigned long,
238  unsigned long,
239  unsigned long),
240  unsigned int irq) = {
241  [MODE_ENABLE_REG] = intc_mode_field,
242  [MODE_MASK_REG] = intc_mode_zero,
243  [MODE_DUAL_REG] = intc_mode_field,
244  [MODE_PRIO_REG] = intc_mode_field,
245  [MODE_PCLR_REG] = intc_mode_field,
246 };