root/arch/mips/kernel/bmips_5xxx_init.S

/*
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * Copyright (C) 2011-2012 by Broadcom Corporation
 *
 * Init for bmips 5000.
 * Used to init second core in dual core 5000's.
 */

#include <linux/init.h>

#include <asm/asm.h>
#include <asm/asmmacro.h>
#include <asm/cacheops.h>
#include <asm/regdef.h>
#include <asm/mipsregs.h>
#include <asm/stackframe.h>
#include <asm/addrspace.h>
#include <asm/hazards.h>
#include <asm/bmips.h>

#ifdef CONFIG_CPU_BMIPS5000


#define cacheop(kva, size, linesize, op)        \
        .set noreorder                  ;       \
        addu            t1, kva, size   ;       \
        subu            t2, linesize, 1 ;       \
        not             t2              ;       \
        and             t0, kva, t2     ;       \
        addiu           t1, t1, -1      ;       \
        and             t1, t2          ;       \
9:      cache           op, 0(t0)       ;       \
        bne             t0, t1, 9b      ;       \
         addu           t0, linesize    ;       \
        .set reorder                    ;



#define IS_SHIFT        22
#define IL_SHIFT        19
#define IA_SHIFT        16
#define DS_SHIFT        13
#define DL_SHIFT        10
#define DA_SHIFT         7
#define IS_MASK          7
#define IL_MASK          7
#define IA_MASK          7
#define DS_MASK          7
#define DL_MASK          7
#define DA_MASK          7
#define ICE_MASK        0x80000000
#define DCE_MASK        0x40000000

#define CP0_BRCM_CONFIG0        $22, 0
#define CP0_BRCM_MODE           $22, 1
#define CP0_CONFIG_K0_MASK      7

#define CP0_ICACHE_TAG_LO       $28
#define CP0_ICACHE_DATA_LO      $28, 1
#define CP0_DCACHE_TAG_LO       $28, 2
#define CP0_D_SEC_CACHE_DATA_LO $28, 3
#define CP0_ICACHE_TAG_HI       $29
#define CP0_ICACHE_DATA_HI      $29, 1
#define CP0_DCACHE_TAG_HI       $29, 2

#define CP0_BRCM_MODE_Luc_MASK          (1 << 11)
#define CP0_BRCM_CONFIG0_CWF_MASK       (1 << 20)
#define CP0_BRCM_CONFIG0_TSE_MASK       (1 << 19)
#define CP0_BRCM_MODE_SET_MASK          (1 << 7)
#define CP0_BRCM_MODE_ClkRATIO_MASK     (7 << 4)
#define CP0_BRCM_MODE_BrPRED_MASK       (3 << 24)
#define CP0_BRCM_MODE_BrPRED_SHIFT      24
#define CP0_BRCM_MODE_BrHIST_MASK       (0x1f << 20)
#define CP0_BRCM_MODE_BrHIST_SHIFT      20

/* ZSC L2 Cache Register Access Register Definitions */
#define BRCM_ZSC_ALL_REGS_SELECT                0x7 << 24

#define BRCM_ZSC_CONFIG_REG                     0 << 3
#define BRCM_ZSC_REQ_BUFFER_REG                 2 << 3
#define BRCM_ZSC_RBUS_ADDR_MAPPING_REG0         4 << 3
#define BRCM_ZSC_RBUS_ADDR_MAPPING_REG1         6 << 3
#define BRCM_ZSC_RBUS_ADDR_MAPPING_REG2         8 << 3

#define BRCM_ZSC_SCB0_ADDR_MAPPING_REG0         0xa << 3
#define BRCM_ZSC_SCB0_ADDR_MAPPING_REG1         0xc << 3

#define BRCM_ZSC_SCB1_ADDR_MAPPING_REG0         0xe << 3
#define BRCM_ZSC_SCB1_ADDR_MAPPING_REG1         0x10 << 3

#define BRCM_ZSC_CONFIG_LMB1En                  1 << (15)
#define BRCM_ZSC_CONFIG_LMB0En                  1 << (14)

/* branch predition values */

#define BRCM_BrPRED_ALL_TAKEN           (0x0)
#define BRCM_BrPRED_ALL_NOT_TAKEN       (0x1)
#define BRCM_BrPRED_BHT_ENABLE          (0x2)
#define BRCM_BrPRED_PREDICT_BACKWARD    (0x3)



.align 2
/*
 * Function:    size_i_cache
 * Arguments:   None
 * Returns:     v0 = i cache size, v1 = I cache line size
 * Description: compute the I-cache size and I-cache line size
 * Trashes:     v0, v1, a0, t0
 *
 *      pseudo code:
 *
 */

LEAF(size_i_cache)
        .set    noreorder

        mfc0    a0, CP0_CONFIG, 1
        move    t0, a0

        /*
         * Determine sets per way: IS
         *
         * This field contains the number of sets (i.e., indices) per way of
         * the instruction cache:
         * i) 0x0: 64, ii) 0x1: 128, iii) 0x2: 256, iv) 0x3: 512, v) 0x4: 1k
         * vi) 0x5 - 0x7: Reserved.
         */

        srl     a0, a0, IS_SHIFT
        and     a0, a0, IS_MASK

        /* sets per way = (64<<IS) */

        li      v0, 0x40
        sllv    v0, v0, a0

        /*
         * Determine line size
         *
         * This field contains the line size of the instruction cache:
         * i) 0x0: No I-cache present, i) 0x3: 16 bytes, ii) 0x4: 32 bytes, iii)
         * 0x5: 64 bytes, iv) the rest: Reserved.
         */

        move    a0, t0

        srl     a0, a0, IL_SHIFT
        and     a0, a0, IL_MASK

        beqz    a0, no_i_cache
        nop

        /* line size = 2 ^ (IL+1) */

        addi    a0, a0, 1
        li      v1, 1
        sll     v1, v1, a0

        /* v0 now have sets per way, multiply it by line size now
         * that will give the set size
         */

        sll     v0, v0, a0

        /*
         * Determine set associativity
         *
         * This field contains the set associativity of the instruction cache.
         * i) 0x0: Direct mapped, ii) 0x1: 2-way, iii) 0x2: 3-way, iv) 0x3:
         * 4-way, v) 0x4 - 0x7: Reserved.
         */

        move    a0, t0

        srl     a0, a0, IA_SHIFT
        and     a0, a0, IA_MASK
        addi    a0, a0, 0x1

        /* v0 has the set size, multiply it by
         * set associativiy, to get the cache size
         */

        multu   v0, a0  /*multu is interlocked, so no need to insert nops */
        mflo    v0
        b       1f
        nop

no_i_cache:
        move    v0, zero
        move    v1, zero
1:
        jr      ra
        nop
        .set    reorder

END(size_i_cache)

/*
 * Function:    size_d_cache
 * Arguments:   None
 * Returns:     v0 = d cache size, v1 = d cache line size
 * Description: compute the D-cache size and D-cache line size.
 * Trashes:     v0, v1, a0, t0
 *
 */

LEAF(size_d_cache)
        .set    noreorder

        mfc0    a0, CP0_CONFIG, 1
        move    t0, a0

        /*
         * Determine sets per way: IS
         *
         * This field contains the number of sets (i.e., indices) per way of
         * the instruction cache:
         * i) 0x0: 64, ii) 0x1: 128, iii) 0x2: 256, iv) 0x3: 512, v) 0x4: 1k
         * vi) 0x5 - 0x7: Reserved.
         */

        srl     a0, a0, DS_SHIFT
        and     a0, a0, DS_MASK

        /* sets per way = (64<<IS) */

        li      v0, 0x40
        sllv    v0, v0, a0

        /*
         * Determine line size
         *
         * This field contains the line size of the instruction cache:
         * i) 0x0: No I-cache present, i) 0x3: 16 bytes, ii) 0x4: 32 bytes, iii)
         * 0x5: 64 bytes, iv) the rest: Reserved.
         */
        move    a0, t0

        srl     a0, a0, DL_SHIFT
        and     a0, a0, DL_MASK

        beqz    a0, no_d_cache
        nop

        /* line size = 2 ^ (IL+1) */

        addi    a0, a0, 1
        li      v1, 1
        sll     v1, v1, a0

        /* v0 now have sets per way, multiply it by line size now
         * that will give the set size
         */

        sll     v0, v0, a0

        /* determine set associativity
         *
         * This field contains the set associativity of the instruction cache.
         * i) 0x0: Direct mapped, ii) 0x1: 2-way, iii) 0x2: 3-way, iv) 0x3:
         * 4-way, v) 0x4 - 0x7: Reserved.
         */

        move    a0, t0

        srl     a0, a0, DA_SHIFT
        and     a0, a0, DA_MASK
        addi    a0, a0, 0x1

        /* v0 has the set size, multiply it by
         * set associativiy, to get the cache size
         */

        multu   v0, a0  /*multu is interlocked, so no need to insert nops */
        mflo    v0

        b       1f
        nop

no_d_cache:
        move    v0, zero
        move    v1, zero
1:
        jr      ra
        nop
        .set    reorder

END(size_d_cache)


/*
 * Function: enable_ID
 * Arguments:   None
 * Returns:     None
 * Description: Enable I and D caches, initialize I and D-caches, also set
 *              hardware delay for d-cache (TP0).
 * Trashes:     t0
 *
 */
        .global enable_ID
        .ent    enable_ID
        .set    noreorder
enable_ID:
        mfc0    t0, CP0_BRCM_CONFIG0
        or      t0, t0, (ICE_MASK | DCE_MASK)
        mtc0    t0, CP0_BRCM_CONFIG0
        jr      ra
        nop

        .end    enable_ID
        .set    reorder


/*
 * Function: l1_init
 * Arguments:   None
 * Returns:     None
 * Description: Enable I and D caches, and initialize I and D-caches
 * Trashes:     a0, v0, v1, t0, t1, t2, t8
 *
 */
        .globl  l1_init
        .ent    l1_init
        .set    noreorder
l1_init:

        /* save return address */
        move    t8, ra


        /* initialize I and D cache Data and Tag registers.  */
        mtc0    zero, CP0_ICACHE_TAG_LO
        mtc0    zero, CP0_ICACHE_TAG_HI
        mtc0    zero, CP0_ICACHE_DATA_LO
        mtc0    zero, CP0_ICACHE_DATA_HI
        mtc0    zero, CP0_DCACHE_TAG_LO
        mtc0    zero, CP0_DCACHE_TAG_HI

        /* Enable Caches before Clearing. If the caches are disabled
         * then the cache operations to clear the cache will be ignored
         */

        jal     enable_ID
        nop

        jal     size_i_cache    /* v0 = i-cache size, v1 = i-cache line size */
        nop

        /* run uncached in kseg 1 */
        la      k0, 1f
        lui     k1, 0x2000
        or      k0, k1, k0
        jr      k0
        nop
1:

        /*
         * set K0 cache mode
         */

        mfc0    t0, CP0_CONFIG
        and     t0, t0, ~CP0_CONFIG_K0_MASK
        or      t0, t0, 3       /* Write Back mode */
        mtc0    t0, CP0_CONFIG

        /*
         * Initialize instruction cache.
         */

        li      a0, KSEG0
        cacheop(a0, v0, v1, Index_Store_Tag_I)

        /*
         * Now we can run from I-$, kseg 0
         */
        la      k0, 1f
        lui     k1, 0x2000
        or      k0, k1, k0
        xor     k0, k1, k0
        jr      k0
        nop
1:
        /*
         * Initialize data cache.
         */

        jal     size_d_cache    /* v0 = d-cache size, v1 = d-cache line size */
        nop


        li      a0, KSEG0
        cacheop(a0, v0, v1, Index_Store_Tag_D)

        jr      t8
        nop

        .end    l1_init
        .set    reorder


/*
 * Function:    set_other_config
 * Arguments:   none
 * Returns:     None
 * Description: initialize other remainder configuration to defaults.
 * Trashes:     t0, t1
 *
 *      pseudo code:
 *
 */
LEAF(set_other_config)
        .set noreorder

        /* enable Bus error for I-fetch */
        mfc0    t0, CP0_CACHEERR, 0
        li      t1, 0x4
        or      t0, t1
        mtc0    t0, CP0_CACHEERR, 0

        /* enable Bus error for Load */
        mfc0    t0, CP0_CACHEERR, 1
        li      t1, 0x4
        or      t0, t1
        mtc0    t0, CP0_CACHEERR, 1

        /* enable Bus Error for Store */
        mfc0    t0, CP0_CACHEERR, 2
        li      t1, 0x4
        or      t0, t1
        mtc0    t0, CP0_CACHEERR, 2

        jr      ra
        nop
        .set reorder
END(set_other_config)

/*
 * Function:    set_branch_pred
 * Arguments:   none
 * Returns:     None
 * Description:
 * Trashes:     t0, t1
 *
 *      pseudo code:
 *
 */

LEAF(set_branch_pred)
        .set noreorder
        mfc0    t0, CP0_BRCM_MODE
        li      t1, ~(CP0_BRCM_MODE_BrPRED_MASK | CP0_BRCM_MODE_BrHIST_MASK )
        and     t0, t0, t1

        /* enable Branch prediction */
        li      t1, BRCM_BrPRED_BHT_ENABLE
        sll     t1, CP0_BRCM_MODE_BrPRED_SHIFT
        or      t0, t0, t1

        /* set history count to 8 */
        li      t1, 8
        sll     t1, CP0_BRCM_MODE_BrHIST_SHIFT
        or      t0, t0, t1

        mtc0    t0, CP0_BRCM_MODE
        jr      ra
        nop
        .set    reorder
END(set_branch_pred)


/*
 * Function:    set_luc
 * Arguments:   set link uncached.
 * Returns:     None
 * Description:
 * Trashes:     t0, t1
 *
 */
LEAF(set_luc)
        .set noreorder
        mfc0    t0, CP0_BRCM_MODE
        li      t1, ~(CP0_BRCM_MODE_Luc_MASK)
        and     t0, t0, t1

        /* set Luc */
        ori     t0, t0, CP0_BRCM_MODE_Luc_MASK

        mtc0    t0, CP0_BRCM_MODE
        jr      ra
        nop
        .set    reorder
END(set_luc)

/*
 * Function:    set_cwf_tse
 * Arguments:   set CWF and TSE bits
 * Returns:     None
 * Description:
 * Trashes:     t0, t1
 *
 */
LEAF(set_cwf_tse)
        .set noreorder
        mfc0    t0, CP0_BRCM_CONFIG0
        li      t1, (CP0_BRCM_CONFIG0_CWF_MASK | CP0_BRCM_CONFIG0_TSE_MASK)
        or      t0, t0, t1

        mtc0    t0, CP0_BRCM_CONFIG0
        jr      ra
        nop
        .set    reorder
END(set_cwf_tse)

/*
 * Function:    set_clock_ratio
 * Arguments:   set clock ratio specified by a0
 * Returns:     None
 * Description:
 * Trashes:     v0, v1, a0, a1
 *
 *      pseudo code:
 *
 */
LEAF(set_clock_ratio)
        .set noreorder

        mfc0    t0, CP0_BRCM_MODE
        li      t1, ~(CP0_BRCM_MODE_SET_MASK | CP0_BRCM_MODE_ClkRATIO_MASK)
        and     t0, t0, t1
        li      t1, CP0_BRCM_MODE_SET_MASK
        or      t0, t0, t1
        or      t0, t0, a0
        mtc0    t0, CP0_BRCM_MODE
        jr      ra
        nop
        .set    reorder
END(set_clock_ratio)
/*
 * Function: set_zephyr
 * Arguments:   None
 * Returns:     None
 * Description: Set any zephyr bits
 * Trashes:     t0 & t1
 *
 */
LEAF(set_zephyr)
        .set    noreorder

        /* enable read/write of CP0 #22 sel. 8 */
        li      t0, 0x5a455048
        .word   0x4088b00f      /* mtc0    t0, $22, 15 */

        .word   0x4008b008      /* mfc0    t0, $22, 8 */
        li      t1, 0x09008000  /* turn off pref, jtb */
        or      t0, t0, t1
        .word   0x4088b008      /* mtc0    t0, $22, 8 */
        sync

        /* disable read/write of CP0 #22 sel 8 */
        li      t0, 0x0
        .word   0x4088b00f      /* mtc0    t0, $22, 15 */


        jr      ra
        nop
        .set reorder

END(set_zephyr)


/*
 * Function:    set_llmb
 * Arguments:   a0=0 disable llmb, a0=1 enables llmb
 * Returns:     None
 * Description:
 * Trashes:     t0, t1, t2
 *
 *      pseudo code:
 *
 */
LEAF(set_llmb)
        .set noreorder

        li      t2, 0x90000000 | BRCM_ZSC_ALL_REGS_SELECT | BRCM_ZSC_CONFIG_REG
        sync
        cache   0x7, 0x0(t2)
        sync
        mfc0    t0, CP0_D_SEC_CACHE_DATA_LO
        li      t1, ~(BRCM_ZSC_CONFIG_LMB1En | BRCM_ZSC_CONFIG_LMB0En)
        and     t0, t0, t1

        beqz    a0, svlmb
        nop

enable_lmb:
        li      t1, (BRCM_ZSC_CONFIG_LMB1En | BRCM_ZSC_CONFIG_LMB0En)
        or      t0, t0, t1

svlmb:
        mtc0    t0, CP0_D_SEC_CACHE_DATA_LO
        sync
        cache   0xb, 0x0(t2)
        sync

        jr      ra
        nop
        .set reorder

END(set_llmb)
/*
 * Function:    core_init
 * Arguments:   none
 * Returns:     None
 * Description: initialize core related configuration
 * Trashes:     v0,v1,a0,a1,t8
 *
 *      pseudo code:
 *
 */
        .globl  core_init
        .ent    core_init
        .set    noreorder
core_init:
        move    t8, ra

        /* set Zephyr bits. */
        bal     set_zephyr
        nop

        /* set low latency memory bus */
        li      a0, 1
        bal     set_llmb
        nop

        /* set branch prediction (TP0 only) */
        bal     set_branch_pred
        nop

        /* set link uncached */
        bal     set_luc
        nop

        /* set CWF and TSE */
        bal     set_cwf_tse
        nop

        /*
         *set clock ratio by setting 1 to 'set'
         * and 0 to ClkRatio, (TP0 only)
         */
        li      a0, 0
        bal     set_clock_ratio
        nop

        /* set other configuration to defaults */
        bal     set_other_config
        nop

        move    ra, t8
        jr      ra
        nop

        .set reorder
        .end    core_init

/*
 * Function:    clear_jump_target_buffer
 * Arguments:   None
 * Returns:     None
 * Description:
 * Trashes:     t0, t1, t2
 *
 */
#define RESET_CALL_RETURN_STACK_THIS_THREAD             (0x06<<16)
#define RESET_JUMP_TARGET_BUFFER_THIS_THREAD            (0x04<<16)
#define JTB_CS_CNTL_MASK                                (0xFF<<16)

        .globl  clear_jump_target_buffer
        .ent    clear_jump_target_buffer
        .set    noreorder
clear_jump_target_buffer:

        mfc0    t0, $22, 2
        nop
        nop

        li      t1, ~JTB_CS_CNTL_MASK
        and     t0, t0, t1
        li      t2, RESET_CALL_RETURN_STACK_THIS_THREAD
        or      t0, t0, t2
        mtc0    t0, $22, 2
        nop
        nop

        and     t0, t0, t1
        li      t2, RESET_JUMP_TARGET_BUFFER_THIS_THREAD
        or      t0, t0, t2
        mtc0    t0, $22, 2
        nop
        nop
        jr      ra
        nop

        .end    clear_jump_target_buffer
        .set    reorder
/*
 * Function:    bmips_cache_init
 * Arguments:   None
 * Returns:     None
 * Description: Enable I and D caches, and initialize I and D-caches
 * Trashes:     v0, v1, t0, t1, t2, t5, t7, t8
 *
 */
        .globl  bmips_5xxx_init
        .ent    bmips_5xxx_init
        .set    noreorder
bmips_5xxx_init:

        /* save return address and A0 */
        move    t7, ra
        move    t5, a0

        jal     l1_init
        nop

        jal     core_init
        nop

        jal     clear_jump_target_buffer
        nop

        mtc0    zero, CP0_CAUSE

        move    a0, t5
        jr      t7
        nop

        .end    bmips_5xxx_init
        .set    reorder


#endif