129461e4cSJit Loon Lim /* 229461e4cSJit Loon Lim * Copyright (c) 2022, Intel Corporation. All rights reserved. 329461e4cSJit Loon Lim * 429461e4cSJit Loon Lim * SPDX-License-Identifier: BSD-3-Clause 529461e4cSJit Loon Lim */ 629461e4cSJit Loon Lim 729461e4cSJit Loon Lim #include <assert.h> 829461e4cSJit Loon Lim #include <errno.h> 929461e4cSJit Loon Lim #include <common/debug.h> 10*68bb3e83SJit Loon Lim #include <drivers/delay_timer.h> 1129461e4cSJit Loon Lim #include "ddr.h" 1229461e4cSJit Loon Lim #include <lib/mmio.h> 1329461e4cSJit Loon Lim #include "socfpga_handoff.h" 1429461e4cSJit Loon Lim 1529461e4cSJit Loon Lim int ddr_calibration_check(void) 1629461e4cSJit Loon Lim { 1729461e4cSJit Loon Lim // DDR calibration check 1829461e4cSJit Loon Lim int status = 0; 1929461e4cSJit Loon Lim uint32_t u32data_read = 0; 2029461e4cSJit Loon Lim 2129461e4cSJit Loon Lim NOTICE("DDR: Access address 0x%x:...\n", IO96B_0_REG_BASE); 2229461e4cSJit Loon Lim u32data_read = mmio_read_32(IO96B_0_REG_BASE); 2329461e4cSJit Loon Lim NOTICE("DDR: Access address 0x%x: read 0x%04x\n", IO96B_0_REG_BASE, u32data_read); 2429461e4cSJit Loon Lim 2529461e4cSJit Loon Lim if (u32data_read == -EPERM) { 2629461e4cSJit Loon Lim status = -EPERM; 2729461e4cSJit Loon Lim assert(u32data_read); 2829461e4cSJit Loon Lim } 2929461e4cSJit Loon Lim 3029461e4cSJit Loon Lim u32data_read = 0x0; 3129461e4cSJit Loon Lim NOTICE("DDR: Access address 0x%x: ...\n", IO96B_1_REG_BASE); 3229461e4cSJit Loon Lim u32data_read = mmio_read_32(IO96B_1_REG_BASE); 3329461e4cSJit Loon Lim NOTICE("DDR: Access address 0x%x: read 0x%04x\n", IO96B_1_REG_BASE, u32data_read); 3429461e4cSJit Loon Lim 3529461e4cSJit Loon Lim if (u32data_read == -EPERM) { 3629461e4cSJit Loon Lim status = -EPERM; 3729461e4cSJit Loon Lim assert(u32data_read); 3829461e4cSJit Loon Lim } 3929461e4cSJit Loon Lim 4029461e4cSJit Loon Lim return status; 4129461e4cSJit Loon Lim } 4229461e4cSJit Loon Lim 4329461e4cSJit Loon Lim int iossm_mb_init(void) 4429461e4cSJit Loon Lim { 4529461e4cSJit Loon Lim // int status; 4629461e4cSJit Loon Lim 4729461e4cSJit Loon Lim // Update according to IOSSM mailbox spec 4829461e4cSJit Loon Lim 4929461e4cSJit Loon Lim // if (status) { 5029461e4cSJit Loon Lim // return status; 5129461e4cSJit Loon Lim // } 5229461e4cSJit Loon Lim 5329461e4cSJit Loon Lim return 0; 5429461e4cSJit Loon Lim } 5529461e4cSJit Loon Lim 5629461e4cSJit Loon Lim int wait_respond(uint16_t timeout) 5729461e4cSJit Loon Lim { 5829461e4cSJit Loon Lim uint32_t status = 0; 5929461e4cSJit Loon Lim uint32_t count = 0; 6029461e4cSJit Loon Lim uint32_t data = 0; 6129461e4cSJit Loon Lim 6229461e4cSJit Loon Lim /* Wait status command response ready */ 6329461e4cSJit Loon Lim do { 6429461e4cSJit Loon Lim data = mmio_read_32(IO96B_CSR_REG(CMD_RESPONSE_STATUS)); 6529461e4cSJit Loon Lim count++; 6629461e4cSJit Loon Lim if (count >= timeout) { 6729461e4cSJit Loon Lim return -ETIMEDOUT; 6829461e4cSJit Loon Lim } 6929461e4cSJit Loon Lim 7029461e4cSJit Loon Lim } while (STATUS_COMMAND_RESPONSE(data) != STATUS_COMMAND_RESPONSE_READY); 7129461e4cSJit Loon Lim 7229461e4cSJit Loon Lim status = (data & STATUS_GENERAL_ERROR_MASK) >> STATUS_GENERAL_ERROR_OFFSET; 7329461e4cSJit Loon Lim if (status != 0) { 7429461e4cSJit Loon Lim return status; 7529461e4cSJit Loon Lim } 7629461e4cSJit Loon Lim 7729461e4cSJit Loon Lim status = (data & STATUS_CMD_RESPONSE_ERROR_MASK) >> STATUS_CMD_RESPONSE_ERROR_OFFSET; 7829461e4cSJit Loon Lim if (status != 0) { 7929461e4cSJit Loon Lim return status; 8029461e4cSJit Loon Lim } 8129461e4cSJit Loon Lim 8229461e4cSJit Loon Lim return status; 8329461e4cSJit Loon Lim } 8429461e4cSJit Loon Lim 8529461e4cSJit Loon Lim int iossm_mb_read_response(void) 8629461e4cSJit Loon Lim { 8729461e4cSJit Loon Lim uint32_t status = 0; 8829461e4cSJit Loon Lim unsigned int i; 8929461e4cSJit Loon Lim uint32_t resp_data[IOSSM_RESP_MAX_WORD_SIZE]; 9029461e4cSJit Loon Lim uint32_t resp_param_reg; 9129461e4cSJit Loon Lim 9229461e4cSJit Loon Lim // Check STATUS_CMD_RESPONSE_DATA_PTR_VALID in 9329461e4cSJit Loon Lim // STATUS_COMMAND_RESPONSE to ensure data pointer response 9429461e4cSJit Loon Lim 9529461e4cSJit Loon Lim /* Read CMD_RESPONSE_STATUS and CMD_RESPONSE_DATA_* */ 9629461e4cSJit Loon Lim resp_data[0] = mmio_read_32(IO96B_CSR_REG(CMD_RESPONSE_STATUS)); 9729461e4cSJit Loon Lim resp_data[0] = (resp_data[0] & CMD_RESPONSE_DATA_SHORT_MASK) >> 9829461e4cSJit Loon Lim CMD_RESPONSE_DATA_SHORT_OFFSET; 9929461e4cSJit Loon Lim resp_param_reg = CMD_RESPONSE_STATUS; 10029461e4cSJit Loon Lim for (i = 1; i < IOSSM_RESP_MAX_WORD_SIZE; i++) { 10129461e4cSJit Loon Lim resp_param_reg = resp_param_reg - CMD_RESPONSE_OFFSET; 10229461e4cSJit Loon Lim resp_data[i] = mmio_read_32(IO96B_CSR_REG(resp_param_reg)); 10329461e4cSJit Loon Lim } 10429461e4cSJit Loon Lim 10529461e4cSJit Loon Lim /* Wait for STATUS_COMMAND_RESPONSE_READY*/ 10629461e4cSJit Loon Lim status = wait_respond(1000); 10729461e4cSJit Loon Lim 10829461e4cSJit Loon Lim /* Read CMD_RESPONSE_STATUS and CMD_RESPONSE_DATA_* */ 10929461e4cSJit Loon Lim mmio_setbits_32(STATUS_COMMAND_RESPONSE(IO96B_CSR_REG( 11029461e4cSJit Loon Lim CMD_RESPONSE_STATUS)), 11129461e4cSJit Loon Lim STATUS_COMMAND_RESPONSE_READY_CLEAR); 11229461e4cSJit Loon Lim 11329461e4cSJit Loon Lim return status; 11429461e4cSJit Loon Lim } 11529461e4cSJit Loon Lim 11629461e4cSJit Loon Lim int iossm_mb_send(uint32_t cmd_target_ip_type, uint32_t cmd_target_ip_instance_id, 11729461e4cSJit Loon Lim uint32_t cmd_type, uint32_t cmd_opcode, uint32_t *args, 11829461e4cSJit Loon Lim unsigned int len) 11929461e4cSJit Loon Lim { 12029461e4cSJit Loon Lim unsigned int i; 12129461e4cSJit Loon Lim uint32_t status = 0; 12229461e4cSJit Loon Lim uint32_t cmd_req; 12329461e4cSJit Loon Lim uint32_t cmd_param_reg; 12429461e4cSJit Loon Lim 12529461e4cSJit Loon Lim cmd_target_ip_type = (cmd_target_ip_type & CMD_TARGET_IP_TYPE_MASK) << 12629461e4cSJit Loon Lim CMD_TARGET_IP_TYPE_OFFSET; 12729461e4cSJit Loon Lim cmd_target_ip_instance_id = (cmd_target_ip_instance_id & 12829461e4cSJit Loon Lim CMD_TARGET_IP_INSTANCE_ID_MASK) << 12929461e4cSJit Loon Lim CMD_TARGET_IP_INSTANCE_ID_OFFSET; 13029461e4cSJit Loon Lim cmd_type = (cmd_type & CMD_TYPE_MASK) << CMD_TYPE_OFFSET; 13129461e4cSJit Loon Lim cmd_opcode = (cmd_opcode & CMD_OPCODE_MASK) << CMD_OPCODE_OFFSET; 13229461e4cSJit Loon Lim cmd_req = cmd_target_ip_type | cmd_target_ip_instance_id | cmd_type | 13329461e4cSJit Loon Lim cmd_opcode; 13429461e4cSJit Loon Lim 13529461e4cSJit Loon Lim /* send mailbox request */ 13629461e4cSJit Loon Lim IOSSM_MB_WRITE(IO96B_CSR_REG(CMD_REQ), cmd_req); 13729461e4cSJit Loon Lim if (len != 0) { 13829461e4cSJit Loon Lim cmd_param_reg = CMD_REQ; 13929461e4cSJit Loon Lim for (i = 0; i < len; i++) { 14029461e4cSJit Loon Lim cmd_param_reg = cmd_param_reg - CMD_PARAM_OFFSET; 14129461e4cSJit Loon Lim IOSSM_MB_WRITE(IO96B_CSR_REG(cmd_param_reg), args[i]); 14229461e4cSJit Loon Lim } 14329461e4cSJit Loon Lim } 14429461e4cSJit Loon Lim 14529461e4cSJit Loon Lim status = iossm_mb_read_response(); 14629461e4cSJit Loon Lim if (status != 0) { 14729461e4cSJit Loon Lim return status; 14829461e4cSJit Loon Lim } 14929461e4cSJit Loon Lim 15029461e4cSJit Loon Lim return status; 15129461e4cSJit Loon Lim } 15229461e4cSJit Loon Lim 15329461e4cSJit Loon Lim int ddr_iossm_mailbox_cmd(uint32_t cmd_opcode) 15429461e4cSJit Loon Lim { 15529461e4cSJit Loon Lim // IOSSM 15629461e4cSJit Loon Lim uint32_t status = 0; 15729461e4cSJit Loon Lim unsigned int i = 0; 15829461e4cSJit Loon Lim uint32_t payload[IOSSM_CMD_MAX_WORD_SIZE] = {0U}; 15929461e4cSJit Loon Lim 16029461e4cSJit Loon Lim switch (cmd_opcode) { 16129461e4cSJit Loon Lim case CMD_INIT: 16229461e4cSJit Loon Lim status = iossm_mb_init(); 16329461e4cSJit Loon Lim break; 16429461e4cSJit Loon Lim 16529461e4cSJit Loon Lim case OPCODE_GET_MEM_INTF_INFO: 16629461e4cSJit Loon Lim status = iossm_mb_send(0, 0, MBOX_CMD_GET_SYS_INFO, 16729461e4cSJit Loon Lim OPCODE_GET_MEM_INTF_INFO, payload, i); 16829461e4cSJit Loon Lim break; 16929461e4cSJit Loon Lim 17029461e4cSJit Loon Lim case OPCODE_GET_MEM_TECHNOLOGY: 17129461e4cSJit Loon Lim status = iossm_mb_send(0, 0, MBOX_CMD_GET_MEM_INFO, 17229461e4cSJit Loon Lim OPCODE_GET_MEM_TECHNOLOGY, payload, i); 17329461e4cSJit Loon Lim break; 17429461e4cSJit Loon Lim 17529461e4cSJit Loon Lim case OPCODE_GET_MEM_WIDTH_INFO: 17629461e4cSJit Loon Lim status = iossm_mb_send(0, 0, MBOX_CMD_GET_MEM_INFO, 17729461e4cSJit Loon Lim OPCODE_GET_MEM_WIDTH_INFO, payload, i); 17829461e4cSJit Loon Lim break; 17929461e4cSJit Loon Lim 18029461e4cSJit Loon Lim case OPCODE_ECC_ENABLE_STATUS: 18129461e4cSJit Loon Lim status = iossm_mb_send(0, 0, 18229461e4cSJit Loon Lim MBOX_CMD_TRIG_CONTROLLER_OP, OPCODE_ECC_ENABLE_STATUS, 18329461e4cSJit Loon Lim payload, i); 18429461e4cSJit Loon Lim break; 18529461e4cSJit Loon Lim 18629461e4cSJit Loon Lim case OPCODE_ECC_INTERRUPT_MASK: 18729461e4cSJit Loon Lim // payload[i] = CMD_PARAM_0 [16:0]: ECC_INTERRUPT_MASK 18829461e4cSJit Loon Lim status = iossm_mb_send(0, 0, 18929461e4cSJit Loon Lim MBOX_CMD_TRIG_CONTROLLER_OP, OPCODE_ECC_INTERRUPT_MASK, 19029461e4cSJit Loon Lim payload, i); 19129461e4cSJit Loon Lim break; 19229461e4cSJit Loon Lim 19329461e4cSJit Loon Lim case OPCODE_ECC_SCRUB_MODE_0_START: 19429461e4cSJit Loon Lim // payload[i] = CMD_PARAM_0 [15:0]: ECC_SCRUB_INTERVAL 19529461e4cSJit Loon Lim //i++; 19629461e4cSJit Loon Lim // payload[i] = CMD_PARAM_1 [11:0]: ECC_SCRUB_LEN 19729461e4cSJit Loon Lim //i++; 19829461e4cSJit Loon Lim // payload[i] = CMD_PARAM_2 [0:0]: ECC_SCRUB_FULL_MEM 19929461e4cSJit Loon Lim //i++; 20029461e4cSJit Loon Lim // payload[i]= CMD_PARAM_3 [31:0]: ECC_SCRUB_START_ADDR [31:0] 20129461e4cSJit Loon Lim //i++; 20229461e4cSJit Loon Lim // payload[i] = CMD_PARAM_4 [5:0]: ECC_SCRUB_START_ADDR [36:32] 20329461e4cSJit Loon Lim //i++; 20429461e4cSJit Loon Lim // payload[i] = CMD_PARAM_5 [31:0]: ECC_SCRUB_END_ADDR [31:0] 20529461e4cSJit Loon Lim //i++; 20629461e4cSJit Loon Lim // payload[i] = CMD_PARAM_6 [5:0]: ECC_SCRUB_END_ADDR [36:32] 20729461e4cSJit Loon Lim //i++; 20829461e4cSJit Loon Lim status = iossm_mb_send(0, 0, 20929461e4cSJit Loon Lim MBOX_CMD_TRIG_CONTROLLER_OP, OPCODE_ECC_SCRUB_MODE_0_START, 21029461e4cSJit Loon Lim payload, i); 21129461e4cSJit Loon Lim break; 21229461e4cSJit Loon Lim 21329461e4cSJit Loon Lim case OPCODE_ECC_SCRUB_MODE_1_START: 21429461e4cSJit Loon Lim // payload[i] = CMD_PARAM_0 [15:0]: ECC_SCRUB_IDLE_CNT 21529461e4cSJit Loon Lim //i++; 21629461e4cSJit Loon Lim // payload[i] = CMD_PARAM_1 [11:0]: ECC_SCRUB_LEN 21729461e4cSJit Loon Lim //i++; 21829461e4cSJit Loon Lim // payload[i] = CMD_PARAM_2 [0:0]: ECC_SCRUB_FULL_MEM 21929461e4cSJit Loon Lim //i++; 22029461e4cSJit Loon Lim // payload[i] = CMD_PARAM_3 [31:0]: ECC_SCRUB_START_ADDR [31:0] 22129461e4cSJit Loon Lim //i++; 22229461e4cSJit Loon Lim // payload[i] = CMD_PARAM_4 [5:0]: ECC_SCRUB_START_ADDR [36:32] 22329461e4cSJit Loon Lim //i++; 22429461e4cSJit Loon Lim // payload[i] = CMD_PARAM_5 [31:0]: ECC_SCRUB_END_ADDR [31:0] 22529461e4cSJit Loon Lim //i++; 22629461e4cSJit Loon Lim // payload[i] = CMD_PARAM_6 [5:0]: ECC_SCRUB_END_ADDR [36:32] 22729461e4cSJit Loon Lim //i++; 22829461e4cSJit Loon Lim status = iossm_mb_send(0, 0, 22929461e4cSJit Loon Lim MBOX_CMD_TRIG_CONTROLLER_OP, OPCODE_ECC_SCRUB_MODE_1_START, 23029461e4cSJit Loon Lim payload, i); 23129461e4cSJit Loon Lim break; 23229461e4cSJit Loon Lim 23329461e4cSJit Loon Lim case OPCODE_BIST_RESULTS_STATUS: 23429461e4cSJit Loon Lim status = iossm_mb_send(0, 0, 23529461e4cSJit Loon Lim MBOX_CMD_TRIG_CONTROLLER_OP, OPCODE_BIST_RESULTS_STATUS, 23629461e4cSJit Loon Lim payload, i); 23729461e4cSJit Loon Lim break; 23829461e4cSJit Loon Lim 23929461e4cSJit Loon Lim case OPCODE_BIST_MEM_INIT_START: 24029461e4cSJit Loon Lim status = iossm_mb_send(0, 0, 24129461e4cSJit Loon Lim MBOX_CMD_TRIG_CONTROLLER_OP, OPCODE_BIST_MEM_INIT_START, 24229461e4cSJit Loon Lim payload, i); 24329461e4cSJit Loon Lim break; 24429461e4cSJit Loon Lim 24529461e4cSJit Loon Lim case OPCODE_TRIG_MEM_CAL: 24629461e4cSJit Loon Lim status = iossm_mb_send(0, 0, MBOX_CMD_TRIG_MEM_CAL_OP, 24729461e4cSJit Loon Lim OPCODE_TRIG_MEM_CAL, payload, i); 24829461e4cSJit Loon Lim break; 24929461e4cSJit Loon Lim 25029461e4cSJit Loon Lim default: 25129461e4cSJit Loon Lim break; 25229461e4cSJit Loon Lim } 25329461e4cSJit Loon Lim 25429461e4cSJit Loon Lim if (status == -EPERM) { 25529461e4cSJit Loon Lim assert(status); 25629461e4cSJit Loon Lim } 25729461e4cSJit Loon Lim 25829461e4cSJit Loon Lim return status; 25929461e4cSJit Loon Lim } 26029461e4cSJit Loon Lim 26129461e4cSJit Loon Lim int ddr_config_handoff(handoff *hoff_ptr) 26229461e4cSJit Loon Lim { 26329461e4cSJit Loon Lim /* Populate DDR handoff data */ 26429461e4cSJit Loon Lim /* TODO: To add in DDR handoff configuration once available */ 26529461e4cSJit Loon Lim return 0; 26629461e4cSJit Loon Lim } 26729461e4cSJit Loon Lim 26829461e4cSJit Loon Lim // DDR firewall and non secure access 26929461e4cSJit Loon Lim void ddr_enable_ns_access(void) 27029461e4cSJit Loon Lim { 27129461e4cSJit Loon Lim /* Please set the ddr non secure registers accordingly */ 27229461e4cSJit Loon Lim 27329461e4cSJit Loon Lim mmio_setbits_32(CCU_REG(DMI0_DMIUSMCTCR), 27429461e4cSJit Loon Lim CCU_DMI_ALLOCEN | CCU_DMI_LOOKUPEN); 27529461e4cSJit Loon Lim mmio_setbits_32(CCU_REG(DMI1_DMIUSMCTCR), 27629461e4cSJit Loon Lim CCU_DMI_ALLOCEN | CCU_DMI_LOOKUPEN); 27729461e4cSJit Loon Lim 27829461e4cSJit Loon Lim /* TODO: To add in CCU NCORE OCRAM bypass mask for non secure registers */ 27929461e4cSJit Loon Lim NOTICE("DDR non secure configured\n"); 28029461e4cSJit Loon Lim } 28129461e4cSJit Loon Lim 28229461e4cSJit Loon Lim void ddr_enable_firewall(void) 28329461e4cSJit Loon Lim { 28429461e4cSJit Loon Lim /* Please set the ddr firewall registers accordingly */ 28529461e4cSJit Loon Lim /* TODO: To add in CCU NCORE OCRAM bypass mask for firewall registers */ 28629461e4cSJit Loon Lim NOTICE("DDR firewall enabled\n"); 28729461e4cSJit Loon Lim } 28829461e4cSJit Loon Lim 28929461e4cSJit Loon Lim bool is_ddr_init_in_progress(void) 29029461e4cSJit Loon Lim { 29129461e4cSJit Loon Lim uint32_t reg = mmio_read_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_POR_0)); 29229461e4cSJit Loon Lim 29329461e4cSJit Loon Lim if (reg & SOCFPGA_SYSMGR_BOOT_SCRATCH_POR_0_MASK) { 29429461e4cSJit Loon Lim return true; 29529461e4cSJit Loon Lim } 29629461e4cSJit Loon Lim return false; 29729461e4cSJit Loon Lim } 29829461e4cSJit Loon Lim 29929461e4cSJit Loon Lim int ddr_init(void) 30029461e4cSJit Loon Lim { 30129461e4cSJit Loon Lim // DDR driver initialization 30229461e4cSJit Loon Lim int status = -EPERM; 30329461e4cSJit Loon Lim uint32_t cmd_opcode = 0; 30429461e4cSJit Loon Lim 30529461e4cSJit Loon Lim // Check and set Boot Scratch Register 30629461e4cSJit Loon Lim if (is_ddr_init_in_progress()) { 30729461e4cSJit Loon Lim return status; 30829461e4cSJit Loon Lim } 30929461e4cSJit Loon Lim mmio_write_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_POR_0), 0x01); 31029461e4cSJit Loon Lim 31129461e4cSJit Loon Lim // Populate DDR handoff data 31229461e4cSJit Loon Lim handoff reverse_handoff_ptr; 31329461e4cSJit Loon Lim 31429461e4cSJit Loon Lim if (!socfpga_get_handoff(&reverse_handoff_ptr)) { 31529461e4cSJit Loon Lim assert(status); 31629461e4cSJit Loon Lim } 31729461e4cSJit Loon Lim status = ddr_config_handoff(&reverse_handoff_ptr); 31829461e4cSJit Loon Lim if (status == -EPERM) { 31929461e4cSJit Loon Lim assert(status); 32029461e4cSJit Loon Lim } 32129461e4cSJit Loon Lim 32229461e4cSJit Loon Lim // CCU and firewall setup 32329461e4cSJit Loon Lim ddr_enable_ns_access(); 32429461e4cSJit Loon Lim ddr_enable_firewall(); 32529461e4cSJit Loon Lim 32629461e4cSJit Loon Lim // DDR calibration check 32729461e4cSJit Loon Lim status = ddr_calibration_check(); 32829461e4cSJit Loon Lim if (status == -EPERM) { 32929461e4cSJit Loon Lim assert(status); 33029461e4cSJit Loon Lim } 33129461e4cSJit Loon Lim 33229461e4cSJit Loon Lim // DDR mailbox command 33329461e4cSJit Loon Lim status = ddr_iossm_mailbox_cmd(cmd_opcode); 33429461e4cSJit Loon Lim if (status != 0) { 33529461e4cSJit Loon Lim assert(status); 33629461e4cSJit Loon Lim } 33729461e4cSJit Loon Lim 33829461e4cSJit Loon Lim // Check and set Boot Scratch Register 33929461e4cSJit Loon Lim mmio_write_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_POR_0), 0x00); 34029461e4cSJit Loon Lim 34129461e4cSJit Loon Lim NOTICE("DDR init successfully\n"); 34229461e4cSJit Loon Lim return status; 34329461e4cSJit Loon Lim } 344*68bb3e83SJit Loon Lim 345*68bb3e83SJit Loon Lim int ddr_config_scrubber(phys_addr_t umctl2_base, enum ddr_type umctl2_type) 346*68bb3e83SJit Loon Lim { 347*68bb3e83SJit Loon Lim uint32_t temp[9] = {0}; 348*68bb3e83SJit Loon Lim int ret = 0; 349*68bb3e83SJit Loon Lim 350*68bb3e83SJit Loon Lim /* Write default value to prevent scrubber stop due to lower power */ 351*68bb3e83SJit Loon Lim mmio_write_32(0, umctl2_base + DDR4_PWRCTL_OFFSET); 352*68bb3e83SJit Loon Lim 353*68bb3e83SJit Loon Lim /* To backup user configurations in temp array */ 354*68bb3e83SJit Loon Lim temp[0] = mmio_read_32(umctl2_base + DDR4_SBRCTL_OFFSET); 355*68bb3e83SJit Loon Lim temp[1] = mmio_read_32(umctl2_base + DDR4_SBRWDATA0_OFFSET); 356*68bb3e83SJit Loon Lim temp[2] = mmio_read_32(umctl2_base + DDR4_SBRSTART0_OFFSET); 357*68bb3e83SJit Loon Lim if (umctl2_type == DDR_TYPE_DDR4) { 358*68bb3e83SJit Loon Lim temp[3] = mmio_read_32(umctl2_base + DDR4_SBRWDATA1_OFFSET); 359*68bb3e83SJit Loon Lim temp[4] = mmio_read_32(umctl2_base + DDR4_SBRSTART1_OFFSET); 360*68bb3e83SJit Loon Lim } 361*68bb3e83SJit Loon Lim temp[5] = mmio_read_32(umctl2_base + DDR4_SBRRANGE0_OFFSET); 362*68bb3e83SJit Loon Lim temp[6] = mmio_read_32(umctl2_base + DDR4_SBRRANGE1_OFFSET); 363*68bb3e83SJit Loon Lim temp[7] = mmio_read_32(umctl2_base + DDR4_ECCCFG0_OFFSET); 364*68bb3e83SJit Loon Lim temp[8] = mmio_read_32(umctl2_base + DDR4_ECCCFG1_OFFSET); 365*68bb3e83SJit Loon Lim 366*68bb3e83SJit Loon Lim if (umctl2_type != DDR_TYPE_DDR4) { 367*68bb3e83SJit Loon Lim /* Lock ECC region, ensure this regions is not being accessed */ 368*68bb3e83SJit Loon Lim mmio_setbits_32(umctl2_base + DDR4_ECCCFG1_OFFSET, 369*68bb3e83SJit Loon Lim LPDDR4_ECCCFG1_ECC_REGIONS_PARITY_LOCK); 370*68bb3e83SJit Loon Lim } 371*68bb3e83SJit Loon Lim /* Disable input traffic per port */ 372*68bb3e83SJit Loon Lim mmio_clrbits_32(umctl2_base + DDR4_PCTRL0_OFFSET, DDR4_PCTRL0_PORT_EN); 373*68bb3e83SJit Loon Lim /* Disables scrubber */ 374*68bb3e83SJit Loon Lim mmio_clrbits_32(umctl2_base + DDR4_SBRCTL_OFFSET, DDR4_SBRCTL_SCRUB_EN); 375*68bb3e83SJit Loon Lim /* Polling all scrub writes data have been sent */ 376*68bb3e83SJit Loon Lim ret = poll_idle_status((umctl2_base + DDR4_SBRSTAT_OFFSET), 377*68bb3e83SJit Loon Lim DDR4_SBRSTAT_SCRUB_BUSY, true, 5000); 378*68bb3e83SJit Loon Lim 379*68bb3e83SJit Loon Lim if (ret) { 380*68bb3e83SJit Loon Lim INFO("%s: Timeout while waiting for", __func__); 381*68bb3e83SJit Loon Lim INFO(" sending all scrub data\n"); 382*68bb3e83SJit Loon Lim return ret; 383*68bb3e83SJit Loon Lim } 384*68bb3e83SJit Loon Lim 385*68bb3e83SJit Loon Lim /* LPDDR4 supports inline ECC only */ 386*68bb3e83SJit Loon Lim if (umctl2_type != DDR_TYPE_DDR4) { 387*68bb3e83SJit Loon Lim /* 388*68bb3e83SJit Loon Lim * Setting all regions for protected, this is required for 389*68bb3e83SJit Loon Lim * srubber to init whole LPDDR4 expect ECC region 390*68bb3e83SJit Loon Lim */ 391*68bb3e83SJit Loon Lim mmio_write_32(((ONE_EIGHT << 392*68bb3e83SJit Loon Lim LPDDR4_ECCCFG0_ECC_REGION_MAP_GRANU_SHIFT) | 393*68bb3e83SJit Loon Lim (ALL_PROTECTED << LPDDR4_ECCCFG0_ECC_REGION_MAP_SHIFT)), 394*68bb3e83SJit Loon Lim umctl2_base + DDR4_ECCCFG0_OFFSET); 395*68bb3e83SJit Loon Lim } 396*68bb3e83SJit Loon Lim 397*68bb3e83SJit Loon Lim /* Scrub_burst = 1, scrub_mode = 1(performs writes) */ 398*68bb3e83SJit Loon Lim mmio_write_32(DDR4_SBRCTL_SCRUB_BURST_1 | DDR4_SBRCTL_SCRUB_WRITE, 399*68bb3e83SJit Loon Lim umctl2_base + DDR4_SBRCTL_OFFSET); 400*68bb3e83SJit Loon Lim 401*68bb3e83SJit Loon Lim /* Wipe DDR content after calibration */ 402*68bb3e83SJit Loon Lim ret = ddr_zerofill_scrubber(umctl2_base, umctl2_type); 403*68bb3e83SJit Loon Lim if (ret) { 404*68bb3e83SJit Loon Lim ERROR("Failed to clear DDR content\n"); 405*68bb3e83SJit Loon Lim } 406*68bb3e83SJit Loon Lim 407*68bb3e83SJit Loon Lim /* Polling all scrub writes data have been sent */ 408*68bb3e83SJit Loon Lim ret = poll_idle_status((umctl2_base + DDR4_SBRSTAT_OFFSET), 409*68bb3e83SJit Loon Lim DDR4_SBRSTAT_SCRUB_BUSY, true, 5000); 410*68bb3e83SJit Loon Lim if (ret) { 411*68bb3e83SJit Loon Lim INFO("%s: Timeout while waiting for", __func__); 412*68bb3e83SJit Loon Lim INFO(" sending all scrub data\n"); 413*68bb3e83SJit Loon Lim return ret; 414*68bb3e83SJit Loon Lim } 415*68bb3e83SJit Loon Lim 416*68bb3e83SJit Loon Lim /* Disables scrubber */ 417*68bb3e83SJit Loon Lim mmio_clrbits_32(umctl2_base + DDR4_SBRCTL_OFFSET, DDR4_SBRCTL_SCRUB_EN); 418*68bb3e83SJit Loon Lim 419*68bb3e83SJit Loon Lim /* Restore user configurations */ 420*68bb3e83SJit Loon Lim mmio_write_32(temp[0], umctl2_base + DDR4_SBRCTL_OFFSET); 421*68bb3e83SJit Loon Lim mmio_write_32(temp[1], umctl2_base + DDR4_SBRWDATA0_OFFSET); 422*68bb3e83SJit Loon Lim mmio_write_32(temp[2], umctl2_base + DDR4_SBRSTART0_OFFSET); 423*68bb3e83SJit Loon Lim if (umctl2_type == DDR_TYPE_DDR4) { 424*68bb3e83SJit Loon Lim mmio_write_32(temp[3], umctl2_base + DDR4_SBRWDATA1_OFFSET); 425*68bb3e83SJit Loon Lim mmio_write_32(temp[4], umctl2_base + DDR4_SBRSTART1_OFFSET); 426*68bb3e83SJit Loon Lim } 427*68bb3e83SJit Loon Lim mmio_write_32(temp[5], umctl2_base + DDR4_SBRRANGE0_OFFSET); 428*68bb3e83SJit Loon Lim mmio_write_32(temp[6], umctl2_base + DDR4_SBRRANGE1_OFFSET); 429*68bb3e83SJit Loon Lim mmio_write_32(temp[7], umctl2_base + DDR4_ECCCFG0_OFFSET); 430*68bb3e83SJit Loon Lim mmio_write_32(temp[8], umctl2_base + DDR4_ECCCFG1_OFFSET); 431*68bb3e83SJit Loon Lim 432*68bb3e83SJit Loon Lim /* Enables ECC scrub on scrubber */ 433*68bb3e83SJit Loon Lim if (!(mmio_read_32(umctl2_base + DDR4_SBRCTL_OFFSET) & DDR4_SBRCTL_SCRUB_WRITE)) { 434*68bb3e83SJit Loon Lim /* Enables scrubber */ 435*68bb3e83SJit Loon Lim mmio_setbits_32(umctl2_base + DDR4_SBRCTL_OFFSET, DDR4_SBRCTL_SCRUB_EN); 436*68bb3e83SJit Loon Lim } 437*68bb3e83SJit Loon Lim 438*68bb3e83SJit Loon Lim return 0; 439*68bb3e83SJit Loon Lim } 440*68bb3e83SJit Loon Lim 441*68bb3e83SJit Loon Lim int ddr_zerofill_scrubber(phys_addr_t umctl2_base, enum ddr_type umctl2_type) 442*68bb3e83SJit Loon Lim { 443*68bb3e83SJit Loon Lim int ret = 0; 444*68bb3e83SJit Loon Lim 445*68bb3e83SJit Loon Lim /* Zeroing whole DDR */ 446*68bb3e83SJit Loon Lim mmio_write_32(0, umctl2_base + DDR4_SBRWDATA0_OFFSET); 447*68bb3e83SJit Loon Lim mmio_write_32(0, umctl2_base + DDR4_SBRSTART0_OFFSET); 448*68bb3e83SJit Loon Lim if (umctl2_type == DDR_TYPE_DDR4) { 449*68bb3e83SJit Loon Lim mmio_write_32(0, umctl2_base + DDR4_SBRWDATA1_OFFSET); 450*68bb3e83SJit Loon Lim mmio_write_32(0, umctl2_base + DDR4_SBRSTART1_OFFSET); 451*68bb3e83SJit Loon Lim } 452*68bb3e83SJit Loon Lim mmio_write_32(0, umctl2_base + DDR4_SBRRANGE0_OFFSET); 453*68bb3e83SJit Loon Lim mmio_write_32(0, umctl2_base + DDR4_SBRRANGE1_OFFSET); 454*68bb3e83SJit Loon Lim 455*68bb3e83SJit Loon Lim NOTICE("Enabling scrubber (zeroing whole DDR) ...\n"); 456*68bb3e83SJit Loon Lim 457*68bb3e83SJit Loon Lim /* Enables scrubber */ 458*68bb3e83SJit Loon Lim mmio_setbits_32(umctl2_base + DDR4_SBRCTL_OFFSET, DDR4_SBRCTL_SCRUB_EN); 459*68bb3e83SJit Loon Lim /* Polling all scrub writes commands have been sent */ 460*68bb3e83SJit Loon Lim ret = poll_idle_status((umctl2_base + DDR4_SBRSTAT_OFFSET), 461*68bb3e83SJit Loon Lim DDR4_SBRSTAT_SCRUB_DONE, true, 5000); 462*68bb3e83SJit Loon Lim if (ret) { 463*68bb3e83SJit Loon Lim INFO("%s: Timeout while waiting for", __func__); 464*68bb3e83SJit Loon Lim INFO(" sending all scrub commands\n"); 465*68bb3e83SJit Loon Lim return ret; 466*68bb3e83SJit Loon Lim } 467*68bb3e83SJit Loon Lim 468*68bb3e83SJit Loon Lim return 0; 469*68bb3e83SJit Loon Lim } 470*68bb3e83SJit Loon Lim 471*68bb3e83SJit Loon Lim int poll_idle_status(uint32_t addr, uint32_t mask, uint32_t match, uint32_t delay_ms) 472*68bb3e83SJit Loon Lim { 473*68bb3e83SJit Loon Lim int time_out = delay_ms; 474*68bb3e83SJit Loon Lim 475*68bb3e83SJit Loon Lim while (time_out-- > 0) { 476*68bb3e83SJit Loon Lim 477*68bb3e83SJit Loon Lim if ((mmio_read_32(addr) & mask) == match) { 478*68bb3e83SJit Loon Lim return 0; 479*68bb3e83SJit Loon Lim } 480*68bb3e83SJit Loon Lim udelay(1000); 481*68bb3e83SJit Loon Lim } 482*68bb3e83SJit Loon Lim return -ETIMEDOUT; 483*68bb3e83SJit Loon Lim } 484