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
|
/* This is the memory initialization functions, the function
* implemented below initializes each memory controller
* found and specified by the input grlib_mctrl_handler structure.
*
* After the memory controllers have been initialized the stack
* can be used.
*
* (C) Copyright 2010, 2015
* Daniel Hellstrom, Cobham Gaisler, daniel@gaisler.com.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <ambapp.h>
#include "memcfg.h"
#include <config.h>
.seg "text"
.globl _nomem_memory_ctrl_init
.globl _nomem_mctrl_init, _nomem_ahbmctrl_init
.extern _nomem_find_apb
.extern _nomem_find_ahb
/* FUNCTION
* _nomem_memory_controller_init(struct grlib_mctrl_handler *mem_handlers)
*
* Initialize AMBA devices, _nomem_amba_init() has prepared i0-i5
* with the AHB buses on the system.
*
* For each entry in mem_handlers find the VENDOR:DEVICE and handle it
* by calling the handler function pointer.
*
* Constraints:
* i6, i7, o6, l7, l6, g3, g4, g5, g6, g7 is used by caller
* o7 is return address
* l5 reserved for this function for future use.
*
* Arguments
* - o0 Pointer to memory handler array
*
* Results
* - o0 Number of memory controllers found
*
* Clobbered
* - o0 (Current AHB slave conf address)
* - l0 (mem handler entry address)
* - l1 (Return value, number of memory controllers found)
* - o7 (function pointer)
* - l0, l1, l2, l3, l4, g1, g2 (used by _nomem_ambapp_find_buses)
* - o0, o1, o2, o3, o4, o5 (Used as arguments)
*
* - g1 ( level 1 return address)
* - g2 ( level 2 return address)
*/
_nomem_memory_ctrl_init:
/* At this point all AHB buses has been found and the I/O Areas of
* all AHB buses is stored in the i0-i5 registers. Max 6 buses. Next,
* memory controllers are found by searching all buses for matching
* VENDOR:DEVICE. The VENDOR:DEVICE to search for are taken from the
* mem_handlers array. For each match the function pointer stored in
* the mem_handler entry is called to handle the hardware setup.
*/
mov %o7, %g1 /* Save return address */
mov %o0, %l0
mov %g0, %l1 /* The return value */
.L_do_one_mem_handler:
ld [%l0 + MH_FUNC], %o7
cmp %o7, %g0
be .L_all_mctrl_handled
nop
/*** Scan for memory controller ***/
/* Set up argments, o5 not used by _nomem_find_apb */
ldub [%l0 + MH_TYPE], %o5
clr %o4
clr %o3
ldub [%l0 + MH_INDEX], %o2
ld [%l0 + MH_VENDOR_DEVICE], %o1
/* An empty config? */
cmp %o5, DEV_NONE
beq .L_all_mctrl_next
/* Select function (APB or AHB) */
cmp %o5, DEV_APB_SLV
bne .L_find_ahb_memctrl
clr %o0
.L_find_apb_memctrl:
call _nomem_find_apb /* Scan for APB slave device */
nop
/* o3 = iobar address
* o4 = AHB Bus index
*
* REG ADR = ((iobar >> 12) & (iobar << 4) & 0xfff00) | "APB Base"
*/
ld [%o3 + AMBA_APB_IOBAR_OFS], %o5
srl %o5, 12, %o2
sll %o5, 4, %o5
and %o2, %o5, %o5
set 0xfff00, %o2
and %o2, %o5, %o5
sethi %hi(0xfff00000), %o2
and %o3, %o2, %o2
or %o5, %o2, %o5 /* Register base address */
ba .L_call_one_mem_handler
nop
.L_find_ahb_memctrl:
call _nomem_find_ahb /* Scan for AHB Slave or Master.
* o5 determine type. */
nop
clr %o5
/* Call the handler function if the hardware was found
*
* o0 = mem_handler
* o1 = Configuration address
* o2 = AHB Bus index
* o3 = APB Base register (if APB Slave)
*
* Constraints:
* i0-i7, l0, l1, l5, g1, g3-g7 may no be used.
*/
.L_call_one_mem_handler:
cmp %o0, %g0
be .L_all_mctrl_next
mov %l0, %o0 /* Mem handler pointer */
mov %o3, %o1 /* AMBA PnP Configuration address */
mov %o4, %o2 /* AHB Bus index */
ld [%l0 + MH_FUNC], %o7 /* Get Function pointer */
call %o7
mov %o5, %o3 /* APB Register Base Address */
inc %l1 /* Number of Memory controllers
* handled. */
/* Do next entry in mem_handlers */
.L_all_mctrl_next:
ba .L_do_one_mem_handler
add %l0, MH_STRUCT_SIZE, %l0
.L_all_mctrl_handled:
mov %g1, %o7 /* Restore return address */
retl
mov %l1, %o0
/* Generic Memory controller initialization routine (APB Registers)
*
* o0 = mem_handler structure pointer
* o1 = Configuration address
* o2 = AHB Bus index
* o3 = APB Base register
*
* Clobbered
* o0-o4
*/
_nomem_mctrl_init:
ld [%o0 + MH_PRIV], %o0 /* Get Private structure */
ld [%o0], %o1 /* Get Reg Mask */
and %o1, 0xff, %o1
add %o0, REGS_OFS, %o0 /* Point to first reg */
.L_do_one_reg:
andcc %o1, 0x1, %g0
beq .L_do_next_reg
ld [%o0], %o2
ld [%o3], %o4
and %o4, %o2, %o4
ld [%o0 + 4], %o2
or %o4, %o2, %o4
st %o4, [%o3]
.L_do_next_reg:
add %o0, REGS_SIZE, %o0
add %o3, 4, %o3
srl %o1, 1, %o1
cmp %o1, 0
bne .L_do_one_reg
nop
/* No more registers to write */
retl
nop
/* Generic Memory controller initialization routine (AHB Registers)
*
* o0 = mem_handler structure pointer
* o1 = Configuration address of memory controller
* o2 = AHB Bus index
*
* Clobbered
* o0-o5
*/
_nomem_ahbmctrl_init:
ld [%o0 + MH_PRIV], %o0 /* Get Private structure */
/* Get index of AHB MBAR to get registers from */
ld [%o0], %o5
add %o0, 4, %o0
/* Get Address of MBAR in PnP info */
add %o5, 4, %o5
sll %o5, 2, %o5
add %o5, %o1, %o5 /* Address of MBAR */
/* Get Address of registers from PnP information
* Address is in AHB I/O format, i.e. relative to bus
*
* ADR = (iobar & (iobar << 16) & 0xfff00000)
* IOADR = (ADR >> 12) | "APB Base"
*/
ld [%o5], %o5
sll %o5, 16, %o4
and %o5, %o4, %o5
sethi %hi(0xfff00000), %o4
and %o5, %o4, %o5 /* ADR */
and %o4, %o1, %o4
srl %o5, 12, %o5
or %o5, %o4, %o3 /* IOADR in o3 */
ld [%o0], %o1 /* Get Reg Mask */
and %o1, 0xff, %o1
add %o0, REGS_OFS, %o0 /* Point to first reg */
.L_do_one_ahbreg:
andcc %o1, 0x1, %g0
beq .L_do_next_reg
ld [%o0], %o2
ld [%o3], %o4
and %o4, %o2, %o4
ld [%o0 + 4], %o2
or %o4, %o2, %o4
st %o4, [%o3]
.L_do_next_ahbreg:
add %o0, REGS_SIZE, %o0
add %o3, 4, %o3
srl %o1, 1, %o1
cmp %o1, 0
bne .L_do_one_reg
nop
/* No more registers to write */
retl
nop
|