mirror of
https://github.com/torvalds/linux.git
synced 2024-12-23 11:21:33 +00:00
a3fed9bc18
When changing the L3 clock frequency, the CPU is executing from internal RAM and the SDRC clock is disabled. During this time accesses made to external DDR are stalled. If the ARM subsystem attempts to access the DDR while the SDRC clock is disabled this will stall the CPU until the access to the SDRC timeouts. A timeout on the SDRC should never occur. Once a timeout occurs all the following accesses will be aborted and the DDR is no longer accessible. Although the code being executed in the internal RAM does not directly access the DDR, it was found that the branch prediction logic in the CPU may cause the CPU to prefetch code from a DDR location while the SDRC clock is disabled. This was causing an SDRC timeout which resulted in a system hang. This patch fixes this problem by ensuring the branch prediction logic is disabled while changing the L3 clock frequency. The branch prediction logic is disabled by clearing the Z-bit in the ARM CTRL register. Disabling the branch prediction logic does not have any noticable impact on the execution time of this code section. The hardware observability signals were used to monitor the sdrc idle time with and without this patch when operating at different CPU frequencies (150MHz, 500MHz and 600MHz) and the total sdrc idle time when changing frequenct was in the range of 9-11us. This was measured on an omap3430 SDP running the omapzoom p-android-omap-2.6.29 branch. Signed-off-by: Jon Hunter <jon-hunter@ti.com> Signed-off-by: Paul Walmsley <paul@pwsan.com> Cc: Santosh Shilimkar <santosh.shilimkar@ti.com> Cc: Richard Woodruff <r-woodruff2@ti.com> Cc: Tony Lindgren <tony@atomide.com>
320 lines
9.8 KiB
ArmAsm
320 lines
9.8 KiB
ArmAsm
/*
|
|
* linux/arch/arm/mach-omap3/sram.S
|
|
*
|
|
* Omap3 specific functions that need to be run in internal SRAM
|
|
*
|
|
* Copyright (C) 2004, 2007, 2008 Texas Instruments, Inc.
|
|
* Copyright (C) 2008 Nokia Corporation
|
|
*
|
|
* Rajendra Nayak <rnayak@ti.com>
|
|
* Richard Woodruff <r-woodruff2@ti.com>
|
|
* Paul Walmsley
|
|
*
|
|
* 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
|
|
*/
|
|
#include <linux/linkage.h>
|
|
#include <asm/assembler.h>
|
|
#include <mach/hardware.h>
|
|
|
|
#include <mach/io.h>
|
|
|
|
#include "sdrc.h"
|
|
#include "cm.h"
|
|
|
|
.text
|
|
|
|
/* r1 parameters */
|
|
#define SDRC_NO_UNLOCK_DLL 0x0
|
|
#define SDRC_UNLOCK_DLL 0x1
|
|
|
|
/* SDRC_DLLA_CTRL bit settings */
|
|
#define FIXEDDELAY_SHIFT 24
|
|
#define FIXEDDELAY_MASK (0xff << FIXEDDELAY_SHIFT)
|
|
#define DLLIDLE_MASK 0x4
|
|
|
|
/*
|
|
* SDRC_DLLA_CTRL default values: TI hardware team indicates that
|
|
* FIXEDDELAY should be initialized to 0xf. This apparently was
|
|
* empirically determined during process testing, so no derivation
|
|
* was provided.
|
|
*/
|
|
#define FIXEDDELAY_DEFAULT (0x0f << FIXEDDELAY_SHIFT)
|
|
|
|
/* SDRC_DLLA_STATUS bit settings */
|
|
#define LOCKSTATUS_MASK 0x4
|
|
|
|
/* SDRC_POWER bit settings */
|
|
#define SRFRONIDLEREQ_MASK 0x40
|
|
|
|
/* CM_IDLEST1_CORE bit settings */
|
|
#define ST_SDRC_MASK 0x2
|
|
|
|
/* CM_ICLKEN1_CORE bit settings */
|
|
#define EN_SDRC_MASK 0x2
|
|
|
|
/* CM_CLKSEL1_PLL bit settings */
|
|
#define CORE_DPLL_CLKOUT_DIV_SHIFT 0x1b
|
|
|
|
/*
|
|
* omap3_sram_configure_core_dpll - change DPLL3 M2 divider
|
|
*
|
|
* Params passed in registers:
|
|
* r0 = new M2 divider setting (only 1 and 2 supported right now)
|
|
* r1 = unlock SDRC DLL? (1 = yes, 0 = no). Only unlock DLL for
|
|
* SDRC rates < 83MHz
|
|
* r2 = number of MPU cycles to wait for SDRC to stabilize after
|
|
* reprogramming the SDRC when switching to a slower MPU speed
|
|
* r3 = increasing SDRC rate? (1 = yes, 0 = no)
|
|
*
|
|
* Params passed via the stack. The needed params will be copied in SRAM
|
|
* before use by the code in SRAM (SDRAM is not accessible during SDRC
|
|
* reconfiguration):
|
|
* new SDRC_RFR_CTRL_0 register contents
|
|
* new SDRC_ACTIM_CTRL_A_0 register contents
|
|
* new SDRC_ACTIM_CTRL_B_0 register contents
|
|
* new SDRC_MR_0 register value
|
|
* new SDRC_RFR_CTRL_1 register contents
|
|
* new SDRC_ACTIM_CTRL_A_1 register contents
|
|
* new SDRC_ACTIM_CTRL_B_1 register contents
|
|
* new SDRC_MR_1 register value
|
|
*
|
|
* If the param SDRC_RFR_CTRL_1 is 0, the parameters are not programmed into
|
|
* the SDRC CS1 registers
|
|
*
|
|
* NOTE: This code no longer attempts to program the SDRC AC timing and MR
|
|
* registers. This is because the code currently cannot ensure that all
|
|
* L3 initiators (e.g., sDMA, IVA, DSS DISPC, etc.) are not accessing the
|
|
* SDRAM when the registers are written. If the registers are changed while
|
|
* an initiator is accessing SDRAM, memory can be corrupted and/or the SDRC
|
|
* may enter an unpredictable state. In the future, the intent is to
|
|
* re-enable this code in cases where we can ensure that no initiators are
|
|
* touching the SDRAM. Until that time, users who know that their use case
|
|
* can satisfy the above requirement can enable the CONFIG_OMAP3_SDRC_AC_TIMING
|
|
* option.
|
|
*/
|
|
ENTRY(omap3_sram_configure_core_dpll)
|
|
stmfd sp!, {r1-r12, lr} @ store regs to stack
|
|
|
|
@ pull the extra args off the stack
|
|
@ and store them in SRAM
|
|
ldr r4, [sp, #52]
|
|
str r4, omap_sdrc_rfr_ctrl_0_val
|
|
ldr r4, [sp, #56]
|
|
str r4, omap_sdrc_actim_ctrl_a_0_val
|
|
ldr r4, [sp, #60]
|
|
str r4, omap_sdrc_actim_ctrl_b_0_val
|
|
ldr r4, [sp, #64]
|
|
str r4, omap_sdrc_mr_0_val
|
|
ldr r4, [sp, #68]
|
|
str r4, omap_sdrc_rfr_ctrl_1_val
|
|
cmp r4, #0 @ if SDRC_RFR_CTRL_1 is 0,
|
|
beq skip_cs1_params @ do not use cs1 params
|
|
ldr r4, [sp, #72]
|
|
str r4, omap_sdrc_actim_ctrl_a_1_val
|
|
ldr r4, [sp, #76]
|
|
str r4, omap_sdrc_actim_ctrl_b_1_val
|
|
ldr r4, [sp, #80]
|
|
str r4, omap_sdrc_mr_1_val
|
|
skip_cs1_params:
|
|
mrc p15, 0, r8, c1, c0, 0 @ read ctrl register
|
|
bic r10, r8, #0x800 @ clear Z-bit, disable branch prediction
|
|
mcr p15, 0, r10, c1, c0, 0 @ write ctrl register
|
|
dsb @ flush buffered writes to interconnect
|
|
isb @ prevent speculative exec past here
|
|
cmp r3, #1 @ if increasing SDRC clk rate,
|
|
bleq configure_sdrc @ program the SDRC regs early (for RFR)
|
|
cmp r1, #SDRC_UNLOCK_DLL @ set the intended DLL state
|
|
bleq unlock_dll
|
|
blne lock_dll
|
|
bl sdram_in_selfrefresh @ put SDRAM in self refresh, idle SDRC
|
|
bl configure_core_dpll @ change the DPLL3 M2 divider
|
|
mov r12, r2
|
|
bl wait_clk_stable @ wait for SDRC to stabilize
|
|
bl enable_sdrc @ take SDRC out of idle
|
|
cmp r1, #SDRC_UNLOCK_DLL @ wait for DLL status to change
|
|
bleq wait_dll_unlock
|
|
blne wait_dll_lock
|
|
cmp r3, #1 @ if increasing SDRC clk rate,
|
|
beq return_to_sdram @ return to SDRAM code, otherwise,
|
|
bl configure_sdrc @ reprogram SDRC regs now
|
|
return_to_sdram:
|
|
mcr p15, 0, r8, c1, c0, 0 @ restore ctrl register
|
|
isb @ prevent speculative exec past here
|
|
mov r0, #0 @ return value
|
|
ldmfd sp!, {r1-r12, pc} @ restore regs and return
|
|
unlock_dll:
|
|
ldr r11, omap3_sdrc_dlla_ctrl
|
|
ldr r12, [r11]
|
|
bic r12, r12, #FIXEDDELAY_MASK
|
|
orr r12, r12, #FIXEDDELAY_DEFAULT
|
|
orr r12, r12, #DLLIDLE_MASK
|
|
str r12, [r11] @ (no OCP barrier needed)
|
|
bx lr
|
|
lock_dll:
|
|
ldr r11, omap3_sdrc_dlla_ctrl
|
|
ldr r12, [r11]
|
|
bic r12, r12, #DLLIDLE_MASK
|
|
str r12, [r11] @ (no OCP barrier needed)
|
|
bx lr
|
|
sdram_in_selfrefresh:
|
|
ldr r11, omap3_sdrc_power @ read the SDRC_POWER register
|
|
ldr r12, [r11] @ read the contents of SDRC_POWER
|
|
mov r9, r12 @ keep a copy of SDRC_POWER bits
|
|
orr r12, r12, #SRFRONIDLEREQ_MASK @ enable self refresh on idle
|
|
str r12, [r11] @ write back to SDRC_POWER register
|
|
ldr r12, [r11] @ posted-write barrier for SDRC
|
|
idle_sdrc:
|
|
ldr r11, omap3_cm_iclken1_core @ read the CM_ICLKEN1_CORE reg
|
|
ldr r12, [r11]
|
|
bic r12, r12, #EN_SDRC_MASK @ disable iclk bit for SDRC
|
|
str r12, [r11]
|
|
wait_sdrc_idle:
|
|
ldr r11, omap3_cm_idlest1_core
|
|
ldr r12, [r11]
|
|
and r12, r12, #ST_SDRC_MASK @ check for SDRC idle
|
|
cmp r12, #ST_SDRC_MASK
|
|
bne wait_sdrc_idle
|
|
bx lr
|
|
configure_core_dpll:
|
|
ldr r11, omap3_cm_clksel1_pll
|
|
ldr r12, [r11]
|
|
ldr r10, core_m2_mask_val @ modify m2 for core dpll
|
|
and r12, r12, r10
|
|
orr r12, r12, r0, lsl #CORE_DPLL_CLKOUT_DIV_SHIFT
|
|
str r12, [r11]
|
|
ldr r12, [r11] @ posted-write barrier for CM
|
|
bx lr
|
|
wait_clk_stable:
|
|
subs r12, r12, #1
|
|
bne wait_clk_stable
|
|
bx lr
|
|
enable_sdrc:
|
|
ldr r11, omap3_cm_iclken1_core
|
|
ldr r12, [r11]
|
|
orr r12, r12, #EN_SDRC_MASK @ enable iclk bit for SDRC
|
|
str r12, [r11]
|
|
wait_sdrc_idle1:
|
|
ldr r11, omap3_cm_idlest1_core
|
|
ldr r12, [r11]
|
|
and r12, r12, #ST_SDRC_MASK
|
|
cmp r12, #0
|
|
bne wait_sdrc_idle1
|
|
restore_sdrc_power_val:
|
|
ldr r11, omap3_sdrc_power
|
|
str r9, [r11] @ restore SDRC_POWER, no barrier needed
|
|
bx lr
|
|
wait_dll_lock:
|
|
ldr r11, omap3_sdrc_dlla_status
|
|
ldr r12, [r11]
|
|
and r12, r12, #LOCKSTATUS_MASK
|
|
cmp r12, #LOCKSTATUS_MASK
|
|
bne wait_dll_lock
|
|
bx lr
|
|
wait_dll_unlock:
|
|
ldr r11, omap3_sdrc_dlla_status
|
|
ldr r12, [r11]
|
|
and r12, r12, #LOCKSTATUS_MASK
|
|
cmp r12, #0x0
|
|
bne wait_dll_unlock
|
|
bx lr
|
|
configure_sdrc:
|
|
ldr r12, omap_sdrc_rfr_ctrl_0_val @ fetch value from SRAM
|
|
ldr r11, omap3_sdrc_rfr_ctrl_0 @ fetch addr from SRAM
|
|
str r12, [r11] @ store
|
|
#ifdef CONFIG_OMAP3_SDRC_AC_TIMING
|
|
ldr r12, omap_sdrc_actim_ctrl_a_0_val
|
|
ldr r11, omap3_sdrc_actim_ctrl_a_0
|
|
str r12, [r11]
|
|
ldr r12, omap_sdrc_actim_ctrl_b_0_val
|
|
ldr r11, omap3_sdrc_actim_ctrl_b_0
|
|
str r12, [r11]
|
|
ldr r12, omap_sdrc_mr_0_val
|
|
ldr r11, omap3_sdrc_mr_0
|
|
str r12, [r11]
|
|
#endif
|
|
ldr r12, omap_sdrc_rfr_ctrl_1_val
|
|
cmp r12, #0 @ if SDRC_RFR_CTRL_1 is 0,
|
|
beq skip_cs1_prog @ do not program cs1 params
|
|
ldr r11, omap3_sdrc_rfr_ctrl_1
|
|
str r12, [r11]
|
|
#ifdef CONFIG_OMAP3_SDRC_AC_TIMING
|
|
ldr r12, omap_sdrc_actim_ctrl_a_1_val
|
|
ldr r11, omap3_sdrc_actim_ctrl_a_1
|
|
str r12, [r11]
|
|
ldr r12, omap_sdrc_actim_ctrl_b_1_val
|
|
ldr r11, omap3_sdrc_actim_ctrl_b_1
|
|
str r12, [r11]
|
|
ldr r12, omap_sdrc_mr_1_val
|
|
ldr r11, omap3_sdrc_mr_1
|
|
str r12, [r11]
|
|
#endif
|
|
skip_cs1_prog:
|
|
ldr r12, [r11] @ posted-write barrier for SDRC
|
|
bx lr
|
|
|
|
omap3_sdrc_power:
|
|
.word OMAP34XX_SDRC_REGADDR(SDRC_POWER)
|
|
omap3_cm_clksel1_pll:
|
|
.word OMAP34XX_CM_REGADDR(PLL_MOD, CM_CLKSEL1)
|
|
omap3_cm_idlest1_core:
|
|
.word OMAP34XX_CM_REGADDR(CORE_MOD, CM_IDLEST)
|
|
omap3_cm_iclken1_core:
|
|
.word OMAP34XX_CM_REGADDR(CORE_MOD, CM_ICLKEN1)
|
|
|
|
omap3_sdrc_rfr_ctrl_0:
|
|
.word OMAP34XX_SDRC_REGADDR(SDRC_RFR_CTRL_0)
|
|
omap3_sdrc_rfr_ctrl_1:
|
|
.word OMAP34XX_SDRC_REGADDR(SDRC_RFR_CTRL_1)
|
|
omap3_sdrc_actim_ctrl_a_0:
|
|
.word OMAP34XX_SDRC_REGADDR(SDRC_ACTIM_CTRL_A_0)
|
|
omap3_sdrc_actim_ctrl_a_1:
|
|
.word OMAP34XX_SDRC_REGADDR(SDRC_ACTIM_CTRL_A_1)
|
|
omap3_sdrc_actim_ctrl_b_0:
|
|
.word OMAP34XX_SDRC_REGADDR(SDRC_ACTIM_CTRL_B_0)
|
|
omap3_sdrc_actim_ctrl_b_1:
|
|
.word OMAP34XX_SDRC_REGADDR(SDRC_ACTIM_CTRL_B_1)
|
|
omap3_sdrc_mr_0:
|
|
.word OMAP34XX_SDRC_REGADDR(SDRC_MR_0)
|
|
omap3_sdrc_mr_1:
|
|
.word OMAP34XX_SDRC_REGADDR(SDRC_MR_1)
|
|
omap_sdrc_rfr_ctrl_0_val:
|
|
.word 0xDEADBEEF
|
|
omap_sdrc_rfr_ctrl_1_val:
|
|
.word 0xDEADBEEF
|
|
omap_sdrc_actim_ctrl_a_0_val:
|
|
.word 0xDEADBEEF
|
|
omap_sdrc_actim_ctrl_a_1_val:
|
|
.word 0xDEADBEEF
|
|
omap_sdrc_actim_ctrl_b_0_val:
|
|
.word 0xDEADBEEF
|
|
omap_sdrc_actim_ctrl_b_1_val:
|
|
.word 0xDEADBEEF
|
|
omap_sdrc_mr_0_val:
|
|
.word 0xDEADBEEF
|
|
omap_sdrc_mr_1_val:
|
|
.word 0xDEADBEEF
|
|
|
|
omap3_sdrc_dlla_status:
|
|
.word OMAP34XX_SDRC_REGADDR(SDRC_DLLA_STATUS)
|
|
omap3_sdrc_dlla_ctrl:
|
|
.word OMAP34XX_SDRC_REGADDR(SDRC_DLLA_CTRL)
|
|
core_m2_mask_val:
|
|
.word 0x07FFFFFF
|
|
|
|
ENTRY(omap3_sram_configure_core_dpll_sz)
|
|
.word . - omap3_sram_configure_core_dpll
|
|
|