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