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
ddr_calibration_check(void)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
iossm_mb_init(void)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
wait_respond(uint16_t timeout)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
iossm_mb_read_response(void)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
iossm_mb_send(uint32_t cmd_target_ip_type,uint32_t cmd_target_ip_instance_id,uint32_t cmd_type,uint32_t cmd_opcode,uint32_t * args,unsigned int len)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
ddr_iossm_mailbox_cmd(uint32_t cmd_opcode)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
ddr_config_handoff(handoff * hoff_ptr)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
ddr_enable_ns_access(void)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
ddr_enable_firewall(void)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
is_ddr_init_in_progress(void)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
ddr_init(void)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
ddr_config_scrubber(phys_addr_t umctl2_base,enum ddr_type umctl2_type)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
ddr_zerofill_scrubber(phys_addr_t umctl2_base,enum ddr_type umctl2_type)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
poll_idle_status(uint32_t addr,uint32_t mask,uint32_t match,uint32_t delay_ms)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