Rebased from upstream / out of band repository.
[librecmc/librecmc.git] / target / linux / ath79 / image / lzma-loader / src / head.S
1 /*
2  * LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards
3  *
4  * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
5  *
6  * Some parts of this code was based on the libreCMC specific lzma-loader
7  * for the BCM47xx and ADM5120 based boards:
8  *      Copyright (C) 2004 Manuel Novoa III (mjn3@codepoet.org)
9  *      Copyright (C) 2005 by Oleg I. Vdovikin <oleg@cs.msu.su>
10  *
11  * This program is free software; you can redistribute it and/or modify it
12  * under the terms of the GNU General Public License version 2 as published
13  * by the Free Software Foundation.
14  */
15
16 #include <asm/asm.h>
17 #include <asm/regdef.h>
18 #include "cp0regdef.h"
19 #include "cacheops.h"
20 #include "config.h"
21
22 #define KSEG0           0x80000000
23
24         .macro  ehb
25         sll     zero, 3
26         .endm
27
28         .text
29
30 LEAF(startup)
31         .set noreorder
32         .set mips32
33
34         mtc0    zero, CP0_WATCHLO       # clear watch registers
35         mtc0    zero, CP0_WATCHHI
36         mtc0    zero, CP0_CAUSE         # clear before writing status register
37
38         mfc0    t0, CP0_STATUS
39         li      t1, 0x1000001f
40         or      t0, t1
41         xori    t0, 0x1f
42         mtc0    t0, CP0_STATUS
43         ehb
44
45         /*
46          * Some bootloaders set the 'Kseg0 coherency algorithm' to
47          * 'Cacheable, noncoherent, write-through, no write allocate'
48          * and this cause performance issues. Let's go and change it to
49          * 'Cacheable, noncoherent, write-back, write allocate'
50          */
51         mfc0    t0, CP0_CONFIG
52         li      t1, ~7                  #~CONF_CM_CMASK
53         and     t0, t1
54         ori     t0, 3                   #CONF_CM_CACHABLE_NONCOHERENT
55         mtc0    t0, CP0_CONFIG
56         nop
57
58         mtc0    zero, CP0_COUNT
59         mtc0    zero, CP0_COMPARE
60         ehb
61
62         la      t0, __reloc_label       # get linked address of label
63         bal     __reloc_label           # branch and link to label to
64         nop                             # get actual address
65 __reloc_label:
66         subu    t0, ra, t0              # get reloc_delta
67
68         beqz    t0, __reloc_done         # if delta is 0 we are in the right place
69         nop
70
71         /* Copy our code to the right place */
72         la      t1, _code_start         # get linked address of _code_start
73         la      t2, _code_end           # get linked address of _code_end
74         addu    t0, t0, t1              # calculate actual address of _code_start
75
76 __reloc_copy:
77         lw      t3, 0(t0)
78         sw      t3, 0(t1)
79         add     t1, 4
80         blt     t1, t2, __reloc_copy
81         add     t0, 4
82
83         /* flush cache */
84         la      t0, _code_start
85         la      t1, _code_end
86
87         li      t2, ~(CONFIG_CACHELINE_SIZE - 1)
88         and     t0, t2
89         and     t1, t2
90         li      t2, CONFIG_CACHELINE_SIZE
91
92         b       __flush_check
93         nop
94
95 __flush_line:
96         cache   Hit_Writeback_Inv_D, 0(t0)
97         cache   Hit_Invalidate_I, 0(t0)
98         add     t0, t2
99
100 __flush_check:
101         bne     t0, t1, __flush_line
102         nop
103
104         sync
105
106 __reloc_done:
107
108         /* clear bss */
109         la      t0, _bss_start
110         la      t1, _bss_end
111         b       __bss_check
112         nop
113
114 __bss_fill:
115         sw      zero, 0(t0)
116         addi    t0, 4
117
118 __bss_check:
119         bne     t0, t1, __bss_fill
120         nop
121
122         /* Setup new "C" stack */
123         la      sp, _stack
124
125         /* reserve stack space for a0-a3 registers */
126         subu    sp, 16
127
128         /* jump to the decompressor routine */
129         la      t0, loader_main
130         jr      t0
131         nop
132
133         .set reorder
134 END(startup)