1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0 2f1df9364SStefan Roese /* 3f1df9364SStefan Roese * Copyright (C) Marvell International Ltd. and its affiliates 4f1df9364SStefan Roese */ 5f1df9364SStefan Roese 6f1df9364SStefan Roese #include <common.h> 7f1df9364SStefan Roese #include <i2c.h> 8f1df9364SStefan Roese #include <spl.h> 9f1df9364SStefan Roese #include <asm/io.h> 10f1df9364SStefan Roese #include <asm/arch/cpu.h> 11f1df9364SStefan Roese #include <asm/arch/soc.h> 12f1df9364SStefan Roese 13f1df9364SStefan Roese #include "ddr3_init.h" 14f1df9364SStefan Roese #include "xor_regs.h" 15f1df9364SStefan Roese 16f1df9364SStefan Roese /* defines */ 17f1df9364SStefan Roese #ifdef MV_DEBUG 18f1df9364SStefan Roese #define DB(x) x 19f1df9364SStefan Roese #else 20f1df9364SStefan Roese #define DB(x) 21f1df9364SStefan Roese #endif 22f1df9364SStefan Roese 23f1df9364SStefan Roese static u32 ui_xor_regs_ctrl_backup; 24f1df9364SStefan Roese static u32 ui_xor_regs_base_backup[MAX_CS]; 25f1df9364SStefan Roese static u32 ui_xor_regs_mask_backup[MAX_CS]; 26f1df9364SStefan Roese 27f1df9364SStefan Roese void mv_sys_xor_init(u32 num_of_cs, u32 cs_ena, u32 cs_size, u32 base_delta) 28f1df9364SStefan Roese { 29f1df9364SStefan Roese u32 reg, ui, base, cs_count; 30f1df9364SStefan Roese 31f1df9364SStefan Roese ui_xor_regs_ctrl_backup = reg_read(XOR_WINDOW_CTRL_REG(0, 0)); 32f1df9364SStefan Roese for (ui = 0; ui < MAX_CS; ui++) 33f1df9364SStefan Roese ui_xor_regs_base_backup[ui] = 34f1df9364SStefan Roese reg_read(XOR_BASE_ADDR_REG(0, ui)); 35f1df9364SStefan Roese for (ui = 0; ui < MAX_CS; ui++) 36f1df9364SStefan Roese ui_xor_regs_mask_backup[ui] = 37f1df9364SStefan Roese reg_read(XOR_SIZE_MASK_REG(0, ui)); 38f1df9364SStefan Roese 39f1df9364SStefan Roese reg = 0; 40f1df9364SStefan Roese for (ui = 0; ui < (num_of_cs); ui++) { 41f1df9364SStefan Roese /* Enable Window x for each CS */ 42f1df9364SStefan Roese reg |= (0x1 << (ui)); 43f1df9364SStefan Roese /* Enable Window x for each CS */ 44f1df9364SStefan Roese reg |= (0x3 << ((ui * 2) + 16)); 45f1df9364SStefan Roese } 46f1df9364SStefan Roese 47f1df9364SStefan Roese reg_write(XOR_WINDOW_CTRL_REG(0, 0), reg); 48f1df9364SStefan Roese 49f1df9364SStefan Roese cs_count = 0; 50f1df9364SStefan Roese for (ui = 0; ui < num_of_cs; ui++) { 51f1df9364SStefan Roese if (cs_ena & (1 << ui)) { 52f1df9364SStefan Roese /* 53f1df9364SStefan Roese * window x - Base - 0x00000000, 54f1df9364SStefan Roese * Attribute 0x0e - DRAM 55f1df9364SStefan Roese */ 56f1df9364SStefan Roese base = cs_size * ui + base_delta; 57f1df9364SStefan Roese switch (ui) { 58f1df9364SStefan Roese case 0: 59f1df9364SStefan Roese base |= 0xe00; 60f1df9364SStefan Roese break; 61f1df9364SStefan Roese case 1: 62f1df9364SStefan Roese base |= 0xd00; 63f1df9364SStefan Roese break; 64f1df9364SStefan Roese case 2: 65f1df9364SStefan Roese base |= 0xb00; 66f1df9364SStefan Roese break; 67f1df9364SStefan Roese case 3: 68f1df9364SStefan Roese base |= 0x700; 69f1df9364SStefan Roese break; 70f1df9364SStefan Roese } 71f1df9364SStefan Roese 72f1df9364SStefan Roese reg_write(XOR_BASE_ADDR_REG(0, cs_count), base); 73f1df9364SStefan Roese 74f1df9364SStefan Roese /* window x - Size */ 75f1df9364SStefan Roese reg_write(XOR_SIZE_MASK_REG(0, cs_count), 0x7fff0000); 76f1df9364SStefan Roese cs_count++; 77f1df9364SStefan Roese } 78f1df9364SStefan Roese } 79f1df9364SStefan Roese 80f1df9364SStefan Roese mv_xor_hal_init(1); 81f1df9364SStefan Roese 82f1df9364SStefan Roese return; 83f1df9364SStefan Roese } 84f1df9364SStefan Roese 85f1df9364SStefan Roese void mv_sys_xor_finish(void) 86f1df9364SStefan Roese { 87f1df9364SStefan Roese u32 ui; 88f1df9364SStefan Roese 89f1df9364SStefan Roese reg_write(XOR_WINDOW_CTRL_REG(0, 0), ui_xor_regs_ctrl_backup); 90f1df9364SStefan Roese for (ui = 0; ui < MAX_CS; ui++) 91f1df9364SStefan Roese reg_write(XOR_BASE_ADDR_REG(0, ui), 92f1df9364SStefan Roese ui_xor_regs_base_backup[ui]); 93f1df9364SStefan Roese for (ui = 0; ui < MAX_CS; ui++) 94f1df9364SStefan Roese reg_write(XOR_SIZE_MASK_REG(0, ui), 95f1df9364SStefan Roese ui_xor_regs_mask_backup[ui]); 96f1df9364SStefan Roese 97f1df9364SStefan Roese reg_write(XOR_ADDR_OVRD_REG(0, 0), 0); 98f1df9364SStefan Roese } 99f1df9364SStefan Roese 100f1df9364SStefan Roese /* 101f1df9364SStefan Roese * mv_xor_hal_init - Initialize XOR engine 102f1df9364SStefan Roese * 103f1df9364SStefan Roese * DESCRIPTION: 104f1df9364SStefan Roese * This function initialize XOR unit. 105f1df9364SStefan Roese * INPUT: 106f1df9364SStefan Roese * None. 107f1df9364SStefan Roese * 108f1df9364SStefan Roese * OUTPUT: 109f1df9364SStefan Roese * None. 110f1df9364SStefan Roese * 111f1df9364SStefan Roese * RETURN: 112f1df9364SStefan Roese * MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise. 113f1df9364SStefan Roese */ 114f1df9364SStefan Roese void mv_xor_hal_init(u32 xor_chan_num) 115f1df9364SStefan Roese { 116f1df9364SStefan Roese u32 i; 117f1df9364SStefan Roese 118f1df9364SStefan Roese /* Abort any XOR activity & set default configuration */ 119f1df9364SStefan Roese for (i = 0; i < xor_chan_num; i++) { 120f1df9364SStefan Roese mv_xor_command_set(i, MV_STOP); 121f1df9364SStefan Roese mv_xor_ctrl_set(i, (1 << XEXCR_REG_ACC_PROTECT_OFFS) | 122f1df9364SStefan Roese (4 << XEXCR_DST_BURST_LIMIT_OFFS) | 123f1df9364SStefan Roese (4 << XEXCR_SRC_BURST_LIMIT_OFFS)); 124f1df9364SStefan Roese } 125f1df9364SStefan Roese } 126f1df9364SStefan Roese 127f1df9364SStefan Roese /* 128f1df9364SStefan Roese * mv_xor_ctrl_set - Set XOR channel control registers 129f1df9364SStefan Roese * 130f1df9364SStefan Roese * DESCRIPTION: 131f1df9364SStefan Roese * 132f1df9364SStefan Roese * INPUT: 133f1df9364SStefan Roese * 134f1df9364SStefan Roese * OUTPUT: 135f1df9364SStefan Roese * None. 136f1df9364SStefan Roese * 137f1df9364SStefan Roese * RETURN: 138f1df9364SStefan Roese * MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise. 139f1df9364SStefan Roese * NOTE: 140f1df9364SStefan Roese * This function does not modify the Operation_mode field of control register. 141f1df9364SStefan Roese */ 142f1df9364SStefan Roese int mv_xor_ctrl_set(u32 chan, u32 xor_ctrl) 143f1df9364SStefan Roese { 144f1df9364SStefan Roese u32 old_value; 145f1df9364SStefan Roese 146f1df9364SStefan Roese /* update the XOR Engine [0..1] Configuration Registers (XEx_c_r) */ 147f1df9364SStefan Roese old_value = reg_read(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan))) & 148f1df9364SStefan Roese XEXCR_OPERATION_MODE_MASK; 149f1df9364SStefan Roese xor_ctrl &= ~XEXCR_OPERATION_MODE_MASK; 150f1df9364SStefan Roese xor_ctrl |= old_value; 151f1df9364SStefan Roese reg_write(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)), xor_ctrl); 152f1df9364SStefan Roese 153f1df9364SStefan Roese return MV_OK; 154f1df9364SStefan Roese } 155f1df9364SStefan Roese 156f1df9364SStefan Roese int mv_xor_mem_init(u32 chan, u32 start_ptr, u32 block_size, 157f1df9364SStefan Roese u32 init_val_high, u32 init_val_low) 158f1df9364SStefan Roese { 159f1df9364SStefan Roese u32 temp; 160f1df9364SStefan Roese 161f1df9364SStefan Roese /* Parameter checking */ 162f1df9364SStefan Roese if (chan >= MV_XOR_MAX_CHAN) 163f1df9364SStefan Roese return MV_BAD_PARAM; 164f1df9364SStefan Roese 165f1df9364SStefan Roese if (MV_ACTIVE == mv_xor_state_get(chan)) 166f1df9364SStefan Roese return MV_BUSY; 167f1df9364SStefan Roese 168f1df9364SStefan Roese if ((block_size < XEXBSR_BLOCK_SIZE_MIN_VALUE) || 169f1df9364SStefan Roese (block_size > XEXBSR_BLOCK_SIZE_MAX_VALUE)) 170f1df9364SStefan Roese return MV_BAD_PARAM; 171f1df9364SStefan Roese 172f1df9364SStefan Roese /* set the operation mode to Memory Init */ 173f1df9364SStefan Roese temp = reg_read(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan))); 174f1df9364SStefan Roese temp &= ~XEXCR_OPERATION_MODE_MASK; 175f1df9364SStefan Roese temp |= XEXCR_OPERATION_MODE_MEM_INIT; 176f1df9364SStefan Roese reg_write(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)), temp); 177f1df9364SStefan Roese 178f1df9364SStefan Roese /* 179f1df9364SStefan Roese * update the start_ptr field in XOR Engine [0..1] Destination Pointer 180f1df9364SStefan Roese * Register 181f1df9364SStefan Roese */ 182f1df9364SStefan Roese reg_write(XOR_DST_PTR_REG(XOR_UNIT(chan), XOR_CHAN(chan)), start_ptr); 183f1df9364SStefan Roese 184f1df9364SStefan Roese /* 185f1df9364SStefan Roese * update the Block_size field in the XOR Engine[0..1] Block Size 186f1df9364SStefan Roese * Registers 187f1df9364SStefan Roese */ 188f1df9364SStefan Roese reg_write(XOR_BLOCK_SIZE_REG(XOR_UNIT(chan), XOR_CHAN(chan)), 189f1df9364SStefan Roese block_size); 190f1df9364SStefan Roese 191f1df9364SStefan Roese /* 192f1df9364SStefan Roese * update the field Init_val_l in the XOR Engine Initial Value Register 193f1df9364SStefan Roese * Low (XEIVRL) 194f1df9364SStefan Roese */ 195f1df9364SStefan Roese reg_write(XOR_INIT_VAL_LOW_REG(XOR_UNIT(chan)), init_val_low); 196f1df9364SStefan Roese 197f1df9364SStefan Roese /* 198f1df9364SStefan Roese * update the field Init_val_h in the XOR Engine Initial Value Register 199f1df9364SStefan Roese * High (XEIVRH) 200f1df9364SStefan Roese */ 201f1df9364SStefan Roese reg_write(XOR_INIT_VAL_HIGH_REG(XOR_UNIT(chan)), init_val_high); 202f1df9364SStefan Roese 203f1df9364SStefan Roese /* start transfer */ 204f1df9364SStefan Roese reg_bit_set(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)), 205f1df9364SStefan Roese XEXACTR_XESTART_MASK); 206f1df9364SStefan Roese 207f1df9364SStefan Roese return MV_OK; 208f1df9364SStefan Roese } 209f1df9364SStefan Roese 210f1df9364SStefan Roese /* 211f1df9364SStefan Roese * mv_xor_state_get - Get XOR channel state. 212f1df9364SStefan Roese * 213f1df9364SStefan Roese * DESCRIPTION: 214f1df9364SStefan Roese * XOR channel activity state can be active, idle, paused. 215f1df9364SStefan Roese * This function retrunes the channel activity state. 216f1df9364SStefan Roese * 217f1df9364SStefan Roese * INPUT: 218f1df9364SStefan Roese * chan - the channel number 219f1df9364SStefan Roese * 220f1df9364SStefan Roese * OUTPUT: 221f1df9364SStefan Roese * None. 222f1df9364SStefan Roese * 223f1df9364SStefan Roese * RETURN: 224f1df9364SStefan Roese * XOR_CHANNEL_IDLE - If the engine is idle. 225f1df9364SStefan Roese * XOR_CHANNEL_ACTIVE - If the engine is busy. 226f1df9364SStefan Roese * XOR_CHANNEL_PAUSED - If the engine is paused. 227f1df9364SStefan Roese * MV_UNDEFINED_STATE - If the engine state is undefind or there is no 228f1df9364SStefan Roese * such engine 229f1df9364SStefan Roese */ 230f1df9364SStefan Roese enum mv_state mv_xor_state_get(u32 chan) 231f1df9364SStefan Roese { 232f1df9364SStefan Roese u32 state; 233f1df9364SStefan Roese 234f1df9364SStefan Roese /* Parameter checking */ 235f1df9364SStefan Roese if (chan >= MV_XOR_MAX_CHAN) { 236f1df9364SStefan Roese DB(printf("%s: ERR. Invalid chan num %d\n", __func__, chan)); 237f1df9364SStefan Roese return MV_UNDEFINED_STATE; 238f1df9364SStefan Roese } 239f1df9364SStefan Roese 240f1df9364SStefan Roese /* read the current state */ 241f1df9364SStefan Roese state = reg_read(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan))); 242f1df9364SStefan Roese state &= XEXACTR_XESTATUS_MASK; 243f1df9364SStefan Roese 244f1df9364SStefan Roese /* return the state */ 245f1df9364SStefan Roese switch (state) { 246f1df9364SStefan Roese case XEXACTR_XESTATUS_IDLE: 247f1df9364SStefan Roese return MV_IDLE; 248f1df9364SStefan Roese case XEXACTR_XESTATUS_ACTIVE: 249f1df9364SStefan Roese return MV_ACTIVE; 250f1df9364SStefan Roese case XEXACTR_XESTATUS_PAUSED: 251f1df9364SStefan Roese return MV_PAUSED; 252f1df9364SStefan Roese } 253f1df9364SStefan Roese 254f1df9364SStefan Roese return MV_UNDEFINED_STATE; 255f1df9364SStefan Roese } 256f1df9364SStefan Roese 257f1df9364SStefan Roese /* 258f1df9364SStefan Roese * mv_xor_command_set - Set command of XOR channel 259f1df9364SStefan Roese * 260f1df9364SStefan Roese * DESCRIPTION: 261f1df9364SStefan Roese * XOR channel can be started, idle, paused and restarted. 262f1df9364SStefan Roese * Paused can be set only if channel is active. 263f1df9364SStefan Roese * Start can be set only if channel is idle or paused. 264f1df9364SStefan Roese * Restart can be set only if channel is paused. 265f1df9364SStefan Roese * Stop can be set only if channel is active. 266f1df9364SStefan Roese * 267f1df9364SStefan Roese * INPUT: 268f1df9364SStefan Roese * chan - The channel number 269f1df9364SStefan Roese * command - The command type (start, stop, restart, pause) 270f1df9364SStefan Roese * 271f1df9364SStefan Roese * OUTPUT: 272f1df9364SStefan Roese * None. 273f1df9364SStefan Roese * 274f1df9364SStefan Roese * RETURN: 275f1df9364SStefan Roese * MV_OK on success , MV_BAD_PARAM on erroneous parameter, MV_ERROR on 276f1df9364SStefan Roese * undefind XOR engine mode 277f1df9364SStefan Roese */ 278f1df9364SStefan Roese int mv_xor_command_set(u32 chan, enum mv_command command) 279f1df9364SStefan Roese { 280f1df9364SStefan Roese enum mv_state state; 281f1df9364SStefan Roese 282f1df9364SStefan Roese /* Parameter checking */ 283f1df9364SStefan Roese if (chan >= MV_XOR_MAX_CHAN) { 284f1df9364SStefan Roese DB(printf("%s: ERR. Invalid chan num %d\n", __func__, chan)); 285f1df9364SStefan Roese return MV_BAD_PARAM; 286f1df9364SStefan Roese } 287f1df9364SStefan Roese 288f1df9364SStefan Roese /* get the current state */ 289f1df9364SStefan Roese state = mv_xor_state_get(chan); 290f1df9364SStefan Roese 291f1df9364SStefan Roese if ((command == MV_START) && (state == MV_IDLE)) { 292f1df9364SStefan Roese /* command is start and current state is idle */ 293f1df9364SStefan Roese reg_bit_set(XOR_ACTIVATION_REG 294f1df9364SStefan Roese (XOR_UNIT(chan), XOR_CHAN(chan)), 295f1df9364SStefan Roese XEXACTR_XESTART_MASK); 296f1df9364SStefan Roese return MV_OK; 297f1df9364SStefan Roese } else if ((command == MV_STOP) && (state == MV_ACTIVE)) { 298f1df9364SStefan Roese /* command is stop and current state is active */ 299f1df9364SStefan Roese reg_bit_set(XOR_ACTIVATION_REG 300f1df9364SStefan Roese (XOR_UNIT(chan), XOR_CHAN(chan)), 301f1df9364SStefan Roese XEXACTR_XESTOP_MASK); 302f1df9364SStefan Roese return MV_OK; 303f1df9364SStefan Roese } else if (((enum mv_state)command == MV_PAUSED) && 304f1df9364SStefan Roese (state == MV_ACTIVE)) { 305f1df9364SStefan Roese /* command is paused and current state is active */ 306f1df9364SStefan Roese reg_bit_set(XOR_ACTIVATION_REG 307f1df9364SStefan Roese (XOR_UNIT(chan), XOR_CHAN(chan)), 308f1df9364SStefan Roese XEXACTR_XEPAUSE_MASK); 309f1df9364SStefan Roese return MV_OK; 310f1df9364SStefan Roese } else if ((command == MV_RESTART) && (state == MV_PAUSED)) { 311f1df9364SStefan Roese /* command is restart and current state is paused */ 312f1df9364SStefan Roese reg_bit_set(XOR_ACTIVATION_REG 313f1df9364SStefan Roese (XOR_UNIT(chan), XOR_CHAN(chan)), 314f1df9364SStefan Roese XEXACTR_XERESTART_MASK); 315f1df9364SStefan Roese return MV_OK; 316f1df9364SStefan Roese } else if ((command == MV_STOP) && (state == MV_IDLE)) { 317f1df9364SStefan Roese /* command is stop and current state is active */ 318f1df9364SStefan Roese return MV_OK; 319f1df9364SStefan Roese } 320f1df9364SStefan Roese 321f1df9364SStefan Roese /* illegal command */ 322f1df9364SStefan Roese DB(printf("%s: ERR. Illegal command\n", __func__)); 323f1df9364SStefan Roese 324f1df9364SStefan Roese return MV_BAD_PARAM; 325f1df9364SStefan Roese } 326f1df9364SStefan Roese 327f1df9364SStefan Roese void ddr3_new_tip_ecc_scrub(void) 328f1df9364SStefan Roese { 329f1df9364SStefan Roese u32 cs_c, max_cs; 330f1df9364SStefan Roese u32 cs_ena = 0; 331f1df9364SStefan Roese 332f1df9364SStefan Roese printf("DDR3 Training Sequence - Start scrubbing\n"); 333f1df9364SStefan Roese 334f1df9364SStefan Roese max_cs = hws_ddr3_tip_max_cs_get(); 335f1df9364SStefan Roese for (cs_c = 0; cs_c < max_cs; cs_c++) 336f1df9364SStefan Roese cs_ena |= 1 << cs_c; 337f1df9364SStefan Roese 338f1df9364SStefan Roese mv_sys_xor_init(max_cs, cs_ena, 0x80000000, 0); 339f1df9364SStefan Roese 340f1df9364SStefan Roese mv_xor_mem_init(0, 0x00000000, 0x80000000, 0xdeadbeef, 0xdeadbeef); 341f1df9364SStefan Roese /* wait for previous transfer completion */ 342f1df9364SStefan Roese while (mv_xor_state_get(0) != MV_IDLE) 343f1df9364SStefan Roese ; 344f1df9364SStefan Roese 345f1df9364SStefan Roese mv_xor_mem_init(0, 0x80000000, 0x40000000, 0xdeadbeef, 0xdeadbeef); 346f1df9364SStefan Roese 347f1df9364SStefan Roese /* wait for previous transfer completion */ 348f1df9364SStefan Roese while (mv_xor_state_get(0) != MV_IDLE) 349f1df9364SStefan Roese ; 350f1df9364SStefan Roese 351f1df9364SStefan Roese /* Return XOR State */ 352f1df9364SStefan Roese mv_sys_xor_finish(); 353f1df9364SStefan Roese 354f1df9364SStefan Roese printf("DDR3 Training Sequence - End scrubbing\n"); 355f1df9364SStefan Roese } 356