2 * linux/arch/arm/lib/io.S
4 * Copyright (C) 1995, 1996 Russell King
6 #include <linux/config.h> /* for CONFIG_CPU_nn */
7 #include <linux/linkage.h>
8 #include <asm/assembler.h>
9 #include <asm/hardware.h>
14 .equ diff_pcio_base, PCIO_BASE - IO_BASE
18 orr r8, r8, r8, lsr #16
19 str r8, [r3, r0, lsl #2]
21 orr r8, r8, r8, lsl #16
22 str r8, [r3, r0, lsl #2]
25 .macro inw2 rd, mask, temp
29 orr \rd, \rd, \temp, lsl #16
35 add \rd, \rd, #IO_BASE
36 addeq \rd, \rd, #diff_pcio_base
40 .ascii "insw: bad buffer alignment (%p), called from %08lX\n\0"
42 .ascii "<4>insl/outsl not implemented, called from %08lX\0"
46 * These make no sense on Acorn machines.
47 * Print a warning message.
56 adr r0, .iosw_bad_align_msg
61 /* Purpose: read a block of data from a hardware register to memory.
62 * Proto : void insw(int from_port, void *to, int len_in_words);
63 * Notes : increment to, 'to' must be 16-bit aligned
66 .insw_align: tst r1, #1
67 bne .iosw_bad_alignment
84 .insw_aligned: mov ip, #0xff
85 orr ip, ip, ip, lsl #8
86 stmfd sp!, {r4, r5, r6, lr}
91 .insw_8_lp: ldr r3, [r0]
94 orr r3, r3, r4, lsl #16
99 orr r4, r4, r5, lsl #16
104 orr r5, r5, r6, lsl #16
109 orr r6, r6, lr, lsl #16
115 LOADREGS(eqfd, sp!, {r4, r5, r6, pc})
117 .no_insw_8: tst r2, #4
123 orr r3, r3, r4, lsl #16
128 orr r4, r4, r5, lsl #16
132 .no_insw_4: tst r2, #2
138 orr r3, r3, r4, lsl #16
142 .no_insw_2: tst r2, #1
147 LOADREGS(fd, sp!, {r4, r5, r6, pc})
149 @ Purpose: write a block of data from memory to a hardware register.
150 @ Proto : outsw(int to_reg, void *from, int len_in_words);
151 @ Notes : increments from
153 .outsw_align: tst r1, #1
154 bne .iosw_bad_alignment
160 orr r3, r3, r3, lsl #16
167 RETINSTR(moveq,pc,lr)
172 .outsw_aligned: stmfd sp!, {r4, r5, r6, lr}
176 .outsw_8_lp: ldmia r1!, {r3, r4, r5, r6}
179 orr ip, ip, ip, lsr #16
183 orr ip, ip, ip, lsl #16
187 orr ip, ip, ip, lsr #16
191 orr ip, ip, ip, lsl #16
195 orr ip, ip, ip, lsr #16
199 orr ip, ip, ip, lsl #16
203 orr ip, ip, ip, lsr #16
207 orr ip, ip, ip, lsl #16
213 LOADREGS(eqfd, sp!, {r4, r5, r6, pc})
215 .no_outsw_8: tst r2, #4
221 orr ip, ip, ip, lsr #16
225 orr ip, ip, ip, lsl #16
229 orr ip, ip, ip, lsr #16
233 orr ip, ip, ip, lsl #16
236 .no_outsw_4: tst r2, #2
242 orr ip, ip, ip, lsr #16
246 orr ip, ip, ip, lsl #16
249 .no_outsw_2: tst r2, #1
253 movne ip, r3, lsl #16
254 orrne ip, ip, ip, lsr #16
257 LOADREGS(fd, sp!, {r4, r5, r6, pc})
259 .insb_align: rsb ip, ip, #4
279 .insb_aligned: stmfd sp!, {r4 - r6, lr}
284 .insb_16_lp: ldrb r3, [r0]
286 orr r3, r3, r4, lsl #8
288 orr r3, r3, r4, lsl #16
290 orr r3, r3, r4, lsl #24
293 orr r4, r4, r5, lsl #8
295 orr r4, r4, r5, lsl #16
297 orr r4, r4, r5, lsl #24
300 orr r5, r5, r6, lsl #8
302 orr r5, r5, r6, lsl #16
304 orr r5, r5, r6, lsl #24
307 orr r6, r6, ip, lsl #8
309 orr r6, r6, ip, lsl #16
311 orr r6, r6, ip, lsl #24
317 LOADREGS(eqfd, sp!, {r4 - r6, pc})
319 .insb_no_16: tst r2, #8
324 orr r3, r3, r4, lsl #8
326 orr r3, r3, r4, lsl #16
328 orr r3, r3, r4, lsl #24
331 orr r4, r4, r5, lsl #8
333 orr r4, r4, r5, lsl #16
335 orr r4, r4, r5, lsl #24
338 .insb_no_8: tst r2, #4
343 orr r3, r3, r4, lsl #8
345 orr r3, r3, r4, lsl #16
347 orr r3, r3, r4, lsl #24
350 .insb_no_4: ands r2, r2, #3
351 LOADREGS(eqfd, sp!, {r4 - r6, pc})
359 LOADREGS(fd, sp!, {r4 - r6, pc})
363 .outsb_align: rsb ip, ip, #4
383 .outsb_aligned: stmfd sp!, {r4 - r6, lr}
388 .outsb_16_lp: ldmia r1!, {r3 - r6}
424 LOADREGS(eqfd, sp!, {r4 - r6, pc})
426 .outsb_no_16: tst r2, #8
446 .outsb_no_8: tst r2, #4
458 .outsb_no_4: ands r2, r2, #3
459 LOADREGS(eqfd, sp!, {r4 - r6, pc})
467 LOADREGS(fd, sp!, {r4 - r6, pc})
472 @ Purpose: write a memc register
473 @ Proto : void memc_write(int register, int value);
476 #if defined(CONFIG_CPU_26)
479 RETINSTR(movgt,pc,lr)
483 orr r0, r0, r1, lsl #2
484 add r0, r0, #0x03600000
487 #define CPSR2SPSR(rt)
489 #define CPSR2SPSR(rt) \
494 @ Purpose: call an expansion card loader to read bytes.
495 @ Proto : char read_loader(int offset, char *card_base, char *loader);
498 ENTRY(ecard_loader_read)
499 stmfd sp!, {r4 - r12, lr}
505 LOADREGS(fd, sp!, {r4 - r12, pc})
507 @ Purpose: call an expansion card loader to reset the card
508 @ Proto : void read_loader(int card_base, char *loader);
511 ENTRY(ecard_loader_reset)
512 stmfd sp!, {r4 - r12, lr}
517 LOADREGS(fd, sp!, {r4 - r12, pc})
523 stmfd sp!, {r4 - r10, fp, ip, lr, pc}
526 add r0, r3, r0, lsl #2
536 LOADREGS(leea, fp, {r4 - r10, fp, sp, pc})
538 Linswok: mov ip, #0xFF
539 orr ip, ip, ip, lsl #8
540 Linswlp: subs r2, r2, #64
550 stmia r1!, {r3 - r10}
559 stmia r1!, {r3 - r10}
561 LOADREGS(ea, fp, {r4 - r10, fp, sp, pc})
573 stmia r1!, {r3 - r10}
574 LOADREGS(eqea, fp, {r4 - r10, fp, sp, pc})
580 LOADREGS(ltea, fp, {r4 - r10, fp, sp, pc})
587 LOADREGS(ea, fp, {r4 - r10, fp, sp, pc})
593 stmfd sp!, {r4 - r8, fp, ip, lr, pc}
600 orr r4, r4, r4, lsr #16
601 str r4, [r3, r0, lsl #2]
603 LOADREGS(eqea, fp, {r4 - r8, fp, sp, pc})
606 ldmia r1!, {r4, r5, r6, r7}
611 ldmia r1!, {r4, r5, r6, r7}
617 LOADREGS(ea, fp, {r4 - r8, fp, sp, pc})
619 LOADREGS(eqea, fp, {r4 - r8, fp, sp, pc})
622 orr r4, r4, r4, lsr#16
623 str r4, [r3, r0, lsl#2]
626 LOADREGS(ea, fp, {r4 - r8, fp, sp, pc})