feat(intel): ddr driver for Agilex5 SoC FPGA

This patch is used to implement ddr driver to
support IO96b for Agilex5 SoC FPGA.
	1. Added DDR support.
	2. Updated product name -> Agilex5

Signed-off-by: Jit Loon Lim <jit.loon.lim@intel.com>
Change-Id: Ibda053de6dbec4a0f12f011d8feeb6c5890fc7a4
This commit is contained in:
Jit Loon Lim 2023-05-17 12:26:11 +08:00
parent a8bf898f02
commit 29461e4c88
2 changed files with 454 additions and 0 deletions

View file

@ -0,0 +1,342 @@
/*
* Copyright (c) 2022, Intel Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <errno.h>
#include <common/debug.h>
#include "ddr.h"
#include <lib/mmio.h>
#include "socfpga_handoff.h"
int ddr_calibration_check(void)
{
// DDR calibration check
int status = 0;
uint32_t u32data_read = 0;
NOTICE("DDR: Access address 0x%x:...\n", IO96B_0_REG_BASE);
u32data_read = mmio_read_32(IO96B_0_REG_BASE);
NOTICE("DDR: Access address 0x%x: read 0x%04x\n", IO96B_0_REG_BASE, u32data_read);
if (u32data_read == -EPERM) {
status = -EPERM;
assert(u32data_read);
}
u32data_read = 0x0;
NOTICE("DDR: Access address 0x%x: ...\n", IO96B_1_REG_BASE);
u32data_read = mmio_read_32(IO96B_1_REG_BASE);
NOTICE("DDR: Access address 0x%x: read 0x%04x\n", IO96B_1_REG_BASE, u32data_read);
if (u32data_read == -EPERM) {
status = -EPERM;
assert(u32data_read);
}
return status;
}
int iossm_mb_init(void)
{
// int status;
// Update according to IOSSM mailbox spec
// if (status) {
// return status;
// }
return 0;
}
int wait_respond(uint16_t timeout)
{
uint32_t status = 0;
uint32_t count = 0;
uint32_t data = 0;
/* Wait status command response ready */
do {
data = mmio_read_32(IO96B_CSR_REG(CMD_RESPONSE_STATUS));
count++;
if (count >= timeout) {
return -ETIMEDOUT;
}
} while (STATUS_COMMAND_RESPONSE(data) != STATUS_COMMAND_RESPONSE_READY);
status = (data & STATUS_GENERAL_ERROR_MASK) >> STATUS_GENERAL_ERROR_OFFSET;
if (status != 0) {
return status;
}
status = (data & STATUS_CMD_RESPONSE_ERROR_MASK) >> STATUS_CMD_RESPONSE_ERROR_OFFSET;
if (status != 0) {
return status;
}
return status;
}
int iossm_mb_read_response(void)
{
uint32_t status = 0;
unsigned int i;
uint32_t resp_data[IOSSM_RESP_MAX_WORD_SIZE];
uint32_t resp_param_reg;
// Check STATUS_CMD_RESPONSE_DATA_PTR_VALID in
// STATUS_COMMAND_RESPONSE to ensure data pointer response
/* Read CMD_RESPONSE_STATUS and CMD_RESPONSE_DATA_* */
resp_data[0] = mmio_read_32(IO96B_CSR_REG(CMD_RESPONSE_STATUS));
resp_data[0] = (resp_data[0] & CMD_RESPONSE_DATA_SHORT_MASK) >>
CMD_RESPONSE_DATA_SHORT_OFFSET;
resp_param_reg = CMD_RESPONSE_STATUS;
for (i = 1; i < IOSSM_RESP_MAX_WORD_SIZE; i++) {
resp_param_reg = resp_param_reg - CMD_RESPONSE_OFFSET;
resp_data[i] = mmio_read_32(IO96B_CSR_REG(resp_param_reg));
}
/* Wait for STATUS_COMMAND_RESPONSE_READY*/
status = wait_respond(1000);
/* Read CMD_RESPONSE_STATUS and CMD_RESPONSE_DATA_* */
mmio_setbits_32(STATUS_COMMAND_RESPONSE(IO96B_CSR_REG(
CMD_RESPONSE_STATUS)),
STATUS_COMMAND_RESPONSE_READY_CLEAR);
return status;
}
int 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)
{
unsigned int i;
uint32_t status = 0;
uint32_t cmd_req;
uint32_t cmd_param_reg;
cmd_target_ip_type = (cmd_target_ip_type & CMD_TARGET_IP_TYPE_MASK) <<
CMD_TARGET_IP_TYPE_OFFSET;
cmd_target_ip_instance_id = (cmd_target_ip_instance_id &
CMD_TARGET_IP_INSTANCE_ID_MASK) <<
CMD_TARGET_IP_INSTANCE_ID_OFFSET;
cmd_type = (cmd_type & CMD_TYPE_MASK) << CMD_TYPE_OFFSET;
cmd_opcode = (cmd_opcode & CMD_OPCODE_MASK) << CMD_OPCODE_OFFSET;
cmd_req = cmd_target_ip_type | cmd_target_ip_instance_id | cmd_type |
cmd_opcode;
/* send mailbox request */
IOSSM_MB_WRITE(IO96B_CSR_REG(CMD_REQ), cmd_req);
if (len != 0) {
cmd_param_reg = CMD_REQ;
for (i = 0; i < len; i++) {
cmd_param_reg = cmd_param_reg - CMD_PARAM_OFFSET;
IOSSM_MB_WRITE(IO96B_CSR_REG(cmd_param_reg), args[i]);
}
}
status = iossm_mb_read_response();
if (status != 0) {
return status;
}
return status;
}
int ddr_iossm_mailbox_cmd(uint32_t cmd_opcode)
{
// IOSSM
uint32_t status = 0;
unsigned int i = 0;
uint32_t payload[IOSSM_CMD_MAX_WORD_SIZE] = {0U};
switch (cmd_opcode) {
case CMD_INIT:
status = iossm_mb_init();
break;
case OPCODE_GET_MEM_INTF_INFO:
status = iossm_mb_send(0, 0, MBOX_CMD_GET_SYS_INFO,
OPCODE_GET_MEM_INTF_INFO, payload, i);
break;
case OPCODE_GET_MEM_TECHNOLOGY:
status = iossm_mb_send(0, 0, MBOX_CMD_GET_MEM_INFO,
OPCODE_GET_MEM_TECHNOLOGY, payload, i);
break;
case OPCODE_GET_MEM_WIDTH_INFO:
status = iossm_mb_send(0, 0, MBOX_CMD_GET_MEM_INFO,
OPCODE_GET_MEM_WIDTH_INFO, payload, i);
break;
case OPCODE_ECC_ENABLE_STATUS:
status = iossm_mb_send(0, 0,
MBOX_CMD_TRIG_CONTROLLER_OP, OPCODE_ECC_ENABLE_STATUS,
payload, i);
break;
case OPCODE_ECC_INTERRUPT_MASK:
// payload[i] = CMD_PARAM_0 [16:0]: ECC_INTERRUPT_MASK
status = iossm_mb_send(0, 0,
MBOX_CMD_TRIG_CONTROLLER_OP, OPCODE_ECC_INTERRUPT_MASK,
payload, i);
break;
case OPCODE_ECC_SCRUB_MODE_0_START:
// payload[i] = CMD_PARAM_0 [15:0]: ECC_SCRUB_INTERVAL
//i++;
// payload[i] = CMD_PARAM_1 [11:0]: ECC_SCRUB_LEN
//i++;
// payload[i] = CMD_PARAM_2 [0:0]: ECC_SCRUB_FULL_MEM
//i++;
// payload[i]= CMD_PARAM_3 [31:0]: ECC_SCRUB_START_ADDR [31:0]
//i++;
// payload[i] = CMD_PARAM_4 [5:0]: ECC_SCRUB_START_ADDR [36:32]
//i++;
// payload[i] = CMD_PARAM_5 [31:0]: ECC_SCRUB_END_ADDR [31:0]
//i++;
// payload[i] = CMD_PARAM_6 [5:0]: ECC_SCRUB_END_ADDR [36:32]
//i++;
status = iossm_mb_send(0, 0,
MBOX_CMD_TRIG_CONTROLLER_OP, OPCODE_ECC_SCRUB_MODE_0_START,
payload, i);
break;
case OPCODE_ECC_SCRUB_MODE_1_START:
// payload[i] = CMD_PARAM_0 [15:0]: ECC_SCRUB_IDLE_CNT
//i++;
// payload[i] = CMD_PARAM_1 [11:0]: ECC_SCRUB_LEN
//i++;
// payload[i] = CMD_PARAM_2 [0:0]: ECC_SCRUB_FULL_MEM
//i++;
// payload[i] = CMD_PARAM_3 [31:0]: ECC_SCRUB_START_ADDR [31:0]
//i++;
// payload[i] = CMD_PARAM_4 [5:0]: ECC_SCRUB_START_ADDR [36:32]
//i++;
// payload[i] = CMD_PARAM_5 [31:0]: ECC_SCRUB_END_ADDR [31:0]
//i++;
// payload[i] = CMD_PARAM_6 [5:0]: ECC_SCRUB_END_ADDR [36:32]
//i++;
status = iossm_mb_send(0, 0,
MBOX_CMD_TRIG_CONTROLLER_OP, OPCODE_ECC_SCRUB_MODE_1_START,
payload, i);
break;
case OPCODE_BIST_RESULTS_STATUS:
status = iossm_mb_send(0, 0,
MBOX_CMD_TRIG_CONTROLLER_OP, OPCODE_BIST_RESULTS_STATUS,
payload, i);
break;
case OPCODE_BIST_MEM_INIT_START:
status = iossm_mb_send(0, 0,
MBOX_CMD_TRIG_CONTROLLER_OP, OPCODE_BIST_MEM_INIT_START,
payload, i);
break;
case OPCODE_TRIG_MEM_CAL:
status = iossm_mb_send(0, 0, MBOX_CMD_TRIG_MEM_CAL_OP,
OPCODE_TRIG_MEM_CAL, payload, i);
break;
default:
break;
}
if (status == -EPERM) {
assert(status);
}
return status;
}
int ddr_config_handoff(handoff *hoff_ptr)
{
/* Populate DDR handoff data */
/* TODO: To add in DDR handoff configuration once available */
return 0;
}
// DDR firewall and non secure access
void ddr_enable_ns_access(void)
{
/* Please set the ddr non secure registers accordingly */
mmio_setbits_32(CCU_REG(DMI0_DMIUSMCTCR),
CCU_DMI_ALLOCEN | CCU_DMI_LOOKUPEN);
mmio_setbits_32(CCU_REG(DMI1_DMIUSMCTCR),
CCU_DMI_ALLOCEN | CCU_DMI_LOOKUPEN);
/* TODO: To add in CCU NCORE OCRAM bypass mask for non secure registers */
NOTICE("DDR non secure configured\n");
}
void ddr_enable_firewall(void)
{
/* Please set the ddr firewall registers accordingly */
/* TODO: To add in CCU NCORE OCRAM bypass mask for firewall registers */
NOTICE("DDR firewall enabled\n");
}
bool is_ddr_init_in_progress(void)
{
uint32_t reg = mmio_read_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_POR_0));
if (reg & SOCFPGA_SYSMGR_BOOT_SCRATCH_POR_0_MASK) {
return true;
}
return false;
}
int ddr_init(void)
{
// DDR driver initialization
int status = -EPERM;
uint32_t cmd_opcode = 0;
// Check and set Boot Scratch Register
if (is_ddr_init_in_progress()) {
return status;
}
mmio_write_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_POR_0), 0x01);
// Populate DDR handoff data
handoff reverse_handoff_ptr;
if (!socfpga_get_handoff(&reverse_handoff_ptr)) {
assert(status);
}
status = ddr_config_handoff(&reverse_handoff_ptr);
if (status == -EPERM) {
assert(status);
}
// CCU and firewall setup
ddr_enable_ns_access();
ddr_enable_firewall();
// DDR calibration check
status = ddr_calibration_check();
if (status == -EPERM) {
assert(status);
}
// DDR mailbox command
status = ddr_iossm_mailbox_cmd(cmd_opcode);
if (status != 0) {
assert(status);
}
// Check and set Boot Scratch Register
mmio_write_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_POR_0), 0x00);
NOTICE("DDR init successfully\n");
return status;
}

View file

@ -0,0 +1,112 @@
/*
* Copyright (c) 2022-2023, Intel Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef DDR_H
#define DDR_H
#include <lib/mmio.h>
#include "socfpga_handoff.h"
/* MACRO DEFINATION */
#define IO96B_0_REG_BASE 0x18400000
#define IO96B_1_REG_BASE 0x18800000
#define IO96B_CSR_BASE 0x05000000
#define IO96B_CSR_REG(reg) (IO96B_CSR_BASE + reg)
#define IOSSM_CMD_MAX_WORD_SIZE 7U
#define IOSSM_RESP_MAX_WORD_SIZE 4U
#define CCU_REG_BASE 0x1C000000
#define DMI0_DMIUSMCTCR 0x7300
#define DMI1_DMIUSMCTCR 0x8300
#define CCU_DMI_ALLOCEN BIT(1)
#define CCU_DMI_LOOKUPEN BIT(2)
#define CCU_REG(reg) (CCU_REG_BASE + reg)
// CMD_RESPONSE_STATUS Register
#define CMD_RESPONSE_STATUS 0x45C
#define CMD_RESPONSE_OFFSET 0x4
#define CMD_RESPONSE_DATA_SHORT_MASK GENMASK(31, 16)
#define CMD_RESPONSE_DATA_SHORT_OFFSET 16
#define STATUS_CMD_RESPONSE_ERROR_MASK GENMASK(7, 5)
#define STATUS_CMD_RESPONSE_ERROR_OFFSET 5
#define STATUS_GENERAL_ERROR_MASK GENMASK(4, 1)
#define STATUS_GENERAL_ERROR_OFFSET 1
#define STATUS_COMMAND_RESPONSE_READY 0x1
#define STATUS_COMMAND_RESPONSE_READY_CLEAR 0x0
#define STATUS_COMMAND_RESPONSE_READY_MASK 0x1
#define STATUS_COMMAND_RESPONSE_READY_OFFSET 0
#define STATUS_COMMAND_RESPONSE(x) (((x) & \
STATUS_COMMAND_RESPONSE_READY_MASK) >> \
STATUS_COMMAND_RESPONSE_READY_OFFSET)
// CMD_REQ Register
#define CMD_STATUS 0x400
#define CMD_PARAM 0x438
#define CMD_REQ 0x43C
#define CMD_PARAM_OFFSET 0x4
#define CMD_TARGET_IP_TYPE_MASK GENMASK(31, 29)
#define CMD_TARGET_IP_TYPE_OFFSET 29
#define CMD_TARGET_IP_INSTANCE_ID_MASK GENMASK(28, 24)
#define CMD_TARGET_IP_INSTANCE_ID_OFFSET 24
#define CMD_TYPE_MASK GENMASK(23, 16)
#define CMD_TYPE_OFFSET 16
#define CMD_OPCODE_MASK GENMASK(15, 0)
#define CMD_OPCODE_OFFSET 0
#define CMD_INIT 0
#define OPCODE_GET_MEM_INTF_INFO 0x0001
#define OPCODE_GET_MEM_TECHNOLOGY 0x0002
#define OPCODE_GET_MEM_WIDTH_INFO 0x0004
#define OPCODE_TRIG_MEM_CAL 0x000A
#define OPCODE_ECC_ENABLE_STATUS 0x0102
#define OPCODE_ECC_INTERRUPT_MASK 0x0105
#define OPCODE_ECC_SCRUB_MODE_0_START 0x0202
#define OPCODE_ECC_SCRUB_MODE_1_START 0x0203
#define OPCODE_BIST_RESULTS_STATUS 0x0302
#define OPCODE_BIST_MEM_INIT_START 0x0303
// Please update according to IOSSM mailbox spec
#define MBOX_ID_IOSSM 0x00
#define MBOX_CMD_GET_SYS_INFO 0x01
// Please update according to IOSSM mailbox spec
#define MBOX_CMD_GET_MEM_INFO 0x02
#define MBOX_CMD_TRIG_CONTROLLER_OP 0x04
#define MBOX_CMD_TRIG_MEM_CAL_OP 0x05
#define MBOX_CMD_POKE_REG 0xFD
#define MBOX_CMD_PEEK_REG 0xFE
#define MBOX_CMD_GET_DEBUG_LOG 0xFF
// Please update according to IOSSM mailbox spec
#define MBOX_CMD_DIRECT 0x00
#define SOCFPGA_SYSMGR_BOOT_SCRATCH_POR_0_MASK 0x01
#define IOSSM_MB_WRITE(addr, data) mmio_write_32(addr, data)
/* FUNCTION DEFINATION */
int ddr_calibration_check(void);
int iossm_mb_init(void);
int iossm_mb_read_response(void);
int 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);
int ddr_iossm_mailbox_cmd(uint32_t cmd);
int ddr_init(void);
int ddr_config_handoff(handoff *hoff_ptr);
void ddr_enable_ns_access(void);
void ddr_enable_firewall(void);
bool is_ddr_init_in_progress(void);
#endif