xref: /OK3568_Linux_fs/kernel/drivers/sh/intc/access.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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