summaryrefslogtreecommitdiff
path: root/arch/arm/mach-mx23/emi.S
blob: 5799ca23be8f8f5d67670f5bd05983d3baebb5fd (plain)
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
/*
 * Freescale MX23 low level RAM frequency manipulation
 *
 * Author: Vitaly Wool <vital@embeddedalley.com>
 *
 * Copyright 2008-2010 Freescale Semiconductor, Inc.
 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <asm/system.h>
#include <asm/pgtable-hwdef.h>
#include <mach/hardware.h>
#include <mach/regs-power.h>
#include <mach/regs-emi.h>
#include "regs-clkctrl.h"
#include "regs-dram.h"
#include "regs-digctl.h"

/* TODO should be move to clock.h */
#define SCALING_DATA_EMI_DIV_OFFSET     0
#define SCALING_DATA_FRAC_DIV_OFFSET    4
#define SCALING_DATA_CUR_FREQ_OFFSET    8
#define SCALING_DATA_NEW_FREQ_OFFSET    12
#define REGS_CLKCTRL_BASE MX23_SOC_IO_ADDRESS(CLKCTRL_PHYS_ADDR)
#define HW_CLKCTRL_EMI_ADDR (REGS_CLKCTRL_BASE + HW_CLKCTRL_EMI)
#define HW_CLKCTRL_FRAC_ADDR (REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC)
#define HW_EMI_CTRL_ADDR MX23_SOC_IO_ADDRESS(REGS_EMI_PHYS + HW_EMI_CTRL)
#define HW_DRAM_CTL04_ADDR MX23_SOC_IO_ADDRESS(REGS_DRAM_PHYS + HW_DRAM_CTL04)
#define HW_CLKCTRL_CLKSEQ_ADDR (REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ)
.global cpu_arm926_switch_mm

.align 8
ENTRY(mxs_ram_freq_scale)
	stmfd	sp!, {r1 - r9, lr}

	ldr	r5, [r0, #SCALING_DATA_NEW_FREQ_OFFSET]
	ldr	r6, [r0, #SCALING_DATA_CUR_FREQ_OFFSET]
	ldr	r7, [r0, #SCALING_DATA_EMI_DIV_OFFSET]
	ldr	r8, [r0, #SCALING_DATA_FRAC_DIV_OFFSET]

	adr	r9, __mxs_temp_stack

	@ clean cache
	ldr	r1, __mxs_flush_cache_addr
	mov	lr, pc
	mov	pc, r1

	@ put DRAM into self refresh
	ldr	r0, __mx23_dram_ctl00
	ldr	r1, [r0, #0x20]
	orr	r1, r1, #(1 << 8)
	str	r1, [r0, #0x20]
	@ wait for it to actually happen
	ldr	r0, __mx23_dram_emi00
1:	ldr	r1, [r0, #0x10]
	tst	r1, #(1 << 1)
	beq	1b
	nop

	@ prepare for change
	cmp	r5, #24
	bgt	2f
	bl	mx23_ram_24M_set_timings
	b	100f
2:	cmp	r5, #48
	bgt	3f
	bl	mx23_ram_48M_set_timings
	b	100f
3:	cmp	r5, #60
	bgt	4f
	bl	mx23_ram_60M_set_timings
	b	100f
4:	cmp	r5, #80
	bgt	5f
	bl	mx23_ram_80M_set_timings
	b	100f
5:	cmp	r5, #96
	bgt	6f
	bl	mx23_ram_96M_set_timings
	b	100f
6:	cmp	r5, #120
	bgt	7f
	bl	mx23_ram_120M_set_timings
	b	100f
7:	cmp     r5, #133
	bgt	8f
	bl	mx23_ram_133M_set_timings
	b	100f
8:	bl	mx23_ram_150M_set_timings

100:
	@ RAM to clk from xtal
	mov	r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x000000FF)
	orr	r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x0000FF00)
	orr	r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x00FF0000)
	orr	r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0xFF000000)
	mov	r1, #(1<<6)
	str	r1, [r0, #4]
	mov	r0, #(HW_CLKCTRL_EMI_ADDR & 0x000000FF)
	orr	r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x0000FF00)
	orr	r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x00FF0000)
	orr	r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0xFF000000)
101:	ldr     r1, [r0]
	tst     r1, #BM_CLKCTRL_EMI_BUSY_REF_XTAL
	bne     101b

	@When are using the DLL, reset the DRAM controller and DLL
	@start point logic (via DLL_SHIFT_RESET and DLL_RESET).
	@After changing clock dividers and loading
	@the new HW_DRAM_CTL* parameters, we will wait for a new DLL_LOCK

	@todo - for DRAM's that will use DLL bypass (non DDR1)
	@	we should not use DLL_RESET and DLL_SHIFT_RESET.

	mov     r0,     #(HW_EMI_CTRL_ADDR & 0x000000FF)
	orr     r0, r0, #(HW_EMI_CTRL_ADDR & 0x0000FF00)
	orr     r0, r0, #(HW_EMI_CTRL_ADDR & 0x00FF0000)
	orr     r0, r0, #(HW_EMI_CTRL_ADDR & 0xFF000000)
	ldr     r1, [r0]            @read values of HW_EMI_CTRL into R1
	orr r1, r1, #BM_EMI_CTRL_DLL_SHIFT_RESET    @Set these 2 fields.
	orr r1, r1, #BM_EMI_CTRL_DLL_RESET
	str     r1, [r0]            @write back values to HW_EMI_CTRL register.

	bl	__mx23_emi_set_values

	@ EMI back to PLL
	mov	r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x000000FF)
	orr	r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x0000FF00)
	orr	r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x00FF0000)
	orr	r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0xFF000000)
	mov	r1, #(1<<6)
	str	r1, [r0, #8]

	@ Wait for BUSY_REF_EMI, to assure new clock dividers
	@ are done transferring
	mov	r0, #(HW_CLKCTRL_EMI_ADDR & 0x000000FF)
	orr	r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x0000FF00)
	orr	r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x00FF0000)
	orr	r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0xFF000000)
1:	ldr	r1, [r0]
	tst	r1, #BM_CLKCTRL_EMI_BUSY_REF_EMI
	bne	1b
	str	r1, [r0]

@todo - for DRAM's that will use DLL bypass (non DDR1)
@we should not use DLL_RESET and DLL_SHIFT_RESET.
@	if(HW_DRAM_CTL04.B.DLL_BYPASS_MODE==0)
@	{
@
@	    Clear the DLL_RESET and DLL_SHIFT_RESET bitfields
@	    (\todo - is that necessary?
@	     they were already set previously to reset
@            the controller/DLL start point,
@	     so clearing should have no effect..)
@
@	     BF_CS2(EMI_CTRL, DLL_RESET, 0, DLL_SHIFT_RESET, 0);

	mov     r0,     #(HW_EMI_CTRL_ADDR & 0x000000FF)
	orr     r0, r0, #(HW_EMI_CTRL_ADDR & 0x0000FF00)
	orr     r0, r0, #(HW_EMI_CTRL_ADDR & 0x00FF0000)
	orr     r0, r0, #(HW_EMI_CTRL_ADDR & 0xFF000000)
	ldr     r1, [r0]
	bic r1, #BM_EMI_CTRL_DLL_SHIFT_RESET
	bic r1, #BM_EMI_CTRL_DLL_RESET
	str     r1, [r0]

@Wait for BUSY_REF_EMI, to assure new clock dividers are done transferring.
@(\todo is that necessary.  we already did this above.
	mov     r0,     #(HW_CLKCTRL_EMI_ADDR & 0x000000FF)
	orr     r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x0000FF00)
	orr     r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x00FF0000)
	orr     r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0xFF000000)
66:	ldr     r1, [r0]
	tst     r1, #BM_CLKCTRL_EMI_BUSY_REF_EMI
	bne     66b

@ Wait for DLL locking.
@        while(HW_DRAM_CTL04.B.DLLLOCKREG==0);

	mov     r0,     #(HW_DRAM_CTL04_ADDR & 0x000000FF)
	orr     r0, r0, #(HW_DRAM_CTL04_ADDR & 0x0000FF00)
	orr     r0, r0, #(HW_DRAM_CTL04_ADDR & 0x00FF0000)
	orr     r0, r0, #(HW_DRAM_CTL04_ADDR & 0xFF000000)
77:	ldr     r1, [r0]
	tst     r1, #BM_DRAM_CTL04_DLLLOCKREG
	beq     77b


	@ resttore normal DRAM mode
        ldr     r0, __mx23_dram_ctl00
        ldr     r1, [r0, #0x20]
        bic     r1, r1, #(1 << 8)
        str     r1, [r0, #0x20]

        @ wait for it to actually happen
        ldr     r0, __mx23_dram_emi00
102:    ldr     r1, [r0, #0x10]
        tst     r1, #(1 << 1)
        bne     102b

@ restore regs and return
	ldmfd   sp!, {r1 - r9, lr}
	mov	pc, lr

	.space	0x100
__mxs_temp_stack:
	.word	0

#include "emi.inc"

__mxs_flush_cache_addr:
	.word	arm926_flush_kern_cache_all

ENTRY(mxs_ram_funcs_sz)
	.word	. - mxs_ram_freq_scale