summaryrefslogtreecommitdiff
path: root/include/asm-alpha/jensen.h
blob: 964b06ead43b07ec12bd56d54cbcbb967b6b367c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
#ifndef __ALPHA_JENSEN_H
#define __ALPHA_JENSEN_H

#include <asm/compiler.h>

/*
 * Defines for the AlphaPC EISA IO and memory address space.
 */

/*
 * NOTE! The memory operations do not set any memory barriers, as it's
 * not needed for cases like a frame buffer that is essentially memory-like.
 * You need to do them by hand if the operations depend on ordering.
 *
 * Similarly, the port IO operations do a "mb" only after a write operation:
 * if an mb is needed before (as in the case of doing memory mapped IO
 * first, and then a port IO operation to the same device), it needs to be
 * done by hand.
 *
 * After the above has bitten me 100 times, I'll give up and just do the
 * mb all the time, but right now I'm hoping this will work out.  Avoiding
 * mb's may potentially be a noticeable speed improvement, but I can't
 * honestly say I've tested it.
 *
 * Handling interrupts that need to do mb's to synchronize to non-interrupts
 * is another fun race area.  Don't do it (because if you do, I'll have to
 * do *everything* with interrupts disabled, ugh).
 */

/*
 * EISA Interrupt Acknowledge address
 */
#define EISA_INTA		(IDENT_ADDR + 0x100000000UL)

/*
 * FEPROM addresses
 */
#define EISA_FEPROM0		(IDENT_ADDR + 0x180000000UL)
#define EISA_FEPROM1		(IDENT_ADDR + 0x1A0000000UL)

/*
 * VL82C106 base address
 */
#define EISA_VL82C106		(IDENT_ADDR + 0x1C0000000UL)

/*
 * EISA "Host Address Extension" address (bits 25-31 of the EISA address)
 */
#define EISA_HAE		(IDENT_ADDR + 0x1D0000000UL)

/*
 * "SYSCTL" register address
 */
#define EISA_SYSCTL		(IDENT_ADDR + 0x1E0000000UL)

/*
 * "spare" register address
 */
#define EISA_SPARE		(IDENT_ADDR + 0x1F0000000UL)

/*
 * EISA memory address offset
 */
#define EISA_MEM		(IDENT_ADDR + 0x200000000UL)

/*
 * EISA IO address offset
 */
#define EISA_IO			(IDENT_ADDR + 0x300000000UL)


#ifdef __KERNEL__

#ifndef __EXTERN_INLINE
#define __EXTERN_INLINE extern inline
#define __IO_EXTERN_INLINE
#endif

/*
 * Handle the "host address register". This needs to be set
 * to the high 7 bits of the EISA address.  This is also needed
 * for EISA IO addresses, which are only 16 bits wide (the
 * hae needs to be set to 0).
 *
 * HAE isn't needed for the local IO operations, though.
 */

#define JENSEN_HAE_ADDRESS	EISA_HAE
#define JENSEN_HAE_MASK		0x1ffffff

__EXTERN_INLINE void jensen_set_hae(unsigned long addr)
{
	/* hae on the Jensen is bits 31:25 shifted right */
	addr >>= 25;
	if (addr != alpha_mv.hae_cache)
		set_hae(addr);
}

#define vuip	volatile unsigned int *

/*
 * IO functions
 *
 * The "local" functions are those that don't go out to the EISA bus,
 * but instead act on the VL82C106 chip directly.. This is mainly the
 * keyboard, RTC,  printer and first two serial lines..
 *
 * The local stuff makes for some complications, but it seems to be
 * gone in the PCI version. I hope I can get DEC suckered^H^H^H^H^H^H^H^H
 * convinced that I need one of the newer machines.
 */

static inline unsigned int jensen_local_inb(unsigned long addr)
{
	return 0xff & *(vuip)((addr << 9) + EISA_VL82C106);
}

static inline void jensen_local_outb(u8 b, unsigned long addr)
{
	*(vuip)((addr << 9) + EISA_VL82C106) = b;
	mb();
}

static inline unsigned int jensen_bus_inb(unsigned long addr)
{
	long result;

	jensen_set_hae(0);
	result = *(volatile int *)((addr << 7) + EISA_IO + 0x00);
	return __kernel_extbl(result, addr & 3);
}

static inline void jensen_bus_outb(u8 b, unsigned long addr)
{
	jensen_set_hae(0);
	*(vuip)((addr << 7) + EISA_IO + 0x00) = b * 0x01010101;
	mb();
}

/*
 * It seems gcc is not very good at optimizing away logical
 * operations that result in operations across inline functions.
 * Which is why this is a macro.
 */

#define jensen_is_local(addr) ( \
/* keyboard */	(addr == 0x60 || addr == 0x64) || \
/* RTC */	(addr == 0x170 || addr == 0x171) || \
/* mb COM2 */	(addr >= 0x2f8 && addr <= 0x2ff) || \
/* mb LPT1 */	(addr >= 0x3bc && addr <= 0x3be) || \
/* mb COM2 */	(addr >= 0x3f8 && addr <= 0x3ff))

__EXTERN_INLINE u8 jensen_inb(unsigned long addr)
{
	if (jensen_is_local(addr))
		return jensen_local_inb(addr);
	else
		return jensen_bus_inb(addr);
}

__EXTERN_INLINE void jensen_outb(u8 b, unsigned long addr)
{
	if (jensen_is_local(addr))
		jensen_local_outb(b, addr);
	else
		jensen_bus_outb(b, addr);
}

__EXTERN_INLINE u16 jensen_inw(unsigned long addr)
{
	long result;

	jensen_set_hae(0);
	result = *(volatile int *) ((addr << 7) + EISA_IO + 0x20);
	result >>= (addr & 3) * 8;
	return 0xffffUL & result;
}

__EXTERN_INLINE u32 jensen_inl(unsigned long addr)
{
	jensen_set_hae(0);
	return *(vuip) ((addr << 7) + EISA_IO + 0x60);
}

__EXTERN_INLINE void jensen_outw(u16 b, unsigned long addr)
{
	jensen_set_hae(0);
	*(vuip) ((addr << 7) + EISA_IO + 0x20) = b * 0x00010001;
	mb();
}

__EXTERN_INLINE void jensen_outl(u32 b, unsigned long addr)
{
	jensen_set_hae(0);
	*(vuip) ((addr << 7) + EISA_IO + 0x60) = b;
	mb();
}

/*
 * Memory functions.
 */

__EXTERN_INLINE u8 jensen_readb(const volatile void __iomem *xaddr)
{
	unsigned long addr = (unsigned long) xaddr;
	long result;

	jensen_set_hae(addr);
	addr &= JENSEN_HAE_MASK;
	result = *(volatile int *) ((addr << 7) + EISA_MEM + 0x00);
	result >>= (addr & 3) * 8;
	return 0xffUL & result;
}

__EXTERN_INLINE u16 jensen_readw(const volatile void __iomem *xaddr)
{
	unsigned long addr = (unsigned long) xaddr;
	long result;

	jensen_set_hae(addr);
	addr &= JENSEN_HAE_MASK;
	result = *(volatile int *) ((addr << 7) + EISA_MEM + 0x20);
	result >>= (addr & 3) * 8;
	return 0xffffUL & result;
}

__EXTERN_INLINE u32 jensen_readl(const volatile void __iomem *xaddr)
{
	unsigned long addr = (unsigned long) xaddr;
	jensen_set_hae(addr);
	addr &= JENSEN_HAE_MASK;
	return *(vuip) ((addr << 7) + EISA_MEM + 0x60);
}

__EXTERN_INLINE u64 jensen_readq(const volatile void __iomem *xaddr)
{
	unsigned long addr = (unsigned long) xaddr;
	unsigned long r0, r1;

	jensen_set_hae(addr);
	addr &= JENSEN_HAE_MASK;
	addr = (addr << 7) + EISA_MEM + 0x60;
	r0 = *(vuip) (addr);
	r1 = *(vuip) (addr + (4 << 7));
	return r1 << 32 | r0;
}

__EXTERN_INLINE void jensen_writeb(u8 b, volatile void __iomem *xaddr)
{
	unsigned long addr = (unsigned long) xaddr;
	jensen_set_hae(addr);
	addr &= JENSEN_HAE_MASK;
	*(vuip) ((addr << 7) + EISA_MEM + 0x00) = b * 0x01010101;
}

__EXTERN_INLINE void jensen_writew(u16 b, volatile void __iomem *xaddr)
{
	unsigned long addr = (unsigned long) xaddr;
	jensen_set_hae(addr);
	addr &= JENSEN_HAE_MASK;
	*(vuip) ((addr << 7) + EISA_MEM + 0x20) = b * 0x00010001;
}

__EXTERN_INLINE void jensen_writel(u32 b, volatile void __iomem *xaddr)
{
	unsigned long addr = (unsigned long) xaddr;
	jensen_set_hae(addr);
	addr &= JENSEN_HAE_MASK;
	*(vuip) ((addr << 7) + EISA_MEM + 0x60) = b;
}

__EXTERN_INLINE void jensen_writeq(u64 b, volatile void __iomem *xaddr)
{
	unsigned long addr = (unsigned long) xaddr;
	jensen_set_hae(addr);
	addr &= JENSEN_HAE_MASK;
	addr = (addr << 7) + EISA_MEM + 0x60;
	*(vuip) (addr) = b;
	*(vuip) (addr + (4 << 7)) = b >> 32;
}

__EXTERN_INLINE void __iomem *jensen_ioportmap(unsigned long addr)
{
	return (void __iomem *)addr;
}

__EXTERN_INLINE void __iomem *jensen_ioremap(unsigned long addr,
					     unsigned long size)
{
	return (void __iomem *)(addr + 0x100000000ul);
}

__EXTERN_INLINE int jensen_is_ioaddr(unsigned long addr)
{
	return (long)addr >= 0;
}

__EXTERN_INLINE int jensen_is_mmio(const volatile void __iomem *addr)
{
	return (unsigned long)addr >= 0x100000000ul;
}

/* New-style ioread interface.  All the routines are so ugly for Jensen
   that it doesn't make sense to merge them.  */

#define IOPORT(OS, NS)							\
__EXTERN_INLINE unsigned int jensen_ioread##NS(void __iomem *xaddr)	\
{									\
	if (jensen_is_mmio(xaddr))					\
		return jensen_read##OS(xaddr - 0x100000000ul);		\
	else								\
		return jensen_in##OS((unsigned long)xaddr);		\
}									\
__EXTERN_INLINE void jensen_iowrite##NS(u##NS b, void __iomem *xaddr)	\
{									\
	if (jensen_is_mmio(xaddr))					\
		jensen_write##OS(b, xaddr - 0x100000000ul);		\
	else								\
		jensen_out##OS(b, (unsigned long)xaddr);		\
}

IOPORT(b, 8)
IOPORT(w, 16)
IOPORT(l, 32)

#undef IOPORT

#undef vuip

#undef __IO_PREFIX
#define __IO_PREFIX		jensen
#define jensen_trivial_rw_bw	0
#define jensen_trivial_rw_lq	0
#define jensen_trivial_io_bw	0
#define jensen_trivial_io_lq	0
#define jensen_trivial_iounmap	1
#include <asm/io_trivial.h>

#ifdef __IO_EXTERN_INLINE
#undef __EXTERN_INLINE
#undef __IO_EXTERN_INLINE
#endif

#endif /* __KERNEL__ */

#endif /* __ALPHA_JENSEN_H */