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