1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2022, Intel Corporation. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <assert.h> 8*91f16700Schasinglulu #include <errno.h> 9*91f16700Schasinglulu #include <common/debug.h> 10*91f16700Schasinglulu #include "ddr.h" 11*91f16700Schasinglulu #include <lib/mmio.h> 12*91f16700Schasinglulu #include "socfpga_handoff.h" 13*91f16700Schasinglulu 14*91f16700Schasinglulu int ddr_calibration_check(void) 15*91f16700Schasinglulu { 16*91f16700Schasinglulu // DDR calibration check 17*91f16700Schasinglulu int status = 0; 18*91f16700Schasinglulu uint32_t u32data_read = 0; 19*91f16700Schasinglulu 20*91f16700Schasinglulu NOTICE("DDR: Access address 0x%x:...\n", IO96B_0_REG_BASE); 21*91f16700Schasinglulu u32data_read = mmio_read_32(IO96B_0_REG_BASE); 22*91f16700Schasinglulu NOTICE("DDR: Access address 0x%x: read 0x%04x\n", IO96B_0_REG_BASE, u32data_read); 23*91f16700Schasinglulu 24*91f16700Schasinglulu if (u32data_read == -EPERM) { 25*91f16700Schasinglulu status = -EPERM; 26*91f16700Schasinglulu assert(u32data_read); 27*91f16700Schasinglulu } 28*91f16700Schasinglulu 29*91f16700Schasinglulu u32data_read = 0x0; 30*91f16700Schasinglulu NOTICE("DDR: Access address 0x%x: ...\n", IO96B_1_REG_BASE); 31*91f16700Schasinglulu u32data_read = mmio_read_32(IO96B_1_REG_BASE); 32*91f16700Schasinglulu NOTICE("DDR: Access address 0x%x: read 0x%04x\n", IO96B_1_REG_BASE, u32data_read); 33*91f16700Schasinglulu 34*91f16700Schasinglulu if (u32data_read == -EPERM) { 35*91f16700Schasinglulu status = -EPERM; 36*91f16700Schasinglulu assert(u32data_read); 37*91f16700Schasinglulu } 38*91f16700Schasinglulu 39*91f16700Schasinglulu return status; 40*91f16700Schasinglulu } 41*91f16700Schasinglulu 42*91f16700Schasinglulu int iossm_mb_init(void) 43*91f16700Schasinglulu { 44*91f16700Schasinglulu // int status; 45*91f16700Schasinglulu 46*91f16700Schasinglulu // Update according to IOSSM mailbox spec 47*91f16700Schasinglulu 48*91f16700Schasinglulu // if (status) { 49*91f16700Schasinglulu // return status; 50*91f16700Schasinglulu // } 51*91f16700Schasinglulu 52*91f16700Schasinglulu return 0; 53*91f16700Schasinglulu } 54*91f16700Schasinglulu 55*91f16700Schasinglulu int wait_respond(uint16_t timeout) 56*91f16700Schasinglulu { 57*91f16700Schasinglulu uint32_t status = 0; 58*91f16700Schasinglulu uint32_t count = 0; 59*91f16700Schasinglulu uint32_t data = 0; 60*91f16700Schasinglulu 61*91f16700Schasinglulu /* Wait status command response ready */ 62*91f16700Schasinglulu do { 63*91f16700Schasinglulu data = mmio_read_32(IO96B_CSR_REG(CMD_RESPONSE_STATUS)); 64*91f16700Schasinglulu count++; 65*91f16700Schasinglulu if (count >= timeout) { 66*91f16700Schasinglulu return -ETIMEDOUT; 67*91f16700Schasinglulu } 68*91f16700Schasinglulu 69*91f16700Schasinglulu } while (STATUS_COMMAND_RESPONSE(data) != STATUS_COMMAND_RESPONSE_READY); 70*91f16700Schasinglulu 71*91f16700Schasinglulu status = (data & STATUS_GENERAL_ERROR_MASK) >> STATUS_GENERAL_ERROR_OFFSET; 72*91f16700Schasinglulu if (status != 0) { 73*91f16700Schasinglulu return status; 74*91f16700Schasinglulu } 75*91f16700Schasinglulu 76*91f16700Schasinglulu status = (data & STATUS_CMD_RESPONSE_ERROR_MASK) >> STATUS_CMD_RESPONSE_ERROR_OFFSET; 77*91f16700Schasinglulu if (status != 0) { 78*91f16700Schasinglulu return status; 79*91f16700Schasinglulu } 80*91f16700Schasinglulu 81*91f16700Schasinglulu return status; 82*91f16700Schasinglulu } 83*91f16700Schasinglulu 84*91f16700Schasinglulu int iossm_mb_read_response(void) 85*91f16700Schasinglulu { 86*91f16700Schasinglulu uint32_t status = 0; 87*91f16700Schasinglulu unsigned int i; 88*91f16700Schasinglulu uint32_t resp_data[IOSSM_RESP_MAX_WORD_SIZE]; 89*91f16700Schasinglulu uint32_t resp_param_reg; 90*91f16700Schasinglulu 91*91f16700Schasinglulu // Check STATUS_CMD_RESPONSE_DATA_PTR_VALID in 92*91f16700Schasinglulu // STATUS_COMMAND_RESPONSE to ensure data pointer response 93*91f16700Schasinglulu 94*91f16700Schasinglulu /* Read CMD_RESPONSE_STATUS and CMD_RESPONSE_DATA_* */ 95*91f16700Schasinglulu resp_data[0] = mmio_read_32(IO96B_CSR_REG(CMD_RESPONSE_STATUS)); 96*91f16700Schasinglulu resp_data[0] = (resp_data[0] & CMD_RESPONSE_DATA_SHORT_MASK) >> 97*91f16700Schasinglulu CMD_RESPONSE_DATA_SHORT_OFFSET; 98*91f16700Schasinglulu resp_param_reg = CMD_RESPONSE_STATUS; 99*91f16700Schasinglulu for (i = 1; i < IOSSM_RESP_MAX_WORD_SIZE; i++) { 100*91f16700Schasinglulu resp_param_reg = resp_param_reg - CMD_RESPONSE_OFFSET; 101*91f16700Schasinglulu resp_data[i] = mmio_read_32(IO96B_CSR_REG(resp_param_reg)); 102*91f16700Schasinglulu } 103*91f16700Schasinglulu 104*91f16700Schasinglulu /* Wait for STATUS_COMMAND_RESPONSE_READY*/ 105*91f16700Schasinglulu status = wait_respond(1000); 106*91f16700Schasinglulu 107*91f16700Schasinglulu /* Read CMD_RESPONSE_STATUS and CMD_RESPONSE_DATA_* */ 108*91f16700Schasinglulu mmio_setbits_32(STATUS_COMMAND_RESPONSE(IO96B_CSR_REG( 109*91f16700Schasinglulu CMD_RESPONSE_STATUS)), 110*91f16700Schasinglulu STATUS_COMMAND_RESPONSE_READY_CLEAR); 111*91f16700Schasinglulu 112*91f16700Schasinglulu return status; 113*91f16700Schasinglulu } 114*91f16700Schasinglulu 115*91f16700Schasinglulu int iossm_mb_send(uint32_t cmd_target_ip_type, uint32_t cmd_target_ip_instance_id, 116*91f16700Schasinglulu uint32_t cmd_type, uint32_t cmd_opcode, uint32_t *args, 117*91f16700Schasinglulu unsigned int len) 118*91f16700Schasinglulu { 119*91f16700Schasinglulu unsigned int i; 120*91f16700Schasinglulu uint32_t status = 0; 121*91f16700Schasinglulu uint32_t cmd_req; 122*91f16700Schasinglulu uint32_t cmd_param_reg; 123*91f16700Schasinglulu 124*91f16700Schasinglulu cmd_target_ip_type = (cmd_target_ip_type & CMD_TARGET_IP_TYPE_MASK) << 125*91f16700Schasinglulu CMD_TARGET_IP_TYPE_OFFSET; 126*91f16700Schasinglulu cmd_target_ip_instance_id = (cmd_target_ip_instance_id & 127*91f16700Schasinglulu CMD_TARGET_IP_INSTANCE_ID_MASK) << 128*91f16700Schasinglulu CMD_TARGET_IP_INSTANCE_ID_OFFSET; 129*91f16700Schasinglulu cmd_type = (cmd_type & CMD_TYPE_MASK) << CMD_TYPE_OFFSET; 130*91f16700Schasinglulu cmd_opcode = (cmd_opcode & CMD_OPCODE_MASK) << CMD_OPCODE_OFFSET; 131*91f16700Schasinglulu cmd_req = cmd_target_ip_type | cmd_target_ip_instance_id | cmd_type | 132*91f16700Schasinglulu cmd_opcode; 133*91f16700Schasinglulu 134*91f16700Schasinglulu /* send mailbox request */ 135*91f16700Schasinglulu IOSSM_MB_WRITE(IO96B_CSR_REG(CMD_REQ), cmd_req); 136*91f16700Schasinglulu if (len != 0) { 137*91f16700Schasinglulu cmd_param_reg = CMD_REQ; 138*91f16700Schasinglulu for (i = 0; i < len; i++) { 139*91f16700Schasinglulu cmd_param_reg = cmd_param_reg - CMD_PARAM_OFFSET; 140*91f16700Schasinglulu IOSSM_MB_WRITE(IO96B_CSR_REG(cmd_param_reg), args[i]); 141*91f16700Schasinglulu } 142*91f16700Schasinglulu } 143*91f16700Schasinglulu 144*91f16700Schasinglulu status = iossm_mb_read_response(); 145*91f16700Schasinglulu if (status != 0) { 146*91f16700Schasinglulu return status; 147*91f16700Schasinglulu } 148*91f16700Schasinglulu 149*91f16700Schasinglulu return status; 150*91f16700Schasinglulu } 151*91f16700Schasinglulu 152*91f16700Schasinglulu int ddr_iossm_mailbox_cmd(uint32_t cmd_opcode) 153*91f16700Schasinglulu { 154*91f16700Schasinglulu // IOSSM 155*91f16700Schasinglulu uint32_t status = 0; 156*91f16700Schasinglulu unsigned int i = 0; 157*91f16700Schasinglulu uint32_t payload[IOSSM_CMD_MAX_WORD_SIZE] = {0U}; 158*91f16700Schasinglulu 159*91f16700Schasinglulu switch (cmd_opcode) { 160*91f16700Schasinglulu case CMD_INIT: 161*91f16700Schasinglulu status = iossm_mb_init(); 162*91f16700Schasinglulu break; 163*91f16700Schasinglulu 164*91f16700Schasinglulu case OPCODE_GET_MEM_INTF_INFO: 165*91f16700Schasinglulu status = iossm_mb_send(0, 0, MBOX_CMD_GET_SYS_INFO, 166*91f16700Schasinglulu OPCODE_GET_MEM_INTF_INFO, payload, i); 167*91f16700Schasinglulu break; 168*91f16700Schasinglulu 169*91f16700Schasinglulu case OPCODE_GET_MEM_TECHNOLOGY: 170*91f16700Schasinglulu status = iossm_mb_send(0, 0, MBOX_CMD_GET_MEM_INFO, 171*91f16700Schasinglulu OPCODE_GET_MEM_TECHNOLOGY, payload, i); 172*91f16700Schasinglulu break; 173*91f16700Schasinglulu 174*91f16700Schasinglulu case OPCODE_GET_MEM_WIDTH_INFO: 175*91f16700Schasinglulu status = iossm_mb_send(0, 0, MBOX_CMD_GET_MEM_INFO, 176*91f16700Schasinglulu OPCODE_GET_MEM_WIDTH_INFO, payload, i); 177*91f16700Schasinglulu break; 178*91f16700Schasinglulu 179*91f16700Schasinglulu case OPCODE_ECC_ENABLE_STATUS: 180*91f16700Schasinglulu status = iossm_mb_send(0, 0, 181*91f16700Schasinglulu MBOX_CMD_TRIG_CONTROLLER_OP, OPCODE_ECC_ENABLE_STATUS, 182*91f16700Schasinglulu payload, i); 183*91f16700Schasinglulu break; 184*91f16700Schasinglulu 185*91f16700Schasinglulu case OPCODE_ECC_INTERRUPT_MASK: 186*91f16700Schasinglulu // payload[i] = CMD_PARAM_0 [16:0]: ECC_INTERRUPT_MASK 187*91f16700Schasinglulu status = iossm_mb_send(0, 0, 188*91f16700Schasinglulu MBOX_CMD_TRIG_CONTROLLER_OP, OPCODE_ECC_INTERRUPT_MASK, 189*91f16700Schasinglulu payload, i); 190*91f16700Schasinglulu break; 191*91f16700Schasinglulu 192*91f16700Schasinglulu case OPCODE_ECC_SCRUB_MODE_0_START: 193*91f16700Schasinglulu // payload[i] = CMD_PARAM_0 [15:0]: ECC_SCRUB_INTERVAL 194*91f16700Schasinglulu //i++; 195*91f16700Schasinglulu // payload[i] = CMD_PARAM_1 [11:0]: ECC_SCRUB_LEN 196*91f16700Schasinglulu //i++; 197*91f16700Schasinglulu // payload[i] = CMD_PARAM_2 [0:0]: ECC_SCRUB_FULL_MEM 198*91f16700Schasinglulu //i++; 199*91f16700Schasinglulu // payload[i]= CMD_PARAM_3 [31:0]: ECC_SCRUB_START_ADDR [31:0] 200*91f16700Schasinglulu //i++; 201*91f16700Schasinglulu // payload[i] = CMD_PARAM_4 [5:0]: ECC_SCRUB_START_ADDR [36:32] 202*91f16700Schasinglulu //i++; 203*91f16700Schasinglulu // payload[i] = CMD_PARAM_5 [31:0]: ECC_SCRUB_END_ADDR [31:0] 204*91f16700Schasinglulu //i++; 205*91f16700Schasinglulu // payload[i] = CMD_PARAM_6 [5:0]: ECC_SCRUB_END_ADDR [36:32] 206*91f16700Schasinglulu //i++; 207*91f16700Schasinglulu status = iossm_mb_send(0, 0, 208*91f16700Schasinglulu MBOX_CMD_TRIG_CONTROLLER_OP, OPCODE_ECC_SCRUB_MODE_0_START, 209*91f16700Schasinglulu payload, i); 210*91f16700Schasinglulu break; 211*91f16700Schasinglulu 212*91f16700Schasinglulu case OPCODE_ECC_SCRUB_MODE_1_START: 213*91f16700Schasinglulu // payload[i] = CMD_PARAM_0 [15:0]: ECC_SCRUB_IDLE_CNT 214*91f16700Schasinglulu //i++; 215*91f16700Schasinglulu // payload[i] = CMD_PARAM_1 [11:0]: ECC_SCRUB_LEN 216*91f16700Schasinglulu //i++; 217*91f16700Schasinglulu // payload[i] = CMD_PARAM_2 [0:0]: ECC_SCRUB_FULL_MEM 218*91f16700Schasinglulu //i++; 219*91f16700Schasinglulu // payload[i] = CMD_PARAM_3 [31:0]: ECC_SCRUB_START_ADDR [31:0] 220*91f16700Schasinglulu //i++; 221*91f16700Schasinglulu // payload[i] = CMD_PARAM_4 [5:0]: ECC_SCRUB_START_ADDR [36:32] 222*91f16700Schasinglulu //i++; 223*91f16700Schasinglulu // payload[i] = CMD_PARAM_5 [31:0]: ECC_SCRUB_END_ADDR [31:0] 224*91f16700Schasinglulu //i++; 225*91f16700Schasinglulu // payload[i] = CMD_PARAM_6 [5:0]: ECC_SCRUB_END_ADDR [36:32] 226*91f16700Schasinglulu //i++; 227*91f16700Schasinglulu status = iossm_mb_send(0, 0, 228*91f16700Schasinglulu MBOX_CMD_TRIG_CONTROLLER_OP, OPCODE_ECC_SCRUB_MODE_1_START, 229*91f16700Schasinglulu payload, i); 230*91f16700Schasinglulu break; 231*91f16700Schasinglulu 232*91f16700Schasinglulu case OPCODE_BIST_RESULTS_STATUS: 233*91f16700Schasinglulu status = iossm_mb_send(0, 0, 234*91f16700Schasinglulu MBOX_CMD_TRIG_CONTROLLER_OP, OPCODE_BIST_RESULTS_STATUS, 235*91f16700Schasinglulu payload, i); 236*91f16700Schasinglulu break; 237*91f16700Schasinglulu 238*91f16700Schasinglulu case OPCODE_BIST_MEM_INIT_START: 239*91f16700Schasinglulu status = iossm_mb_send(0, 0, 240*91f16700Schasinglulu MBOX_CMD_TRIG_CONTROLLER_OP, OPCODE_BIST_MEM_INIT_START, 241*91f16700Schasinglulu payload, i); 242*91f16700Schasinglulu break; 243*91f16700Schasinglulu 244*91f16700Schasinglulu case OPCODE_TRIG_MEM_CAL: 245*91f16700Schasinglulu status = iossm_mb_send(0, 0, MBOX_CMD_TRIG_MEM_CAL_OP, 246*91f16700Schasinglulu OPCODE_TRIG_MEM_CAL, payload, i); 247*91f16700Schasinglulu break; 248*91f16700Schasinglulu 249*91f16700Schasinglulu default: 250*91f16700Schasinglulu break; 251*91f16700Schasinglulu } 252*91f16700Schasinglulu 253*91f16700Schasinglulu if (status == -EPERM) { 254*91f16700Schasinglulu assert(status); 255*91f16700Schasinglulu } 256*91f16700Schasinglulu 257*91f16700Schasinglulu return status; 258*91f16700Schasinglulu } 259*91f16700Schasinglulu 260*91f16700Schasinglulu int ddr_config_handoff(handoff *hoff_ptr) 261*91f16700Schasinglulu { 262*91f16700Schasinglulu /* Populate DDR handoff data */ 263*91f16700Schasinglulu /* TODO: To add in DDR handoff configuration once available */ 264*91f16700Schasinglulu return 0; 265*91f16700Schasinglulu } 266*91f16700Schasinglulu 267*91f16700Schasinglulu // DDR firewall and non secure access 268*91f16700Schasinglulu void ddr_enable_ns_access(void) 269*91f16700Schasinglulu { 270*91f16700Schasinglulu /* Please set the ddr non secure registers accordingly */ 271*91f16700Schasinglulu 272*91f16700Schasinglulu mmio_setbits_32(CCU_REG(DMI0_DMIUSMCTCR), 273*91f16700Schasinglulu CCU_DMI_ALLOCEN | CCU_DMI_LOOKUPEN); 274*91f16700Schasinglulu mmio_setbits_32(CCU_REG(DMI1_DMIUSMCTCR), 275*91f16700Schasinglulu CCU_DMI_ALLOCEN | CCU_DMI_LOOKUPEN); 276*91f16700Schasinglulu 277*91f16700Schasinglulu /* TODO: To add in CCU NCORE OCRAM bypass mask for non secure registers */ 278*91f16700Schasinglulu NOTICE("DDR non secure configured\n"); 279*91f16700Schasinglulu } 280*91f16700Schasinglulu 281*91f16700Schasinglulu void ddr_enable_firewall(void) 282*91f16700Schasinglulu { 283*91f16700Schasinglulu /* Please set the ddr firewall registers accordingly */ 284*91f16700Schasinglulu /* TODO: To add in CCU NCORE OCRAM bypass mask for firewall registers */ 285*91f16700Schasinglulu NOTICE("DDR firewall enabled\n"); 286*91f16700Schasinglulu } 287*91f16700Schasinglulu 288*91f16700Schasinglulu bool is_ddr_init_in_progress(void) 289*91f16700Schasinglulu { 290*91f16700Schasinglulu uint32_t reg = mmio_read_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_POR_0)); 291*91f16700Schasinglulu 292*91f16700Schasinglulu if (reg & SOCFPGA_SYSMGR_BOOT_SCRATCH_POR_0_MASK) { 293*91f16700Schasinglulu return true; 294*91f16700Schasinglulu } 295*91f16700Schasinglulu return false; 296*91f16700Schasinglulu } 297*91f16700Schasinglulu 298*91f16700Schasinglulu int ddr_init(void) 299*91f16700Schasinglulu { 300*91f16700Schasinglulu // DDR driver initialization 301*91f16700Schasinglulu int status = -EPERM; 302*91f16700Schasinglulu uint32_t cmd_opcode = 0; 303*91f16700Schasinglulu 304*91f16700Schasinglulu // Check and set Boot Scratch Register 305*91f16700Schasinglulu if (is_ddr_init_in_progress()) { 306*91f16700Schasinglulu return status; 307*91f16700Schasinglulu } 308*91f16700Schasinglulu mmio_write_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_POR_0), 0x01); 309*91f16700Schasinglulu 310*91f16700Schasinglulu // Populate DDR handoff data 311*91f16700Schasinglulu handoff reverse_handoff_ptr; 312*91f16700Schasinglulu 313*91f16700Schasinglulu if (!socfpga_get_handoff(&reverse_handoff_ptr)) { 314*91f16700Schasinglulu assert(status); 315*91f16700Schasinglulu } 316*91f16700Schasinglulu status = ddr_config_handoff(&reverse_handoff_ptr); 317*91f16700Schasinglulu if (status == -EPERM) { 318*91f16700Schasinglulu assert(status); 319*91f16700Schasinglulu } 320*91f16700Schasinglulu 321*91f16700Schasinglulu // CCU and firewall setup 322*91f16700Schasinglulu ddr_enable_ns_access(); 323*91f16700Schasinglulu ddr_enable_firewall(); 324*91f16700Schasinglulu 325*91f16700Schasinglulu // DDR calibration check 326*91f16700Schasinglulu status = ddr_calibration_check(); 327*91f16700Schasinglulu if (status == -EPERM) { 328*91f16700Schasinglulu assert(status); 329*91f16700Schasinglulu } 330*91f16700Schasinglulu 331*91f16700Schasinglulu // DDR mailbox command 332*91f16700Schasinglulu status = ddr_iossm_mailbox_cmd(cmd_opcode); 333*91f16700Schasinglulu if (status != 0) { 334*91f16700Schasinglulu assert(status); 335*91f16700Schasinglulu } 336*91f16700Schasinglulu 337*91f16700Schasinglulu // Check and set Boot Scratch Register 338*91f16700Schasinglulu mmio_write_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_POR_0), 0x00); 339*91f16700Schasinglulu 340*91f16700Schasinglulu NOTICE("DDR init successfully\n"); 341*91f16700Schasinglulu return status; 342*91f16700Schasinglulu } 343