1/* head.S: kernel entry point for FR-V kernel
2 *
3 * Copyright (C) 2003, 2004 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12#include <linux/threads.h>
13#include <linux/linkage.h>
14#include <asm/thread_info.h>
15#include <asm/ptrace.h>
16#include <asm/page.h>
17#include <asm/spr-regs.h>
18#include <asm/mb86943a.h>
19#include <asm/cache.h>
20#include "head.inc"
21
22###############################################################################
23#
24# void _boot(unsigned long magic, char *command_line) __attribute__((noreturn))
25#
26# - if magic is 0xdead1eaf, then command_line is assumed to point to the kernel
27#   command line string
28#
29###############################################################################
30	.section	.text.head,"ax"
31	.balign		4
32
33	.globl		_boot, __head_reference
34        .type		_boot,@function
35_boot:
36__head_reference:
37	sethi.p		%hi(LED_ADDR),gr30
38	setlo		%lo(LED_ADDR),gr30
39
40	LEDS		0x0000
41
42	# calculate reference address for PC-relative stuff
43	call		0f
440:	movsg		lr,gr26
45	addi		gr26,#__head_reference-0b,gr26
46
47	# invalidate and disable both of the caches and turn off the memory access checking
48	dcef		@(gr0,gr0),1
49	bar
50
51	sethi.p		%hi(~(HSR0_ICE|HSR0_DCE|HSR0_CBM|HSR0_EIMMU|HSR0_EDMMU)),gr4
52	setlo		%lo(~(HSR0_ICE|HSR0_DCE|HSR0_CBM|HSR0_EIMMU|HSR0_EDMMU)),gr4
53	movsg		hsr0,gr5
54	and		gr4,gr5,gr5
55	movgs		gr5,hsr0
56	movsg		hsr0,gr5
57
58	LEDS		0x0001
59
60	icei		@(gr0,gr0),1
61	dcei		@(gr0,gr0),1
62	bar
63
64	# turn the instruction cache back on
65	sethi.p		%hi(HSR0_ICE),gr4
66	setlo		%lo(HSR0_ICE),gr4
67	movsg		hsr0,gr5
68	or		gr4,gr5,gr5
69	movgs		gr5,hsr0
70	movsg		hsr0,gr5
71
72	bar
73
74	LEDS		0x0002
75
76	# retrieve the parameters (including command line) before we overwrite them
77	sethi.p		%hi(0xdead1eaf),gr7
78	setlo		%lo(0xdead1eaf),gr7
79	subcc		gr7,gr8,gr0,icc0
80	bne		icc0,#0,__head_no_parameters
81
82	sethi.p		%hi(redboot_command_line-1),gr6
83	setlo		%lo(redboot_command_line-1),gr6
84	sethi.p		%hi(__head_reference),gr4
85	setlo		%lo(__head_reference),gr4
86	sub		gr6,gr4,gr6
87	add.p		gr6,gr26,gr6
88	subi		gr9,#1,gr9
89	setlos.p	#511,gr4
90	setlos		#1,gr5
91
92__head_copy_cmdline:
93	ldubu.p		@(gr9,gr5),gr16
94	subicc		gr4,#1,gr4,icc0
95	stbu.p		gr16,@(gr6,gr5)
96	subicc		gr16,#0,gr0,icc1
97	bls		icc0,#0,__head_end_cmdline
98	bne		icc1,#1,__head_copy_cmdline
99__head_end_cmdline:
100	stbu		gr0,@(gr6,gr5)
101__head_no_parameters:
102
103###############################################################################
104#
105# we need to relocate the SDRAM to 0x00000000 (linux) or 0xC0000000 (uClinux)
106# - note that we're going to have to run entirely out of the icache whilst
107#   fiddling with the SDRAM controller registers
108#
109###############################################################################
110#ifdef CONFIG_MMU
111	call		__head_fr451_describe_sdram
112
113#else
114	movsg		psr,gr5
115	srli		gr5,#28,gr5
116	subicc		gr5,#3,gr0,icc0
117	beq		icc0,#0,__head_fr551_sdram
118
119	call		__head_fr401_describe_sdram
120	bra		__head_do_sdram
121
122__head_fr551_sdram:
123	call		__head_fr555_describe_sdram
124	LEDS		0x000d
125
126__head_do_sdram:
127#endif
128
129	# preload the registers with invalid values in case any DBR/DARS are marked not present
130	sethi.p		%hi(0xfe000000),gr17		; unused SDRAM DBR value
131	setlo		%lo(0xfe000000),gr17
132	or.p		gr17,gr0,gr20
133	or		gr17,gr0,gr21
134	or.p		gr17,gr0,gr22
135	or		gr17,gr0,gr23
136
137	# consult the SDRAM controller CS address registers
138	cld		@(gr14,gr0 ),gr20,	cc0,#1	; DBR0 / DARS0
139	cld		@(gr14,gr11),gr21,	cc1,#1	; DBR1 / DARS1
140	cld		@(gr14,gr12),gr22,	cc2,#1	; DBR2 / DARS2
141	cld.p		@(gr14,gr13),gr23,	cc3,#1	; DBR3 / DARS3
142
143	sll		gr20,gr15,gr20			; shift values up for FR551
144	sll		gr21,gr15,gr21
145	sll		gr22,gr15,gr22
146	sll		gr23,gr15,gr23
147
148	LEDS		0x0003
149
150	# assume the lowest valid CS line to be the SDRAM base and get its address
151	subcc		gr20,gr17,gr0,icc0
152	subcc.p		gr21,gr17,gr0,icc1
153	subcc		gr22,gr17,gr0,icc2
154	subcc.p		gr23,gr17,gr0,icc3
155	ckne		icc0,cc4			; T if DBR0 != 0xfe000000
156	ckne		icc1,cc5
157	ckne		icc2,cc6
158	ckne		icc3,cc7
159	cor		gr23,gr0,gr24,		cc7,#1	; GR24 = SDRAM base
160	cor		gr22,gr0,gr24,		cc6,#1
161	cor		gr21,gr0,gr24,		cc5,#1
162	cor		gr20,gr0,gr24,		cc4,#1
163
164	# calculate the displacement required to get the SDRAM into the right place in memory
165	sethi.p		%hi(__sdram_base),gr16
166	setlo		%lo(__sdram_base),gr16
167	sub		gr16,gr24,gr16			; delta = __sdram_base - DBRx
168
169	# calculate the new values to go in the controller regs
170	cadd.p		gr20,gr16,gr20,		cc4,#1	; DCS#0 (new) = DCS#0 (old) + delta
171	cadd		gr21,gr16,gr21,		cc5,#1
172	cadd.p		gr22,gr16,gr22,		cc6,#1
173	cadd		gr23,gr16,gr23,		cc7,#1
174
175	srl		gr20,gr15,gr20			; shift values down for FR551
176	srl		gr21,gr15,gr21
177	srl		gr22,gr15,gr22
178	srl		gr23,gr15,gr23
179
180	# work out the address at which the reg updater resides and lock it into icache
181	# also work out the address the updater will jump to when finished
182	sethi.p		%hi(__head_move_sdram-__head_reference),gr18
183	setlo		%lo(__head_move_sdram-__head_reference),gr18
184	sethi.p		%hi(__head_sdram_moved-__head_reference),gr19
185	setlo		%lo(__head_sdram_moved-__head_reference),gr19
186	add.p		gr18,gr26,gr18
187	add		gr19,gr26,gr19
188	add.p		gr19,gr16,gr19			; moved = addr + (__sdram_base - DBRx)
189	add		gr18,gr5,gr4			; two cachelines probably required
190
191	icpl		gr18,gr0,#1			; load and lock the cachelines
192	icpl		gr4,gr0,#1
193	LEDS		0x0004
194	membar
195	bar
196	jmpl		@(gr18,gr0)
197
198	.balign		L1_CACHE_BYTES
199__head_move_sdram:
200	cst		gr20,@(gr14,gr0 ),	cc4,#1
201	cst		gr21,@(gr14,gr11),	cc5,#1
202	cst		gr22,@(gr14,gr12),	cc6,#1
203	cst		gr23,@(gr14,gr13),	cc7,#1
204	cld		@(gr14,gr0 ),gr20,	cc4,#1
205	cld		@(gr14,gr11),gr21,	cc5,#1
206	cld		@(gr14,gr12),gr22,	cc4,#1
207	cld		@(gr14,gr13),gr23,	cc7,#1
208	bar
209	membar
210	jmpl		@(gr19,gr0)
211
212	.balign		L1_CACHE_BYTES
213__head_sdram_moved:
214	icul		gr18
215	add		gr18,gr5,gr4
216	icul		gr4
217	icei		@(gr0,gr0),1
218	dcei		@(gr0,gr0),1
219
220	LEDS		0x0005
221
222	# recalculate reference address
223	call		0f
2240:	movsg		lr,gr26
225	addi		gr26,#__head_reference-0b,gr26
226
227
228###############################################################################
229#
230# move the kernel image down to the bottom of the SDRAM
231#
232###############################################################################
233	sethi.p		%hi(__kernel_image_size_no_bss+15),gr4
234	setlo		%lo(__kernel_image_size_no_bss+15),gr4
235	srli.p		gr4,#4,gr4			; count
236	or		gr26,gr26,gr16			; source
237
238	sethi.p		%hi(__sdram_base),gr17		; destination
239	setlo		%lo(__sdram_base),gr17
240
241	setlos		#8,gr5
242	sub.p		gr16,gr5,gr16			; adjust src for LDDU
243	sub		gr17,gr5,gr17			; adjust dst for LDDU
244
245	sethi.p		%hi(__head_move_kernel-__head_reference),gr18
246	setlo		%lo(__head_move_kernel-__head_reference),gr18
247	sethi.p		%hi(__head_kernel_moved-__head_reference+__sdram_base),gr19
248	setlo		%lo(__head_kernel_moved-__head_reference+__sdram_base),gr19
249	add		gr18,gr26,gr18
250	icpl		gr18,gr0,#1
251	jmpl		@(gr18,gr0)
252
253	.balign		32
254__head_move_kernel:
255	lddu		@(gr16,gr5),gr10
256	lddu		@(gr16,gr5),gr12
257	stdu.p		gr10,@(gr17,gr5)
258	subicc		gr4,#1,gr4,icc0
259	stdu.p		gr12,@(gr17,gr5)
260	bhi		icc0,#0,__head_move_kernel
261	jmpl		@(gr19,gr0)
262
263	.balign		32
264__head_kernel_moved:
265	icul		gr18
266	icei		@(gr0,gr0),1
267	dcei		@(gr0,gr0),1
268
269	LEDS		0x0006
270
271	# recalculate reference address
272	call		0f
2730:	movsg		lr,gr26
274	addi		gr26,#__head_reference-0b,gr26
275
276
277###############################################################################
278#
279# rearrange the iomem map and set the protection registers
280#
281###############################################################################
282
283#ifdef CONFIG_MMU
284	LEDS		0x3301
285	call		__head_fr451_set_busctl
286	LEDS		0x3303
287	call		__head_fr451_survey_sdram
288	LEDS		0x3305
289	call		__head_fr451_set_protection
290
291#else
292	movsg		psr,gr5
293	srli		gr5,#PSR_IMPLE_SHIFT,gr5
294	subicc		gr5,#PSR_IMPLE_FR551,gr0,icc0
295	beq		icc0,#0,__head_fr555_memmap
296	subicc		gr5,#PSR_IMPLE_FR451,gr0,icc0
297	beq		icc0,#0,__head_fr451_memmap
298
299	LEDS		0x3101
300	call		__head_fr401_set_busctl
301	LEDS		0x3103
302	call		__head_fr401_survey_sdram
303	LEDS		0x3105
304	call		__head_fr401_set_protection
305	bra		__head_done_memmap
306
307__head_fr451_memmap:
308	LEDS		0x3301
309	call		__head_fr401_set_busctl
310	LEDS		0x3303
311	call		__head_fr401_survey_sdram
312	LEDS		0x3305
313	call		__head_fr451_set_protection
314	bra		__head_done_memmap
315
316__head_fr555_memmap:
317	LEDS		0x3501
318	call		__head_fr555_set_busctl
319	LEDS		0x3503
320	call		__head_fr555_survey_sdram
321	LEDS		0x3505
322	call		__head_fr555_set_protection
323
324__head_done_memmap:
325#endif
326	LEDS		0x0007
327
328###############################################################################
329#
330# turn the data cache and MMU on
331# - for the FR451 this'll mean that the window through which the kernel is
332#   viewed will change
333#
334###############################################################################
335
336#ifdef CONFIG_MMU
337#define MMUMODE		HSR0_EIMMU|HSR0_EDMMU|HSR0_EXMMU|HSR0_EDAT|HSR0_XEDAT
338#else
339#define MMUMODE		HSR0_EIMMU|HSR0_EDMMU
340#endif
341
342	movsg		hsr0,gr5
343
344	sethi.p		%hi(MMUMODE),gr4
345	setlo		%lo(MMUMODE),gr4
346	or		gr4,gr5,gr5
347
348#if defined(CONFIG_FRV_DEFL_CACHE_WTHRU)
349	sethi.p		%hi(HSR0_DCE|HSR0_CBM_WRITE_THRU),gr4
350	setlo		%lo(HSR0_DCE|HSR0_CBM_WRITE_THRU),gr4
351#elif defined(CONFIG_FRV_DEFL_CACHE_WBACK)
352	sethi.p		%hi(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4
353	setlo		%lo(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4
354#elif defined(CONFIG_FRV_DEFL_CACHE_WBEHIND)
355	sethi.p		%hi(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4
356	setlo		%lo(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4
357
358	movsg		psr,gr6
359	srli		gr6,#24,gr6
360	cmpi		gr6,#0x50,icc0		// FR451
361	beq		icc0,#0,0f
362	cmpi		gr6,#0x40,icc0		// FR405
363	bne		icc0,#0,1f
3640:
365	# turn off write-allocate
366	sethi.p		%hi(HSR0_NWA),gr6
367	setlo		%lo(HSR0_NWA),gr6
368	or		gr4,gr6,gr4
3691:
370
371#else
372#error No default cache configuration set
373#endif
374
375	or		gr4,gr5,gr5
376	movgs		gr5,hsr0
377	bar
378
379	LEDS		0x0008
380
381	sethi.p		%hi(__head_mmu_enabled),gr19
382	setlo		%lo(__head_mmu_enabled),gr19
383	jmpl		@(gr19,gr0)
384
385__head_mmu_enabled:
386	icei		@(gr0,gr0),#1
387	dcei		@(gr0,gr0),#1
388
389	LEDS		0x0009
390
391#ifdef CONFIG_MMU
392	call		__head_fr451_finalise_protection
393#endif
394
395	LEDS		0x000a
396
397###############################################################################
398#
399# set up the runtime environment
400#
401###############################################################################
402
403	# clear the BSS area
404	sethi.p		%hi(__bss_start),gr4
405	setlo		%lo(__bss_start),gr4
406	sethi.p		%hi(_end),gr5
407	setlo		%lo(_end),gr5
408	or.p		gr0,gr0,gr18
409	or		gr0,gr0,gr19
410
4110:
412	stdi		gr18,@(gr4,#0)
413	stdi		gr18,@(gr4,#8)
414	stdi		gr18,@(gr4,#16)
415	stdi.p		gr18,@(gr4,#24)
416	addi		gr4,#24,gr4
417	subcc		gr5,gr4,gr0,icc0
418	bhi		icc0,#2,0b
419
420	LEDS		0x000b
421
422	# save the SDRAM details
423	sethi.p		%hi(__sdram_old_base),gr4
424	setlo		%lo(__sdram_old_base),gr4
425	st		gr24,@(gr4,gr0)
426
427	sethi.p		%hi(__sdram_base),gr5
428	setlo		%lo(__sdram_base),gr5
429	sethi.p		%hi(memory_start),gr4
430	setlo		%lo(memory_start),gr4
431	st		gr5,@(gr4,gr0)
432
433	add		gr25,gr5,gr25
434	sethi.p		%hi(memory_end),gr4
435	setlo		%lo(memory_end),gr4
436	st		gr25,@(gr4,gr0)
437
438	# point the TBR at the kernel trap table
439	sethi.p		%hi(__entry_kerneltrap_table),gr4
440	setlo		%lo(__entry_kerneltrap_table),gr4
441	movgs		gr4,tbr
442
443	# set up the exception frame for init
444	sethi.p		%hi(__kernel_frame0_ptr),gr28
445	setlo		%lo(__kernel_frame0_ptr),gr28
446	sethi.p		%hi(_gp),gr16
447	setlo		%lo(_gp),gr16
448	sethi.p		%hi(__entry_usertrap_table),gr4
449	setlo		%lo(__entry_usertrap_table),gr4
450
451	lddi		@(gr28,#0),gr28		; load __frame & current
452	ldi.p		@(gr29,#4),gr15		; set current_thread
453
454	or		gr0,gr0,fp
455	or		gr28,gr0,sp
456
457	sti.p		gr4,@(gr28,REG_TBR)
458	setlos		#ISR_EDE|ISR_DTT_DIVBYZERO|ISR_EMAM_EXCEPTION,gr5
459	movgs		gr5,isr
460
461	# turn on and off various CPU services
462	movsg		psr,gr22
463	sethi.p		%hi(#PSR_EM|PSR_EF|PSR_CM|PSR_NEM),gr4
464	setlo		%lo(#PSR_EM|PSR_EF|PSR_CM|PSR_NEM),gr4
465	or		gr22,gr4,gr22
466	movgs		gr22,psr
467
468	andi		gr22,#~(PSR_PIL|PSR_PS|PSR_S),gr22
469	ori		gr22,#PSR_ET,gr22
470	sti		gr22,@(gr28,REG_PSR)
471
472
473###############################################################################
474#
475# set up the registers and jump into the kernel
476#
477###############################################################################
478
479	LEDS		0x000c
480
481	# initialise the processor and the peripherals
482	#call		SYMBOL_NAME(processor_init)
483	#call		SYMBOL_NAME(unit_init)
484	#LEDS		0x0aff
485
486	sethi.p		#0xe5e5,gr3
487	setlo		#0xe5e5,gr3
488	or.p		gr3,gr0,gr4
489	or		gr3,gr0,gr5
490	or.p		gr3,gr0,gr6
491	or		gr3,gr0,gr7
492	or.p		gr3,gr0,gr8
493	or		gr3,gr0,gr9
494	or.p		gr3,gr0,gr10
495	or		gr3,gr0,gr11
496	or.p		gr3,gr0,gr12
497	or		gr3,gr0,gr13
498	or.p		gr3,gr0,gr14
499	or		gr3,gr0,gr17
500	or.p		gr3,gr0,gr18
501	or		gr3,gr0,gr19
502	or.p		gr3,gr0,gr20
503	or		gr3,gr0,gr21
504	or.p		gr3,gr0,gr23
505	or		gr3,gr0,gr24
506	or.p		gr3,gr0,gr25
507	or		gr3,gr0,gr26
508	or.p		gr3,gr0,gr27
509#	or		gr3,gr0,gr30
510	or		gr3,gr0,gr31
511	movgs		gr0,lr
512	movgs		gr0,lcr
513	movgs		gr0,ccr
514	movgs		gr0,cccr
515
516	# initialise the virtual interrupt handling
517	subcc		gr0,gr0,gr0,icc2		/* set Z, clear C */
518
519#ifdef CONFIG_MMU
520	movgs		gr3,scr2
521	movgs		gr3,scr3
522#endif
523
524	LEDS		0x0fff
525
526	# invoke the debugging stub if present
527	# - arch/frv/kernel/debug-stub.c will shift control directly to init/main.c
528	#   (it will not return here)
529	break
530	.globl		__debug_stub_init_break
531__debug_stub_init_break:
532
533	# however, if you need to use an ICE, and don't care about using any userspace
534	# debugging tools (such as the ptrace syscall), you can just step over the break
535	# above and get to the kernel this way
536	# look at arch/frv/kernel/debug-stub.c: debug_stub_init() to see what you've missed
537	call		start_kernel
538
539	.globl		__head_end
540__head_end:
541	.size		_boot, .-_boot
542
543	# provide a point for GDB to place a break
544	.section	.text.start,"ax"
545	.globl		_start
546	.balign		4
547_start:
548	call		_boot
549
550	.previous
551###############################################################################
552#
553# split a tile off of the region defined by GR8-GR9
554#
555#	ENTRY:			EXIT:
556# GR4	-			IAMPR value representing tile
557# GR5	-			DAMPR value representing tile
558# GR6	-			IAMLR value representing tile
559# GR7	-			DAMLR value representing tile
560# GR8	region base pointer	[saved]
561# GR9	region top pointer	updated to exclude new tile
562# GR11	xAMLR mask		[saved]
563# GR25	SDRAM size		[saved]
564# GR30	LED address		[saved]
565#
566# - GR8 and GR9 should be rounded up/down to the nearest megabyte before calling
567#
568###############################################################################
569	.globl		__head_split_region
570	.type		__head_split_region,@function
571__head_split_region:
572	subcc.p		gr9,gr8,gr4,icc0
573	setlos		#31,gr5
574	scan.p		gr4,gr0,gr6
575	beq		icc0,#0,__head_region_empty
576	sub.p		gr5,gr6,gr6			; bit number of highest set bit (1MB=>20)
577	setlos		#1,gr4
578	sll.p		gr4,gr6,gr4			; size of region (1 << bitno)
579	subi		gr6,#17,gr6			; 1MB => 0x03
580	slli.p		gr6,#4,gr6			; 1MB => 0x30
581	sub		gr9,gr4,gr9			; move uncovered top down
582
583	or		gr9,gr6,gr4
584	ori		gr4,#xAMPRx_S_USER|xAMPRx_C_CACHED|xAMPRx_V,gr4
585	or.p		gr4,gr0,gr5
586
587	and		gr4,gr11,gr6
588	and.p		gr5,gr11,gr7
589	bralr
590
591__head_region_empty:
592	or.p		gr0,gr0,gr4
593	or		gr0,gr0,gr5
594	or.p		gr0,gr0,gr6
595	or		gr0,gr0,gr7
596	bralr
597	.size		__head_split_region, .-__head_split_region
598
599###############################################################################
600#
601# write the 32-bit hex number in GR8 to ttyS0
602#
603###############################################################################
604