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