;------------------------------------------------------------------------------
;
;   Copyright (C) 2004-2007, Freescale Semiconductor, Inc. All Rights Reserved.
;   THIS SOURCE CODE, AND ITS USE AND DISTRIBUTION, IS SUBJECT TO THE TERMS
;   AND CONDITIONS OF THE APPLICABLE LICENSE AGREEMENT
;
;------------------------------------------------------------------------------
;
;  Module: dvfc.s
;
;  This module implements the OAL assembly-level support for supporting
;  DVFC (DVFS/DPTC) operations that require kernel mode.
;
;------------------------------------------------------------------------------
    INCLUDE kxarm.h
    INCLUDE armmacros.s
    INCLUDE mxarm11_base_regs.inc
    INCLUDE mxarm11_base_mem.inc
    INCLUDE mx31_base_regs.inc
    INCLUDE mx31_base_mem.inc
    INCLUDE image_cfg.inc

;
; ESDCTL constants
;
ESDCTL_ESDMISC_OFFSET       EQU     0x0010
ESDCTL_ESDMISC_MDDR_DL_RST  EQU     (1 << 3)


;
; CCM constants
;
CCM_PDR0_OFFSET             EQU     0x0004
CCM_PDR0_IPG_PODF_LSH       EQU     (6)
CCM_PDR0_IPG_PODF_MASK      EQU     (0x3 << CCM_PDR0_IPG_PODF_LSH)

;
; SDMA constants
;
SDMA_HSTART_OFFSET          EQU     0x000C

    IMPORT g_pCCM
    IMPORT g_pSDMA
    IMPORT g_pESDCTL
    EXPORT OALDvfcBusFreqUpdate_END
    EXPORT OALDvfcBusFreqUpdate_BEGIN

    TEXTAREA
;------------------------------------------------------------------------------
;
;  Function: OALDvfcBusFreqUpdate
;
;  This function provides the sequence to calibrate the DDR delay line
;  during an AHB frequency shift.
;
;  Parameters:
;       ccm_pdr0_addr (passed in R0) 
;           [in] - Specifies the address of the CCM PDR0 register.
;
;       ccm_pdr0_val (passed in R1) 
;           [in] - Specifies CCM PDR0 value that applies the AHB frequency 
;               shift.
;
;       sdma_hstart_addr (passed R2)
;           [in] - Specifies the address of the SDMA STOP_STAT register.
;
;       sdma_hstart_val (passed R3)
;           [in] - Specifies the SDMA STOP_STAT register that will be
;               restored during DDR delay line calibration.
;
;  Returns:
;      None.
;
;------------------------------------------------------------------------------
    LEAF_ENTRY OALDvfcBusFreqUpdate

OALDvfcBusFreqUpdate_BEGIN

    ; Save non-volatile registers
    stmfd   sp!, {r4-r6}

    ; During the AHB frequency shift, accesses to the DDR are not allowed.  
    ; This code will be executed from internal memory to perform the 
    ; shift and calibrate the DDR delay line.


    ; Preload all peripheral addresses into CPU registers.  This avoids 
    ; dereferencing global pointers (which live in DDR) during the calibration
    ; sequence.
    ldr     r2, =g_pCCM
    ldr     r2, [r2]
    ldr     r3, =g_pSDMA
    ldr     r3, [r3]
    ldr     r4, =g_pESDCTL
    ldr     r4, [r4]
    ldr     r5, =(IMAGE_SHARE_ARGS_RAM_UA_START+IMAGE_SHARE_ARGS_RAM_SIZE-4)
    
    ; Use dummy accesses to avoid TLB miss which results in DDR page 
    ; table walk.
    ldr     r6, [r2]        ; Dummy access to CCM
    ldr     r6, [r3]        ; Dummy access to SDMA
    ldr     r6, [r5]        ; Dummy access to BSP_ARGS
    
    ; Prepare to reset the DDR delay line and start a new
    ; measurement after the bus has been scaled
    ldr     r6, [r4, #ESDCTL_ESDMISC_OFFSET]
    orr     r6, r6, #ESDCTL_ESDMISC_MDDR_DL_RST

    ; Scale the bus per the PDR0 input parameter
    str     r0, [r2, #CCM_PDR0_OFFSET]

    ; Read the post-divider register to make sure the configuration
    ; has taken effect.  The number of dummy reads may need adjustment 
    ; based on the slowest clock being effected by the update of PDR0.  
    ; Worst case clock alignment for dividers in current configuration
    ; is 2*3*5 = 30 clocks  
    ldr     r0, [r2, #CCM_PDR0_OFFSET]
    ldr     r0, [r2, #CCM_PDR0_OFFSET]
    ldr     r0, [r2, #CCM_PDR0_OFFSET]
    ldr     r0, [r2, #CCM_PDR0_OFFSET]
    ldr     r0, [r2, #CCM_PDR0_OFFSET]
    ldr     r0, [r2, #CCM_PDR0_OFFSET]
    ldr     r0, [r2, #CCM_PDR0_OFFSET]
    ldr     r0, [r2, #CCM_PDR0_OFFSET]
    ldr     r0, [r2, #CCM_PDR0_OFFSET]
    ldr     r0, [r2, #CCM_PDR0_OFFSET]
    ldr     r0, [r2, #CCM_PDR0_OFFSET]
    ldr     r0, [r2, #CCM_PDR0_OFFSET]
    ldr     r0, [r2, #CCM_PDR0_OFFSET]
    ldr     r0, [r2, #CCM_PDR0_OFFSET]
    ldr     r0, [r2, #CCM_PDR0_OFFSET]
    ldr     r0, [r2, #CCM_PDR0_OFFSET]
    ldr     r0, [r2, #CCM_PDR0_OFFSET]
    ldr     r0, [r2, #CCM_PDR0_OFFSET]
    ldr     r0, [r2, #CCM_PDR0_OFFSET]
    ldr     r0, [r2, #CCM_PDR0_OFFSET]
    ldr     r0, [r2, #CCM_PDR0_OFFSET]
    ldr     r0, [r2, #CCM_PDR0_OFFSET]
    ldr     r0, [r2, #CCM_PDR0_OFFSET]
    ldr     r0, [r2, #CCM_PDR0_OFFSET]
    ldr     r0, [r2, #CCM_PDR0_OFFSET]
    ldr     r0, [r2, #CCM_PDR0_OFFSET]
    ldr     r0, [r2, #CCM_PDR0_OFFSET]
    ldr     r0, [r2, #CCM_PDR0_OFFSET]
    ldr     r0, [r2, #CCM_PDR0_OFFSET]
    ldr     r0, [r2, #CCM_PDR0_OFFSET]

    ; Reset the DDR delay line and start a new measurement.  
    ; R6 has already been configured with ESDMISC value above.
    str     r6, [r4, #ESDCTL_ESDMISC_OFFSET]

    ; Activate SDMA channels (i.e. audio) that do not require DDR access
    str     r1, [r3, #SDMA_HSTART_OFFSET]
                    
    ; Branch to the aligned calibration loop.  Keeping the loop aligned will
    ; provide consistent execution timing.
    b       CAL_START
    ALIGN   32

    ; Delay loop calibrated for 4500 AHB cycles which is the time needed
    ; for the DDR delay measurement to adapt to the new bus frequency.
CAL_START
    ldr     r1, =(200)
CAL_LOOP
    subs    r1, r1, #1
    bne     CAL_LOOP

    ; Dummy read/writes to DDR (read/write last 4 bytes of shared args) 
    ldr     r1, [r5]
    str     r1, [r5]

    ; Access to DDR is okay now.  Restore non-volatile registers.
    ldmfd   sp!, {r4-r6}

    RETURN

OALDvfcBusFreqUpdate_END

    END
