sram242x.S 10.3 KB
Newer Older
1
/*
2
 * linux/arch/arm/mach-omap2/sram242x.S
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *
 * Omap2 specific functions that need to be run in internal SRAM
 *
 * (C) Copyright 2004
 * Texas Instruments, <www.ti.com>
 * Richard Woodruff <r-woodruff2@ti.com>
 *
 * 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., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
24 25 26 27 28 29
 *
 * Richard Woodruff notes that any changes to this code must be carefully
 * audited and tested to ensure that they don't cause a TLB miss while
 * the SDRAM is inaccessible.  Such a situation will crash the system
 * since it will cause the ARM MMU to attempt to walk the page tables.
 * These crashes may be intermittent.
30 31
 */
#include <linux/linkage.h>
32

33
#include <asm/assembler.h>
34

35
#include <mach/hardware.h>
36

37
#include "iomap.h"
38 39
#include "prm2xxx_3xxx.h"
#include "cm2xxx_3xxx.h"
40
#include "sdrc.h"
41 42 43

	.text

44
	.align	3
45
ENTRY(omap242x_sram_ddr_init)
46 47 48 49 50 51
	stmfd	sp!, {r0 - r12, lr}	@ save registers on stack

	mov	r12, r2			@ capture CS1 vs CS0
	mov	r8, r3			@ capture force parameter

	/* frequency shift down */
52
	ldr	r2, omap242x_sdi_cm_clksel2_pll	@ get address of dpllout reg
53 54 55 56 57 58 59 60
	mov	r3, #0x1		@ value for 1x operation
	str	r3, [r2]		@ go to L1-freq operation

	/* voltage shift down */
	mov r9, #0x1			@ set up for L1 voltage call
	bl voltage_shift		@ go drop voltage

	/* dll lock mode */
61
	ldr	r11, omap242x_sdi_sdrc_dlla_ctrl	@ addr of dlla ctrl
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
	ldr	r10, [r11]		@ get current val
	cmp	r12, #0x1		@ cs1 base (2422 es2.05/1)
	addeq	r11, r11, #0x8		@ if cs1 base, move to DLLB
	mvn	r9, #0x4		@ mask to get clear bit2
	and	r10, r10, r9		@ clear bit2 for lock mode.
	orr	r10, r10, #0x8		@ make sure DLL on (es2 bit pos)
	orr	r10, r10, #0x2		@ 90 degree phase for all below 133Mhz
	str	r10, [r11]		@ commit to DLLA_CTRL
	bl	i_dll_wait		@ wait for dll to lock

	/* get dll value */
	add	r11, r11, #0x4		@ get addr of status reg
	ldr	r10, [r11]		@ get locked value

	/* voltage shift up */
	mov r9, #0x0			@ shift back to L0-voltage
	bl voltage_shift		@ go raise voltage

	/* frequency shift up */
	mov	r3, #0x2		@ value for 2x operation
	str	r3, [r2]		@ go to L0-freq operation

	/* reset entry mode for dllctrl */
	sub	r11, r11, #0x4		@ move from status to ctrl
	cmp	r12, #0x1		@ normalize if cs1 based
	subeq	r11, r11, #0x8		@ possibly back to DLLA
	cmp	r8, #0x1		@ if forced unlock exit
	orreq	r1, r1, #0x4		@ make sure exit with unlocked value
	str	r1, [r11]		@ restore DLLA_CTRL high value
	add	r11, r11, #0x8		@ move to DLLB_CTRL addr
	str	r1, [r11]		@ set value DLLB_CTRL
	bl	i_dll_wait		@ wait for possible lock

	/* set up for return, DDR should be good */
	str r10, [r0]			@ write dll_status and return counter
	ldmfd	sp!, {r0 - r12, pc}	@ restore regs and return

	/* ensure the DLL has relocked */
i_dll_wait:
	mov	r4, #0x800		@ delay DLL relock, min 0x400 L3 clocks
i_dll_delay:
	subs	r4, r4, #0x1
	bne	i_dll_delay
	mov	pc, lr

	/*
	 * shift up or down voltage, use R9 as input to tell level.
	 * wait for it to finish, use 32k sync counter, 1tick=31uS.
	 */
voltage_shift:
112
	ldr	r4, omap242x_sdi_prcm_voltctrl	@ get addr of volt ctrl.
113 114 115 116 117 118 119 120 121
	ldr	r5, [r4]		@ get value.
	ldr	r6, prcm_mask_val	@ get value of mask
	and	r5, r5, r6		@ apply mask to clear bits
	orr	r5, r5, r9		@ bulld value for L0/L1-volt operation.
	str	r5, [r4]		@ set up for change.
	mov	r3, #0x4000		@ get val for force
	orr	r5, r5, r3		@ build value for force
	str	r5, [r4]		@ Force transition to L1

122
	ldr	r3, omap242x_sdi_timer_32ksynct_cr	@ get addr of counter
123 124 125 126 127 128 129 130
	ldr	r5, [r3]		@ get value
	add	r5, r5, #0x3		@ give it at most 93uS
volt_delay:
	ldr	r7, [r3]		@ get timer value
	cmp	r5, r7			@ time up?
	bhi	volt_delay		@ not yet->branch
	mov	pc, lr			@ back to caller.

131
omap242x_sdi_cm_clksel2_pll:
132
	.word OMAP2420_CM_REGADDR(PLL_MOD, CM_CLKSEL2)
133
omap242x_sdi_sdrc_dlla_ctrl:
134
	.word OMAP242X_SDRC_REGADDR(SDRC_DLLA_CTRL)
135
omap242x_sdi_prcm_voltctrl:
136
	.word OMAP2420_PRCM_VOLTCTRL
137 138
prcm_mask_val:
	.word 0xFFFF3FFC
139
omap242x_sdi_timer_32ksynct_cr:
140
	.word OMAP2_L4_IO_ADDRESS(OMAP2420_32KSYNCT_BASE + 0x010)
141 142
ENTRY(omap242x_sram_ddr_init_sz)
	.word	. - omap242x_sram_ddr_init
143 144 145 146 147 148

/*
 * Reprograms memory timings.
 * r0 = [PRCM_FULL | PRCM_HALF] r1 = SDRC_DLLA_CTRL value r2 = [DDR | SDR]
 * PRCM_FULL = 2, PRCM_HALF = 1, DDR = 1, SDR = 0
 */
149
	.align	3
150
ENTRY(omap242x_sram_reprogram_sdrc)
151 152 153 154 155
	stmfd	sp!, {r0 - r10, lr}	@ save registers on stack
	mov	r3, #0x0		@ clear for mrc call
	mcr	p15, 0, r3, c7, c10, 4	@ memory barrier, finish ARM SDR/DDR
	nop
	nop
156
	ldr	r6, omap242x_srs_sdrc_rfr_ctrl	@ get addr of refresh reg
157 158 159 160 161 162 163 164 165 166 167 168 169
	ldr	r5, [r6]		@ get value
	mov	r5, r5, lsr #8		@ isolate rfr field and drop burst

	cmp	r0, #0x1		@ going to half speed?
	movne	r9, #0x0		@ if up set flag up for pre up, hi volt

	blne	voltage_shift_c		@ adjust voltage

	cmp	r0, #0x1		@ going to half speed (post branch link)
	moveq	r5, r5, lsr #1		@ divide by 2 if to half
	movne	r5, r5, lsl #1		@ mult by 2 if to full
	mov	r5, r5, lsl #8		@ put rfr field back into place
	add	r5, r5, #0x1		@ turn on burst of 1
170
	ldr	r4, omap242x_srs_cm_clksel2_pll	@ get address of out reg
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
	ldr	r3, [r4]		@ get curr value
	orr	r3, r3, #0x3
	bic	r3, r3, #0x3		@ clear lower bits
	orr	r3, r3, r0		@ new state value
	str	r3, [r4]		@ set new state (pll/x, x=1 or 2)
	nop
	nop

	moveq	r9, #0x1		@ if speed down, post down, drop volt
	bleq	voltage_shift_c

	mcr	p15, 0, r3, c7, c10, 4	@ memory barrier
	str	r5, [r6]		@ set new RFR_1 value
	add	r6, r6, #0x30		@ get RFR_2 addr
	str	r5, [r6]		@ set RFR_2
	nop
	cmp	r2, #0x1		@ (SDR or DDR) do we need to adjust DLL
	bne	freq_out		@ leave if SDR, no DLL function

	/* With DDR, we need to take care of the DLL for the frequency change */
191
	ldr	r2, omap242x_srs_sdrc_dlla_ctrl	@ addr of dlla ctrl
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
	str	r1, [r2]		@ write out new SDRC_DLLA_CTRL
	add	r2, r2, #0x8		@ addr to SDRC_DLLB_CTRL
	str	r1, [r2]		@ commit to SDRC_DLLB_CTRL
	mov	r1, #0x2000		@ wait DLL relock, min 0x400 L3 clocks
dll_wait:
	subs	r1, r1, #0x1
	bne	dll_wait
freq_out:
	ldmfd	sp!, {r0 - r10, pc}	@ restore regs and return

    /*
     * shift up or down voltage, use R9 as input to tell level.
     *	wait for it to finish, use 32k sync counter, 1tick=31uS.
     */
voltage_shift_c:
207
	ldr	r10, omap242x_srs_prcm_voltctrl	@ get addr of volt ctrl
208 209 210 211 212 213 214 215 216
	ldr	r8, [r10]		@ get value
	ldr	r7, ddr_prcm_mask_val	@ get value of mask
	and	r8, r8, r7		@ apply mask to clear bits
	orr	r8, r8, r9		@ bulld value for L0/L1-volt operation.
	str	r8, [r10]		@ set up for change.
	mov	r7, #0x4000		@ get val for force
	orr	r8, r8, r7		@ build value for force
	str	r8, [r10]		@ Force transition to L1

217
	ldr	r10, omap242x_srs_timer_32ksynct	@ get addr of counter
218 219 220 221 222 223 224 225
	ldr	r8, [r10]		@ get value
	add	r8, r8, #0x2		@ give it at most 62uS (min 31+)
volt_delay_c:
	ldr	r7, [r10]		@ get timer value
	cmp	r8, r7			@ time up?
	bhi	volt_delay_c		@ not yet->branch
	mov	pc, lr			@ back to caller

226
omap242x_srs_cm_clksel2_pll:
227
	.word OMAP2420_CM_REGADDR(PLL_MOD, CM_CLKSEL2)
228
omap242x_srs_sdrc_dlla_ctrl:
229
	.word OMAP242X_SDRC_REGADDR(SDRC_DLLA_CTRL)
230
omap242x_srs_sdrc_rfr_ctrl:
231
	.word OMAP242X_SDRC_REGADDR(SDRC_RFR_CTRL_0)
232
omap242x_srs_prcm_voltctrl:
233
	.word OMAP2420_PRCM_VOLTCTRL
234 235
ddr_prcm_mask_val:
	.word 0xFFFF3FFC
236
omap242x_srs_timer_32ksynct:
237
	.word OMAP2_L4_IO_ADDRESS(OMAP2420_32KSYNCT_BASE + 0x010)
238

239 240
ENTRY(omap242x_sram_reprogram_sdrc_sz)
	.word	. - omap242x_sram_reprogram_sdrc
241 242 243 244

/*
 * Set dividers and pll. Also recalculate DLL value for DDR and unlock mode.
 */
245
	.align	3
246
ENTRY(omap242x_sram_set_prcm)
247 248 249 250 251 252
	stmfd	sp!, {r0-r12, lr}	@ regs to stack
	adr	r4, pbegin		@ addr of preload start
	adr	r8, pend		@ addr of preload end
	mcrr	p15, 1, r8, r4, c12	@ preload into icache
pbegin:
	/* move into fast relock bypass */
253
	ldr	r8, omap242x_ssp_pll_ctl	@ get addr
254 255 256 257 258
	ldr	r5, [r8]		@ get val
	mvn	r6, #0x3		@ clear mask
	and	r5, r5, r6		@ clear field
	orr	r7, r5, #0x2		@ fast relock val
	str	r7, [r8]		@ go to fast relock
259
	ldr	r4, omap242x_ssp_pll_stat	@ addr of stat
260 261 262 263 264 265 266 267
block:
	/* wait for bypass */
	ldr	r8, [r4]		@ stat value
	and	r8, r8, #0x3		@ mask for stat
	cmp	r8, #0x1		@ there yet
	bne	block			@ loop if not

	/* set new dpll dividers _after_ in bypass */
268
	ldr	r4, omap242x_ssp_pll_div	@ get addr
269 270
	str	r0, [r4]		@ set dpll ctrl val

271
	ldr	r4, omap242x_ssp_set_config	@ get addr
272 273 274 275 276 277 278 279 280 281 282 283 284
	mov	r8, #1			@ valid cfg msk
	str	r8, [r4]		@ make dividers take

	mov	r4, #100		@ dead spin a bit
wait_a_bit:
	subs	r4, r4, #1		@ dec loop
	bne	wait_a_bit		@ delay done?

	/* check if staying in bypass */
	cmp	r2, #0x1		@ stay in bypass?
	beq	pend			@ jump over dpll relock

	/* relock DPLL with new vals */
285 286
	ldr	r5, omap242x_ssp_pll_stat	@ get addr
	ldr	r4, omap242x_ssp_pll_ctl	@ get addr
287 288 289 290 291 292 293 294 295 296 297 298 299
	orr	r8, r7, #0x3		@ val for lock dpll
	str	r8, [r4]		@ set val
	mov	r0, #1000		@ dead spin a bit
wait_more:
	subs	r0, r0, #1		@ dec loop
	bne	wait_more		@ delay done?
wait_lock:
	ldr	r8, [r5]		@ get lock val
	and	r8, r8, #3		@ isolate field
	cmp	r8, #2			@ locked?
	bne	wait_lock		@ wait if not
pend:
	/* update memory timings & briefly lock dll */
300
	ldr	r4, omap242x_ssp_sdrc_rfr	@ get addr
301
	str	r1, [r4]		@ update refresh timing
302
	ldr	r11, omap242x_ssp_dlla_ctrl	@ get addr of DLLA ctrl
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
	ldr	r10, [r11]		@ get current val
	mvn	r9, #0x4		@ mask to get clear bit2
	and	r10, r10, r9		@ clear bit2 for lock mode
	orr	r10, r10, #0x8		@ make sure DLL on (es2 bit pos)
	str	r10, [r11]		@ commit to DLLA_CTRL
	add	r11, r11, #0x8		@ move to dllb
	str	r10, [r11]		@ hit DLLB also

	mov	r4, #0x800		@ relock time (min 0x400 L3 clocks)
wait_dll_lock:
	subs	r4, r4, #0x1
	bne	wait_dll_lock
	nop
	ldmfd	sp!, {r0-r12, pc}	@ restore regs and return

318
omap242x_ssp_set_config:
319
	.word OMAP2420_PRCM_CLKCFG_CTRL
320 321 322 323 324 325 326
omap242x_ssp_pll_ctl:
	.word OMAP2420_CM_REGADDR(PLL_MOD, CM_CLKEN)
omap242x_ssp_pll_stat:
	.word OMAP2420_CM_REGADDR(PLL_MOD, CM_IDLEST)
omap242x_ssp_pll_div:
	.word OMAP2420_CM_REGADDR(PLL_MOD, CM_CLKSEL1)
omap242x_ssp_sdrc_rfr:
327
	.word OMAP242X_SDRC_REGADDR(SDRC_RFR_CTRL_0)
328
omap242x_ssp_dlla_ctrl:
329
	.word OMAP242X_SDRC_REGADDR(SDRC_DLLA_CTRL)
330

331 332
ENTRY(omap242x_sram_set_prcm_sz)
	.word	. - omap242x_sram_set_prcm