]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/lubbock/memsetup.S
c0278340a82933e9fbc5444135948223cab84207
[karo-tx-uboot.git] / board / lubbock / memsetup.S
1 /*
2  * Most of this taken from Redboot hal_platform_setup.h with cleanup
3  *
4  * NOTE: I haven't clean this up considerably, just enough to get it
5  * running. See hal_platform_setup.h for the source. See
6  * board/cradle/memsetup.S for another PXA250 setup that is
7  * much cleaner.
8  *
9  * See file CREDITS for list of people who contributed to this
10  * project.
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License as
14  * published by the Free Software Foundation; either version 2 of
15  * the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
25  * MA 02111-1307 USA
26  */
27
28 #include <config.h>
29 #include <version.h>
30 #include <asm/arch/pxa-regs.h>
31
32 DRAM_SIZE:  .long   CFG_DRAM_SIZE
33
34 /* wait for coprocessor write complete */
35    .macro CPWAIT reg
36    mrc  p15,0,\reg,c2,c0,0
37    mov  \reg,\reg
38    sub  pc,pc,#4
39    .endm
40
41
42 .globl memsetup
43 memsetup:
44
45     mov      r10, lr
46
47     /* Set up GPIO pins first */
48
49         ldr             r0,     =GPSR0
50         ldr             r1,     =CFG_GPSR0_VAL
51         str             r1,   [r0]
52
53         ldr             r0,     =GPSR1
54         ldr             r1,     =CFG_GPSR1_VAL
55         str             r1,   [r0]
56
57         ldr             r0,     =GPSR2
58         ldr             r1,     =CFG_GPSR2_VAL
59         str             r1,   [r0]
60
61         ldr             r0,     =GPCR0
62         ldr             r1,     =CFG_GPCR0_VAL
63         str             r1,   [r0]
64
65         ldr             r0,     =GPCR1
66         ldr             r1,     =CFG_GPCR1_VAL
67         str             r1,   [r0]
68
69         ldr             r0,     =GPCR2
70         ldr             r1,     =CFG_GPCR2_VAL
71         str             r1,   [r0]
72
73         ldr             r0,     =GPDR0
74         ldr             r1,     =CFG_GPDR0_VAL
75         str             r1,   [r0]
76
77         ldr             r0,     =GPDR1
78         ldr             r1,     =CFG_GPDR1_VAL
79         str             r1,   [r0]
80
81         ldr             r0,     =GPDR2
82         ldr             r1,     =CFG_GPDR2_VAL
83         str             r1,   [r0]
84
85         ldr             r0,     =GAFR0_L
86         ldr             r1,     =CFG_GAFR0_L_VAL
87         str             r1,   [r0]
88
89         ldr             r0,     =GAFR0_U
90         ldr             r1,     =CFG_GAFR0_U_VAL
91         str             r1,   [r0]
92
93         ldr             r0,     =GAFR1_L
94         ldr             r1,     =CFG_GAFR1_L_VAL
95         str             r1,   [r0]
96
97         ldr             r0,     =GAFR1_U
98         ldr             r1,     =CFG_GAFR1_U_VAL
99         str             r1,   [r0]
100
101         ldr             r0,     =GAFR2_L
102         ldr             r1,     =CFG_GAFR2_L_VAL
103         str             r1,   [r0]
104
105         ldr             r0,     =GAFR2_U
106         ldr             r1,     =CFG_GAFR2_U_VAL
107         str             r1,   [r0]
108
109    /* enable GPIO pins */
110         ldr             r0,     =PSSR
111         ldr             r1,     =CFG_PSSR_VAL
112         str             r1,   [r0]
113
114    ldr    r3, =MSC1                             /* low - bank 2 Lubbock Registers / SRAM */
115    ldr    r2, =CFG_MSC1_VAL                     /* high - bank 3 Ethernet Controller */
116    str    r2, [r3]                              /* need to set MSC1 before trying to write to the HEX LEDs */
117    ldr    r2, [r3]                              /* need to read it back to make sure the value latches (see MSC section of manual) */
118
119    ldr    r1, =LED_BLANK
120    mov    r0, #0xFF
121    str    r0, [r1]              /* turn on hex leds */
122
123 loop:
124    ldr          r0, =0xB0070001
125    ldr          r1, =_LED
126    str          r0, [r1]                                                        /* hex display */
127
128 /*********************************************************************
129     Initlialize Memory Controller
130          The sequence below is based on the recommended init steps detailed
131          in the EAS, chapter 5 (Chapter 10, Operating Systems Developers Guide)
132
133
134     pause for 200 uSecs- allow internal clocks to settle
135          *Note: only need this if hard reset... doing it anyway for now
136 */
137
138         @ ---- Wait 200 usec
139         ldr r3, =OSCR       @ reset the OS Timer Count to zero
140         mov r2, #0
141         str r2, [r3]
142         ldr r4, =0x300                  @ really 0x2E1 is about 200usec, so 0x300 should be plenty
143 1:
144         ldr r2, [r3]
145         cmp r4, r2
146         bgt 1b
147
148 mem_init:
149         @ get memory controller base address
150         ldr     r1,  =MEMC_BASE
151
152 @****************************************************************************
153 @  Step 1
154 @
155
156         @ write msc0, read back to ensure data latches
157         @
158         ldr     r2,   =CFG_MSC0_VAL
159         str     r2,   [r1, #MSC0_OFFSET]
160         ldr     r2,   [r1, #MSC0_OFFSET]
161
162         @ write msc1
163         ldr     r2,  =CFG_MSC1_VAL
164         str     r2,  [r1, #MSC1_OFFSET]
165         ldr     r2,  [r1, #MSC1_OFFSET]
166
167         @ write msc2
168         ldr     r2,  =CFG_MSC2_VAL
169         str     r2,  [r1, #MSC2_OFFSET]
170         ldr     r2,  [r1, #MSC2_OFFSET]
171
172         @ write mecr
173         ldr     r2,  =CFG_MECR_VAL
174         str     r2,  [r1, #MECR_OFFSET]
175
176         @ write mcmem0
177         ldr     r2,  =CFG_MCMEM0_VAL
178         str     r2,  [r1, #MCMEM0_OFFSET]
179
180         @ write mcmem1
181         ldr     r2,  =CFG_MCMEM1_VAL
182         str     r2,  [r1, #MCMEM1_OFFSET]
183
184         @ write mcatt0
185         ldr     r2,  =CFG_MCATT0_VAL
186         str     r2,  [r1, #MCATT0_OFFSET]
187
188         @ write mcatt1
189         ldr     r2,  =CFG_MCATT1_VAL
190         str     r2,  [r1, #MCATT1_OFFSET]
191
192         @ write mcio0
193         ldr     r2,  =CFG_MCIO0_VAL
194         str     r2,  [r1, #MCIO0_OFFSET]
195
196         @ write mcio1
197         ldr     r2,  =CFG_MCIO1_VAL
198         str     r2,  [r1, #MCIO1_OFFSET]
199
200         @-------------------------------------------------------
201         @ 3rd bullet, Step 1
202         @
203
204         @ get the mdrefr settings
205         ldr     r3,  =CFG_MDREFR_VAL_100
206
207         @ extract DRI field (we need a valid DRI field)
208         @
209         ldr     r2,  =0xFFF
210
211         @ valid DRI field in r3
212         @
213         and     r3,  r3,  r2
214
215         @ get the reset state of MDREFR
216         @
217         ldr     r4,  [r1, #MDREFR_OFFSET]
218
219         @ clear the DRI field
220         @
221         bic     r4,  r4,  r2
222
223         @ insert the valid DRI field loaded above
224         @
225         orr     r4,  r4,  r3
226
227         @ write back mdrefr
228         @
229         str     r4,  [r1, #MDREFR_OFFSET]
230
231         @ *Note: preserve the mdrefr value in r4 *
232
233 @****************************************************************************
234 @  Step 2
235 @
236         /* This should be for SRAM, why is it commented out??? */
237
238         @ fetch sxcnfg value
239         @
240         @ldr     r2,  =0
241         @ write back sxcnfg
242         @str     r2,  [r1, #SXCNFG_OFFSET]
243
244 /*        @if sxcnfg=0, don't program for synch-static memory */
245         @cmp     r2,  #0
246         @beq     1f
247
248         @program sxmrs
249         @ldr     r2,  =SXMRS_SETTINGS
250         @str     r2,  [r1, #SXMRS_OFFSET]
251
252
253 @****************************************************************************
254 @  Step 3
255 @
256
257         @ Assumes previous mdrefr value in r4, if not then read current mdrefr
258
259         @ clear the free-running clock bits
260         @ (clear K0Free, K1Free, K2Free
261         @
262         bic     r4,  r4,  #(0x00800000 | 0x01000000 | 0x02000000)
263
264         @ set K1RUN if bank 0 installed
265         @
266         orr   r4,  r4,  #0x00010000
267
268
269
270 #ifdef THIS
271 @<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<
272 @<!<!<!<!<!<!<!<!<!<!<!  Begin INSERT 1    <!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<
273         @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
274         @ Lubbock: Allow the user to select the {T/R/M} with predetermined
275         @   SDCLK.  Based on Table 3-1 in PXA250 and PXA210 Dev Man.
276         @
277         @  * = Must set MDREFR.K1DB2 to halve the MemClk for desired SDCLK[1]
278         @
279         @   S25, S26 used to provide all 400 MHz BIN values for Cotulla (0,0 - 1,3)
280         @   S25, S26 used to provide all 200 MHz BIN values for Sabinal
281         @
282         @   S23: Force the halving of MemClk when deriving SDCLK[1]
283         @        DOT: no override  !DOT: halve (if not already forced half)
284 /*        @        *For certain MemClks, SDCLK's derivation is forced to be halved */
285         @
286         @   S24: Run/Turbo.
287         @        DOT: Run mode   !DOT: Turbo mode
288         @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
289
290         @
291         @ Allow the user to control K1DB2 where applicable
292         @
293         @ Get the value of S23:          @ 1 = DOT (unity), 0 = !DOT (halve it)
294         @
295         @ DOT:   set K1DB2     (SDCLD = MemClk)
296         @ !DOT:  clear K1DB2   (SDCLK = MemClk/2)
297         @
298         @ldr r2, =FPGA_REGS_BASE_PHYSICAL
299
300         bl GET_S23                          @ r3, r2                    @ get the value of S23 in R0, i put the base adx of fpga in r3
301
302         cmp      r3, #0x0                 @ is !DOT?
303         orreq    r4, r4,  #0x00020000     @ SDClk[1] = MemClk/2
304         bicne    r4, r4,  #0x00020000     @ SDClk[1] = MemClk
305
306         @
307         @ Next, we need to look for S25,S26 selections that necessitate the
308         @  halving of MemClk to derive SDCLK[1]: (S25,S26)={03-0C, 10-13}
309         @ Override above S23-based selection accordingly.
310         @
311         ldr r2, =FPGA_REGS_BASE_PHYSICAL
312         bl  GET_S25                           @ r0, r2
313                                        @ get the value of S25 in R0, i put the base adx of fpga in r2
314
315
316
317         ldr r2, =FPGA_REGS_BASE_PHYSICAL
318         BL  GET_S26                              @ r3, r2
319                                       @ get the value of S26 in R1, i put the base adx of fpga in r2
320
321         orr     r0, r0, r3               @ concatenate S25 & S26 vals
322         and     r0, r0, #0xFF
323
324         @ Set K1DB2 for the frequencies that require it
325         @
326         cmp     r0, #0x03
327         cmpne   r0, #0x04
328         cmpne   r0, #0x05
329         cmpne   r0, #0x06
330         cmpne   r0, #0x07
331         cmpne   r0, #0x08
332         cmpne   r0, #0x09
333         cmpne   r0, #0x0A
334         cmpne   r0, #0x0B
335         cmpne   r0, #0x0C
336         cmpne   r0, #0x10
337         cmpne   r0, #0x11
338         cmpne   r0, #0x12
339         cmpne   r0, #0x13
340         orreq   r4, r4,  #0x00020000     @ SDCLK[1] = (MemClk)/2 for 03 - 0C @ 10 - 13
341
342         @
343         @ *Must make MSC0&1 adjustments now for MEMClks > 100MHz.
344         @
345         @ Adjust MSC0 for MemClks > 100 MHz
346         @
347         ldreq   r0,   [r1, #MSC0_OFFSET]
348         ldreq   r3,   =0x7F007F00
349         biceq   r0,   r0, r3                @ clear MSC0[14:12, 11:8] (RRR, RDN)
350         ldreq   r3,   =0x46004600
351         orreq   r0,   r0, r3                @ set   MSC0[14, 10:9]  (doubling RRR, RDN)
352         streq   r0,   [r1, #MSC0_OFFSET]
353         ldreq   r0,   [r1, #MSC0_OFFSET]    @ read it back to ensure that the data latches
354
355         @
356         @ Adjust MSC1.LH for MemClks > 100 MHz
357         @
358         ldreq   r0,   [r1, #MSC1_OFFSET]
359         ldreq   r3,   =0x7FF0
360         biceq   r0,   r0, r3               @ clear MSC1[14:12, 11:8, 7:4] (RRR, RDN, RDF)
361         ldreq   r3,   =0x4880
362         orreq   r0,   r0, r3               @ set   MSC1[14, 11, 7]  (doubling RRR, RDN, RDF)
363         streq   r0,   [r1, #MSC1_OFFSET]
364         ldreq   r0,   [r1, #MSC1_OFFSET]   @ read it back to ensure that the data latches
365
366         @                                                                   @
367         @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
368 #endif
369
370 @<!<!<!<!<!<!<!<!<!<!<!    End INSERT 1    <!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<
371 @<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<!<
372
373
374         @ write back mdrefr
375         @
376         str     r4,  [r1, #MDREFR_OFFSET]
377         ldr     r4,  [r1, #MDREFR_OFFSET]
378
379         @ deassert SLFRSH
380         @
381         bic     r4,  r4,  #0x00400000
382
383         @ write back mdrefr
384         @
385         str     r4,  [r1, #MDREFR_OFFSET]
386
387         @ assert E1PIN
388         @
389         orr     r4,  r4,  #0x00008000
390
391         @ write back mdrefr
392         @
393         str     r4,  [r1, #MDREFR_OFFSET]
394         ldr     r4,  [r1, #MDREFR_OFFSET]
395         nop
396         nop
397
398
399 @****************************************************************************
400 @  Step 4
401 @
402
403         @ fetch platform value of mdcnfg
404         @
405         ldr     r2,  =CFG_MDCNFG_VAL
406
407         @ disable all sdram banks
408         @
409         bic     r2,  r2,  #(MDCNFG_DE0 | MDCNFG_DE1)
410         bic     r2,  r2,  #(MDCNFG_DE2 | MDCNFG_DE3)
411
412         @ program banks 0/1 for bus width
413         @
414         bic   r2,  r2,  #MDCNFG_DWID0      @0=32-bit
415
416
417         @ write initial value of mdcnfg, w/o enabling sdram banks
418         @
419         str     r2,  [r1, #MDCNFG_OFFSET]
420
421 @ ****************************************************************************
422 @  Step 5
423 @
424
425         @ pause for 200 uSecs
426         @
427         ldr r3, =OSCR   @reset the OS Timer Count to zero
428         mov r2, #0
429             str r2, [r3]
430             ldr r4, =0x300                      @really 0x2E1 is about 200usec, so 0x300 should be plenty
431 1:
432             ldr r2, [r3]
433             cmp r4, r2
434             bgt 1b
435
436
437 @****************************************************************************
438 @  Step 6
439 @
440
441             mov    r0, #0x78                                @turn everything off
442       mcr    p15, 0, r0, c1, c0, 0              @(caches off, MMU off, etc.)
443
444
445 @ ****************************************************************************
446 @  Step 7
447 @
448         @ Access memory *not yet enabled* for CBR refresh cycles (8)
449         @ - CBR is generated for all banks
450
451             ldr     r2, =CFG_DRAM_BASE
452             str     r2, [r2]
453             str     r2, [r2]
454             str     r2, [r2]
455             str     r2, [r2]
456             str     r2, [r2]
457             str     r2, [r2]
458             str     r2, [r2]
459             str     r2, [r2]
460
461
462 @ ****************************************************************************
463 @  Step 8: NOP (enable dcache if you wanna... we dont)
464 @
465
466
467 @ ****************************************************************************
468 @  Step 9
469 @
470
471
472         @get memory controller base address
473         @
474         ldr     r1,  =MEMC_BASE
475
476         @fetch current mdcnfg value
477         @
478         ldr     r3,  [r1, #MDCNFG_OFFSET]
479
480         @enable sdram bank 0 if installed (must do for any populated bank)
481         @
482         orr     r3,  r3,  #MDCNFG_DE0
483
484         @write back mdcnfg, enabling the sdram bank(s)
485         @
486         str     r3,  [r1, #MDCNFG_OFFSET]
487
488
489 @****************************************************************************
490 @  Step 10
491 @
492
493         @ write mdmrs
494         @
495         ldr     r2,  =CFG_MDMRS_VAL
496         str     r2,  [r1, #MDMRS_OFFSET]
497
498
499 @****************************************************************************
500 @  Step 11: Final Step
501 @
502
503 @INITINTC
504         @********************************************************************
505         @ Disable (mask) all interrupts at the interrupt controller
506         @
507
508         @ clear the interrupt level register (use IRQ, not FIQ)
509         @
510         mov     r1, #0
511         ldr     r2,  =ICLR
512         str     r1,  [r2]
513
514         @ mask all interrupts at the controller
515         @
516         ldr     r2,  =ICMR
517         str     r1,  [r2]
518
519
520 @INITCLKS
521         @ ********************************************************************
522         @ Disable the peripheral clocks, and set the core clock
523         @ frequency (hard-coding at 398.12MHz for now).
524         @
525
526                 @ Turn Off ALL on-chip peripheral clocks for re-configuration
527                 @ *Note: See label 'ENABLECLKS' for the re-enabling
528                 @
529         ldr     r1,  =CKEN
530         mov     r2,  #0
531         str     r2,  [r1]
532
533
534         @ default value in case no valid rotary switch setting is found
535         ldr     r2, =(CCCR_L27 | CCCR_M2 | CCCR_N10)        @ DEFAULT: {200/200/100}
536
537
538         @... and write the core clock config register
539         @
540         ldr     r1,  =CCCR
541         str     r2,  [r1]
542
543 /*        @ enable the 32Khz oscillator for RTC and PowerManager
544         @
545         ldr     r1,  =OSCC
546         mov     r2,  #OSCC_OON
547         str     r2,  [r1]
548
549
550         @ NOTE:  spin here until OSCC.OOK get set,
551         @        meaning the PLL has settled.
552         @
553 60:
554         ldr     r2, [r1]
555         ands    r2, r2, #1
556         beq     60b
557 */
558
559 @OSCC_OON_DONE
560
561
562 #ifdef  A0_COTULLA
563     @****************************************************************************
564     @ !!! Take care of A0 Errata Sighting #4 --
565     @ after a frequency change, the memory controller must be restarted
566     @
567
568         @ get memory controller base address
569         ldr     r1,  =MEMC_BASE
570
571         @ get the current state of MDREFR
572         @
573         ldr     r2,  [r1, #MDREFR_OFFSET]
574
575         @ clear E0PIN, E1PIN
576         @
577         bic     r3,  r2,  #(MDREFR_E0PIN | MDREFR_E1PIN)
578
579         @ write MDREFR with E0PIN, E1PIN cleared (disable sdclk[0,1])
580         @
581         str     r3,  [r1, #MDREFR_OFFSET]
582
583         @ then write MDREFR with E0PIN, E1PIN set (enable sdclk[0,1])
584         @
585         str     r2,  [r1, #MDREFR_OFFSET]
586
587         @ get the current state of MDCNFG
588         @
589         ldr     r3,  [r1, #MDCNFG_OFFSET]
590
591         @ disable all SDRAM banks
592         @
593         bic     r3,  r3,  #(MDCNFG_DE0 | MDCNFG_DE1)
594         bic     r3,  r3,  #(MDCNFG_DE2 |  MDCNFG_DE3)
595
596         @ write back MDCNFG
597         @
598         ldr     r3,  [r1, #MDCNFG_OFFSET]
599
600             @ Access memory not yet enabled for CBR refresh cycles (8)
601         @ - CBR is generated for *all* banks
602             ldr     r2, =CFG_DRAM_BASE
603             str     r2, [r2]
604             str     r2, [r2]
605             str     r2, [r2]
606             str     r2, [r2]
607             str     r2, [r2]
608             str     r2, [r2]
609             str     r2, [r2]
610             str     r2, [r2]
611
612         @ fetch current mdcnfg value
613         @
614         ldr     r3,  [r1, #MDCNFG_OFFSET]
615
616         @ enable sdram bank 0 if installed
617         @
618         orr     r3,  r3,  #MDCNFG_DE0
619
620         @ write back mdcnfg, enabling the sdram bank(s)
621         @
622         str     r3,  [r1, #MDCNFG_OFFSET]
623
624         @ write mdmrs
625         @
626         ldr     r2,  =CFG_MDMRS_VAL
627         str     r2,  [r1, #MDMRS_OFFSET]
628
629
630
631     /*    @ errata: don't enable auto power-down */
632         @ get current value of mdrefr
633         @ldr     r3,  [r1, #MDREFR_OFFSET]
634         @ enable auto-power down
635         @orr     r3,  r3,  #MDREFR_APD
636         @write back mdrefr
637         @str     r3,  [r1, #MDREFR_OFFSET]
638
639 #endif A0_Cotulla
640
641
642   ldr     r0, =0x000C0dE3
643   ldr           r1, =_LED
644   str           r0, [r1]                /* hex display */
645
646 @ ^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%
647 @ ^%^%^%^%^%^%^%^%^%   above could be replaced by prememLLI ^%^%^%^%^%^%^%^%^%
648 @ ^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%
649
650
651         /* Save SDRAM size */
652     ldr     r1, =DRAM_SIZE
653          str       r8, [r1]
654
655     ldr     r0, =0xC0DE0006
656     ldr         r1, =_LED
657     str         r0, [r1]                /* hex display */
658
659         /* Interrupt init */
660         /* Mask all interrupts */
661     ldr r0, =ICMR /* enable no sources */
662         mov r1, #0
663     str r1, [r0]
664
665 #define NODEBUG
666 #ifdef NODEBUG
667         /*Disable software and data breakpoints */
668         mov     r0,#0
669         mcr     p15,0,r0,c14,c8,0  /* ibcr0 */
670         mcr     p15,0,r0,c14,c9,0  /* ibcr1 */
671         mcr     p15,0,r0,c14,c4,0  /* dbcon */
672
673         /*Enable all debug functionality */
674         mov     r0,#0x80000000
675         mcr     p14,0,r0,c10,c0,0  /* dcsr */
676
677 #endif
678
679         ldr     r0, =0xBEEF001D
680     ldr         r1, =_LED
681     str         r0, [r1]                /* hex display */
682
683         mov     pc, r10
684
685 @ End memsetup
686
687 @ %%%%%%%%%%%   Useful subroutines
688 GET_S23:
689     @ This macro will read S23 and return its value in r3
690     @ r2 contains the base address of the Lubbock user registers
691     ldr r2, =FPGA_REGS_BASE_PHYSICAL
692
693     /*@ read S23's value */
694     ldr     r3, [r2, #USER_SWITCHES_OFFSET]
695
696     @ mask out irrelevant bits
697     and     r3, r3, #0x200
698
699     @ get bit into position 0
700     mov     r3, r3, LSR #9
701
702     mov     pc, lr
703 @ End GET_S23
704
705
706 GET_S24:
707     @ This macro will read S24 and return its value in r0
708     @ r2 contains the base address of the Lubbock user registers
709     ldr r2, =FPGA_REGS_BASE_PHYSICAL
710
711     /*@ read S24's value */
712     ldr     r0, [r2, #USER_SWITCHES_OFFSET]
713
714     @ mask out irrelevant bits
715     and     r0, r0, #0x100
716
717     @ get bit into position 0
718     mov     r0, r0, LSR #8
719
720     mov     pc, lr
721 @ End GET_S23
722
723
724 GET_S25:
725     @ This macro will read rotary S25 and return its value in r0
726     @ r2 contains the base address of the Lubbock user registers
727     @ read the user switches register
728     ldr     r0, [r2, #USER_SWITCHES_OFFSET]
729
730     @ mask out irrelevant bits
731     and     r0, r0, #0xF0
732
733     mov     pc, lr
734 @ End subroutine
735
736
737 GET_S26:
738     @ This macro will read rotary S26 and return its value in r3
739     @ r2 contains the base address of the Lubbock user registers
740     @ read the user switches register
741     ldr     r3, [r2, #USER_SWITCHES_OFFSET]
742
743     @ mask out irrelevant bits
744     and     r3, r3, #0x0F
745
746     mov     pc, lr
747 @ End subroutine GET_S26
748
749