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