From patchwork Wed Jun 21 03:16:01 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jit Loon Lim X-Patchwork-Id: 1797634 X-Patchwork-Delegate: marek.vasut@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=BjerqIru; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Qm7xW6MXJz20XS for ; Wed, 21 Jun 2023 13:18:23 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id C05B986322; Wed, 21 Jun 2023 05:17:26 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=intel.com header.i=@intel.com header.b="BjerqIru"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 7497D86366; Wed, 21 Jun 2023 05:16:56 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE, SPF_NONE,T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.2 Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 54E80862EB for ; Wed, 21 Jun 2023 05:16:26 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: phobos.denx.de; spf=none smtp.mailfrom=jitloonl@ecsmtp.png.intel.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1687317386; x=1718853386; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=j7+kleynN3JLg2msvOq3+hqj4F+95fIJ+EdGSK0DXqc=; b=BjerqIrukdgimh3DWWVYx9glWVp2HjSsyCJ/Nk8OA0YXVAkz5V6W6ziI LEiMdpVI/BefOmPCEOP+8QZc12s4hncV673CYDSxlT0yvd9id/JTWrOfI XTGq/pWuke9Oru4fBMklkt3S3+dyw9wtoJa2kBKeK9t/6qwdakD9C1Hfr jdAObuuMdkFLP1NZQRtcN4HxzpEEj2bkJ5En3umgRi1UVtXSyAZ6E5Oyp jkxFPitAZols5sSsf6E5dr/Xj30JPw/b5JYvs55o1tzKsQiB4GhsOfJvK T30gRPWw6U2q1iggJg6NM7Q2EgXdDhmI87u7rxUBOzMkHGwL1VIa9uvsf w==; X-IronPort-AV: E=McAfee;i="6600,9927,10747"; a="360059751" X-IronPort-AV: E=Sophos;i="6.00,259,1681196400"; d="scan'208";a="360059751" Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Jun 2023 20:16:24 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10747"; a="664479887" X-IronPort-AV: E=Sophos;i="6.00,259,1681196400"; d="scan'208";a="664479887" Received: from pglmail07.png.intel.com ([10.221.193.207]) by orsmga003.jf.intel.com with ESMTP; 20 Jun 2023 20:16:20 -0700 Received: from localhost (pgli0121.png.intel.com [10.221.240.84]) by pglmail07.png.intel.com (Postfix) with ESMTP id C22262B97; Wed, 21 Jun 2023 11:16:19 +0800 (+08) Received: by localhost (Postfix, from userid 12048045) id C04112950; Wed, 21 Jun 2023 11:16:19 +0800 (+08) From: Jit Loon Lim To: u-boot@lists.denx.de Cc: Jagan Teki , Vignesh R , Marek , Simon , Tien Fong , Kok Kiang , Raaj , Dinesh , Boon Khai , Alif , Teik Heng , Hazim , Jit Loon Lim , Sieu Mun Tang Subject: [PATCH v1 08/17] drivers: ddr: altera: add ddr support for agilex5 Date: Wed, 21 Jun 2023 11:16:01 +0800 Message-Id: <20230621031610.28401-9-jit.loon.lim@intel.com> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20230621031610.28401-1-jit.loon.lim@intel.com> References: <20230621031610.28401-1-jit.loon.lim@intel.com> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.8 at phobos.denx.de X-Virus-Status: Clean This is for new platform enablement for agilex5. Add new ddr and iossm mailbox files for new platform.Add Signed-off-by: Jit Loon Lim --- drivers/ddr/altera/Makefile | 5 +- drivers/ddr/altera/iossm_mailbox.c | 786 +++++++++++++++++++++++++++++ drivers/ddr/altera/iossm_mailbox.h | 141 ++++++ drivers/ddr/altera/sdram_agilex5.c | 329 ++++++++++++ drivers/ddr/altera/sdram_soc64.c | 78 ++- drivers/ddr/altera/sdram_soc64.h | 17 +- 6 files changed, 1345 insertions(+), 11 deletions(-) create mode 100644 drivers/ddr/altera/iossm_mailbox.c create mode 100644 drivers/ddr/altera/iossm_mailbox.h create mode 100644 drivers/ddr/altera/sdram_agilex5.c diff --git a/drivers/ddr/altera/Makefile b/drivers/ddr/altera/Makefile index 9fa5d85a27..fa6c880b39 100644 --- a/drivers/ddr/altera/Makefile +++ b/drivers/ddr/altera/Makefile @@ -7,9 +7,10 @@ # Copyright (C) 2014-2021 Altera Corporation ifdef CONFIG_$(SPL_)ALTERA_SDRAM -obj-$(CONFIG_TARGET_SOCFPGA_GEN5) += sdram_gen5.o sequencer.o -obj-$(CONFIG_TARGET_SOCFPGA_ARRIA10) += sdram_arria10.o +obj-$(CONFIG_TARGET_SOCFPGA_GEN5) += sdram_soc32.o sdram_gen5.o sequencer.o +obj-$(CONFIG_TARGET_SOCFPGA_ARRIA10) += sdram_soc32.o sdram_arria10.o obj-$(CONFIG_TARGET_SOCFPGA_STRATIX10) += sdram_soc64.o sdram_s10.o obj-$(CONFIG_TARGET_SOCFPGA_AGILEX) += sdram_soc64.o sdram_agilex.o obj-$(CONFIG_TARGET_SOCFPGA_N5X) += sdram_soc64.o sdram_n5x.o +obj-$(CONFIG_TARGET_SOCFPGA_AGILEX5) += sdram_soc64.o sdram_agilex5.o iossm_mailbox.o endif diff --git a/drivers/ddr/altera/iossm_mailbox.c b/drivers/ddr/altera/iossm_mailbox.c new file mode 100644 index 0000000000..c7ceed7c45 --- /dev/null +++ b/drivers/ddr/altera/iossm_mailbox.c @@ -0,0 +1,786 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 Intel Corporation + * + */ + +#define DEBUG +#include +#include +#include +#include "iossm_mailbox.h" +#include + +/* supported DDR type list */ +static const char *ddr_type_list[7] = { + "DDR4", "DDR5", "DDR5_RDIMM", "LPDDR4", "LPDDR5", "QDRIV", "UNKNOWN" +}; + +/* Mailbox request function + * This function will send the request to IOSSM mailbox and wait for response return + * + * @io96b_csr_addr: CSR address for the target IO96B + * @ip_type: IP type for the specified memory interface + * @instance_id: IP instance ID for the specified memory interface + * @usr_cmd_type: User desire IOSSM mailbox command type + * @usr_cmd_opcode: User desire IOSSM mailbox command opcode + * @cmd_param_*: Parameters (if applicable) for the requested IOSSM mailbox command + * @resp_data_len: User desire extra response data fields other than + * CMD_RESPONSE_DATA_SHORT field on CMD_RESPONSE_STATUS + * @resp: Structure contain responses returned from the requested IOSSM + * mailbox command + */ +int io96b_mb_req(phys_addr_t io96b_csr_addr, u32 ip_type, u32 instance_id + , u32 usr_cmd_type, u32 usr_cmd_opcode, u32 cmd_param_0 + , u32 cmd_param_1, u32 cmd_param_2, u32 cmd_param_3 + , u32 cmd_param_4, u32 cmd_param_5, u32 cmd_param_6 + , u32 resp_data_len, struct io96b_mb_resp *resp) +{ + int i; + int ret; + u32 cmd_req, cmd_resp; + + /* Initialized zeros for responses*/ + resp->cmd_resp_status = 0; + resp->cmd_resp_data_0 = 0; + resp->cmd_resp_data_1 = 0; + resp->cmd_resp_data_2 = 0; + + /* Ensure CMD_REQ is cleared before write any command request */ + ret = wait_for_bit_le32((const void *)(io96b_csr_addr + IOSSM_CMD_REQ_OFFSET) + , GENMASK(31, 0), 0, TIMEOUT, false); + + if (ret) { + printf("%s: CMD_REQ not ready\n", __func__); + return -1; + } + + /* Write CMD_PARAM_* */ + for (i = 0; i < 6 ; i++) { + switch (i) { + case 0: + if (cmd_param_0) + writel(cmd_param_0, io96b_csr_addr + IOSSM_CMD_PARAM_0_OFFSET); + break; + case 1: + if (cmd_param_1) + writel(cmd_param_1, io96b_csr_addr + IOSSM_CMD_PARAM_1_OFFSET); + break; + case 2: + if (cmd_param_2) + writel(cmd_param_2, io96b_csr_addr + IOSSM_CMD_PARAM_2_OFFSET); + break; + case 3: + if (cmd_param_3) + writel(cmd_param_3, io96b_csr_addr + IOSSM_CMD_PARAM_3_OFFSET); + break; + case 4: + if (cmd_param_4) + writel(cmd_param_4, io96b_csr_addr + IOSSM_CMD_PARAM_4_OFFSET); + break; + case 5: + if (cmd_param_5) + writel(cmd_param_5, io96b_csr_addr + IOSSM_CMD_PARAM_5_OFFSET); + break; + case 6: + if (cmd_param_6) + writel(cmd_param_6, io96b_csr_addr + IOSSM_CMD_PARAM_6_OFFSET); + break; + default: + printf("%s: Invalid command parameter\n", __func__); + } + } + + /* Write CMD_REQ (IP_TYPE, IP_INSTANCE_ID, CMD_TYPE and CMD_OPCODE) */ + cmd_req = (usr_cmd_opcode << 0) | (usr_cmd_type << 16) | (instance_id << 24) | + (ip_type << 29); + writel(cmd_req, io96b_csr_addr + IOSSM_CMD_REQ_OFFSET); + debug("%s: Write 0x%x to IOSSM_CMD_REQ_OFFSET 0x%llx\n", __func__, cmd_req + , io96b_csr_addr + IOSSM_CMD_REQ_OFFSET); + + /* Read CMD_RESPONSE_READY in CMD_RESPONSE_STATUS*/ + ret = wait_for_bit_le32((const void *)(io96b_csr_addr + + IOSSM_CMD_RESPONSE_STATUS_OFFSET), IOSSM_STATUS_COMMAND_RESPONSE_READY, 1, + TIMEOUT, false); + + if (ret) { + printf("%s: CMD_RESPONSE ERROR:\n", __func__); + cmd_resp = readl(io96b_csr_addr + IOSSM_CMD_RESPONSE_STATUS_OFFSET); + printf("%s: STATUS_GENERAL_ERROR: 0x%x\n", __func__, (cmd_resp >> 1) & 0xF); + printf("%s: STATUS_CMD_RESPONSE_ERROR: 0x%x\n", __func__, (cmd_resp >> 5) & 0x7); + } + + /* read CMD_RESPONSE_STATUS*/ + resp->cmd_resp_status = readl(io96b_csr_addr + IOSSM_CMD_RESPONSE_STATUS_OFFSET); + debug("%s: CMD_RESPONSE_STATUS 0x%llx: 0x%x\n", __func__, io96b_csr_addr + + IOSSM_CMD_RESPONSE_STATUS_OFFSET, resp->cmd_resp_status); + + /* read CMD_RESPONSE_DATA_* */ + for (i = 0; i < resp_data_len; i++) { + switch (i) { + case 0: + resp->cmd_resp_data_0 = + readl(io96b_csr_addr + IOSSM_CMD_RESPONSE_DATA_0_OFFSET); + debug("%s: IOSSM_CMD_RESPONSE_DATA_0_OFFSET 0x%llx: 0x%x\n", __func__ + , io96b_csr_addr + IOSSM_CMD_RESPONSE_DATA_0_OFFSET, + resp->cmd_resp_data_0); + break; + case 1: + resp->cmd_resp_data_1 = + readl(io96b_csr_addr + IOSSM_CMD_RESPONSE_DATA_1_OFFSET); + debug("%s: IOSSM_CMD_RESPONSE_DATA_1_OFFSET 0x%llx: 0x%x\n", __func__ + , io96b_csr_addr + IOSSM_CMD_RESPONSE_DATA_1_OFFSET, + resp->cmd_resp_data_1); + break; + case 2: + resp->cmd_resp_data_2 = + readl(io96b_csr_addr + IOSSM_CMD_RESPONSE_DATA_2_OFFSET); + debug("%s: IOSSM_CMD_RESPONSE_DATA_2_OFFSET 0x%llx: 0x%x\n", __func__ + , io96b_csr_addr + IOSSM_CMD_RESPONSE_DATA_2_OFFSET, + resp->cmd_resp_data_2); + break; + default: + printf("%s: Invalid response data\n", __func__); + } + } + + resp->cmd_resp_status = readl(io96b_csr_addr + IOSSM_CMD_RESPONSE_STATUS_OFFSET); + debug("%s: CMD_RESPONSE_STATUS 0x%llx: 0x%x\n", __func__, io96b_csr_addr + + IOSSM_CMD_RESPONSE_STATUS_OFFSET, resp->cmd_resp_status); + + /* write CMD_RESPONSE_READY = 0 */ + clrbits_le32((u32 *)(uintptr_t)(io96b_csr_addr + IOSSM_CMD_RESPONSE_STATUS_OFFSET) + , IOSSM_STATUS_COMMAND_RESPONSE_READY); + + resp->cmd_resp_status = readl(io96b_csr_addr + IOSSM_CMD_RESPONSE_STATUS_OFFSET); + debug("%s: CMD_RESPONSE_READY 0x%llx: 0x%x\n", __func__, io96b_csr_addr + + IOSSM_CMD_RESPONSE_STATUS_OFFSET, resp->cmd_resp_status); + + return 0; +} + +/* + * Initial function to be called to set memory interface IP type and instance ID + * IP type and instance ID need to be determined before sending mailbox command + */ +void io96b_mb_init(struct io96b_info *io96b_ctrl) +{ + struct io96b_mb_resp usr_resp; + u8 ip_type_ret, instance_id_ret; + int i, j, k; + + debug("%s: num_instance %d\n", __func__, io96b_ctrl->num_instance); + for (i = 0; i < io96b_ctrl->num_instance; i++) { + debug("%s: get memory interface IO96B %d\n", __func__, i); + switch (i) { + case 0: + /* Get memory interface IP type & instance ID (IP identifier) */ + io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr, 0, 0 + , CMD_GET_SYS_INFO, GET_MEM_INTF_INFO + , 0, 0, 0, 0, 0, 0, 0, 2, &usr_resp); + debug("%s: get response from memory interface IO96B %d\n", __func__, i); + /* Retrieve number of memory interface(s) */ + io96b_ctrl->io96b_0.mb_ctrl.num_mem_interface = + IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status) & 0x3; + + /* Retrieve memory interface IP type and instance ID (IP identifier) */ + j = 0; + for (k = 0; k < MAX_MEM_INTERFACES_SUPPORTED; k++) { + switch (k) { + case 0: + ip_type_ret = (usr_resp.cmd_resp_data_0 >> 29) & 0x7; + instance_id_ret = (usr_resp.cmd_resp_data_0 >> 24) & 0x1F; + break; + case 1: + ip_type_ret = (usr_resp.cmd_resp_data_1 >> 29) & 0x7; + instance_id_ret = (usr_resp.cmd_resp_data_1 >> 24) & 0x1F; + break; + } + + if (ip_type_ret) { + io96b_ctrl->io96b_0.mb_ctrl.ip_type[j] = ip_type_ret; + io96b_ctrl->io96b_0.mb_ctrl.ip_instance_id[j] = + instance_id_ret; + j++; + } + } + break; + case 1: + /* Get memory interface IP type and instance ID (IP identifier) */ + io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr, 0, 0, CMD_GET_SYS_INFO + , GET_MEM_INTF_INFO, 0, 0, 0, 0, 0, 0, 0, 2, &usr_resp); + debug("%s: get response from memory interface IO96B %d\n", __func__, i); + /* Retrieve number of memory interface(s) */ + io96b_ctrl->io96b_1.mb_ctrl.num_mem_interface = + IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status) & 0x3; + debug("%s: IO96B %d: num_mem_interface: 0x%x\n", __func__, i + , io96b_ctrl->io96b_1.mb_ctrl.num_mem_interface); + + /* Retrieve memory interface IP type and instance ID (IP identifier) */ + j = 0; + for (k = 0; k < MAX_MEM_INTERFACES_SUPPORTED; k++) { + switch (k) { + case 0: + ip_type_ret = (usr_resp.cmd_resp_data_0 >> 29) & 0x7; + instance_id_ret = (usr_resp.cmd_resp_data_0 >> 24) & 0x1F; + break; + case 1: + ip_type_ret = (usr_resp.cmd_resp_data_1 >> 29) & 0x7; + instance_id_ret = (usr_resp.cmd_resp_data_1 >> 24) & 0x1F; + break; + } + + if (ip_type_ret) { + io96b_ctrl->io96b_1.mb_ctrl.ip_type[j] = ip_type_ret; + io96b_ctrl->io96b_1.mb_ctrl.ip_instance_id[j] = + instance_id_ret; + j++; + } + } + break; + } + debug("%s: IO96B %d: ip_type_ret: 0x%x\n", __func__, i, ip_type_ret); + debug("%s: IO96B %d: instance_id_ret: 0x%x\n", __func__, i, instance_id_ret); + } +} + +int io96b_cal_status(phys_addr_t addr) +{ + int ret; + u32 cal_success, cal_fail; + phys_addr_t status_addr = addr + IOSSM_STATUS_OFFSET; + /* Ensure calibration completed */ + ret = wait_for_bit_le32((const void *)status_addr, IOSSM_STATUS_CAL_BUSY, false + , TIMEOUT, false); + if (ret) { + printf("%s: SDRAM calibration IO96b instance 0x%llx timeout\n", __func__ + , status_addr); + hang(); + } + + /* Calibration status */ + cal_success = readl(status_addr) & IOSSM_STATUS_CAL_SUCCESS; + cal_fail = readl(status_addr) & IOSSM_STATUS_CAL_FAIL; + + if (cal_success && !cal_fail) + return 0; + else + return -EPERM; +} + +void init_mem_cal(struct io96b_info *io96b_ctrl) +{ + int count, i, ret; + + /* Initialize overall calibration status */ + io96b_ctrl->overall_cal_status = false; + + /* Check initial calibration status for the assigned IO96B*/ + count = 0; + for (i = 0; i < io96b_ctrl->num_instance; i++) { + switch (i) { + case 0: + ret = io96b_cal_status(io96b_ctrl->io96b_0.io96b_csr_addr); + if (ret) { + io96b_ctrl->io96b_0.cal_status = false; + printf("%s: Initial DDR calibration IO96B_0 failed %d\n", __func__ + , ret); + break; + } + io96b_ctrl->io96b_0.cal_status = true; + printf("%s: Initial DDR calibration IO96B_0 succeed\n", __func__); + count++; + break; + case 1: + ret = io96b_cal_status(io96b_ctrl->io96b_1.io96b_csr_addr); + if (ret) { + io96b_ctrl->io96b_1.cal_status = false; + printf("%s: Initial DDR calibration IO96B_1 failed %d\n", __func__ + , ret); + break; + } + io96b_ctrl->io96b_1.cal_status = true; + printf("%s: Initial DDR calibration IO96B_1 succeed\n", __func__); + count++; + break; + } + } + + if (count == io96b_ctrl->num_instance) + io96b_ctrl->overall_cal_status = true; +} + +/* + * Trying 3 times re-calibration if initial calibration failed + */ +int trig_mem_cal(struct io96b_info *io96b_ctrl) +{ + struct io96b_mb_resp usr_resp; + bool recal_success; + int i; + u8 cal_stat; + + for (i = 0; i < io96b_ctrl->num_instance; i++) { + switch (i) { + case 0: + if (!(io96b_ctrl->io96b_0.cal_status)) { + /* Get the memory calibration status for first memory interface */ + io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr, 0, 0 + , CMD_TRIG_MEM_CAL_OP, GET_MEM_CAL_STATUS, 0, 0, 0 + , 0, 0, 0, 0, 2, &usr_resp); + + recal_success = false; + + /* Re-calibration first memory interface with failed calibration */ + for (i = 0; i < 3; i++) { + cal_stat = usr_resp.cmd_resp_data_0 & GENMASK(2, 0); + if (cal_stat < 0x2) { + recal_success = true; + break; + } + io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr + , io96b_ctrl->io96b_0.mb_ctrl.ip_type[0] + , io96b_ctrl->io96b_0.mb_ctrl.ip_instance_id[0] + , CMD_TRIG_MEM_CAL_OP, TRIG_MEM_CAL, 0, 0, 0, 0, 0 + , 0, 0, 2, &usr_resp); + + udelay(1); + + io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr, 0, 0 + , CMD_TRIG_MEM_CAL_OP, GET_MEM_CAL_STATUS + , 0, 0, 0, 0, 0, 0, 0, 2, &usr_resp); + } + + if (!recal_success) { + printf("%s: Error as SDRAM calibration failed\n", __func__); + hang(); + } + + /* Get the memory calibration status for second memory interface */ + io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr, 0, 0 + , CMD_TRIG_MEM_CAL_OP, GET_MEM_CAL_STATUS, 0, 0, 0 + , 0, 0, 0, 0, 2, &usr_resp); + + recal_success = false; + + /* Re-calibration second memory interface with failed calibration */ + for (i = 0; i < 3; i++) { + cal_stat = usr_resp.cmd_resp_data_1 & GENMASK(2, 0); + if (cal_stat < 0x2) { + recal_success = true; + break; + } + io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr + , io96b_ctrl->io96b_0.mb_ctrl.ip_type[1] + , io96b_ctrl->io96b_0.mb_ctrl.ip_instance_id[1] + , CMD_TRIG_MEM_CAL_OP, TRIG_MEM_CAL, 0, 0, 0, 0, 0 + , 0, 0, 2, &usr_resp); + + udelay(1); + + io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr, 0, 0 + , CMD_TRIG_MEM_CAL_OP, GET_MEM_CAL_STATUS + , 0, 0, 0, 0, 0, 0, 0, 2, &usr_resp); + } + + if (!recal_success) { + printf("%s: Error as SDRAM calibration failed\n", __func__); + hang(); + } + + io96b_ctrl->io96b_0.cal_status = true; + } + break; + case 1: + if (!(io96b_ctrl->io96b_1.cal_status)) { + /* Get the memory calibration status for first memory interface */ + io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr, 0, 0 + , CMD_TRIG_MEM_CAL_OP, GET_MEM_CAL_STATUS, 0, 0, 0 + , 0, 0, 0, 0, 2, &usr_resp); + + recal_success = false; + + /* Re-calibration first memory interface with failed calibration */ + for (i = 0; i < 3; i++) { + cal_stat = usr_resp.cmd_resp_data_0 & GENMASK(2, 0); + if (cal_stat < 0x2) { + recal_success = true; + break; + } + io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr + , io96b_ctrl->io96b_1.mb_ctrl.ip_type[0] + , io96b_ctrl->io96b_1.mb_ctrl.ip_instance_id[0] + , CMD_TRIG_MEM_CAL_OP, TRIG_MEM_CAL, 0, 0, 0, 0, 0 + , 0, 0, 2, &usr_resp); + + udelay(1); + + io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr, 0, 0 + , CMD_TRIG_MEM_CAL_OP, GET_MEM_CAL_STATUS + , 0, 0, 0, 0, 0, 0, 0, 2, &usr_resp); + } + + if (!recal_success) { + printf("%s: Error as SDRAM calibration failed\n", __func__); + hang(); + } + + /* Get the memory calibration status for second memory interface */ + io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr, 0, 0 + , CMD_TRIG_MEM_CAL_OP, GET_MEM_CAL_STATUS, 0, 0, 0 + , 0, 0, 0, 0, 2, &usr_resp); + + recal_success = false; + + /* Re-calibration second memory interface with failed calibration */ + for (i = 0; i < 3; i++) { + cal_stat = usr_resp.cmd_resp_data_0 & GENMASK(2, 0); + if (cal_stat < 0x2) { + recal_success = true; + break; + } + io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr + , io96b_ctrl->io96b_1.mb_ctrl.ip_type[1] + , io96b_ctrl->io96b_1.mb_ctrl.ip_instance_id[1] + , CMD_TRIG_MEM_CAL_OP, TRIG_MEM_CAL, 0, 0, 0, 0, 0 + , 0, 0, 2, &usr_resp); + + udelay(1); + + io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr, 0, 0 + , CMD_TRIG_MEM_CAL_OP, GET_MEM_CAL_STATUS + , 0, 0, 0, 0, 0, 0, 0, 2, &usr_resp); + } + + if (!recal_success) { + printf("%s: Error as SDRAM calibration failed\n", __func__); + hang(); + } + + io96b_ctrl->io96b_1.cal_status = true; + } + break; + } + } + + if (io96b_ctrl->io96b_0.cal_status && io96b_ctrl->io96b_1.cal_status) { + debug("%s: Overall SDRAM calibration success\n", __func__); + io96b_ctrl->overall_cal_status = true; + } + + return 0; +} + +int get_mem_technology(struct io96b_info *io96b_ctrl) +{ + struct io96b_mb_resp usr_resp; + int i, j; + u8 ddr_type_ret; + + /* Initialize ddr type */ + io96b_ctrl->ddr_type = ddr_type_list[6]; + + /* Get and ensure all memory interface(s) same DDR type */ + for (i = 0; i < io96b_ctrl->num_instance; i++) { + switch (i) { + case 0: + for (j = 0; j < io96b_ctrl->io96b_0.mb_ctrl.num_mem_interface; j++) { + io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr + , io96b_ctrl->io96b_0.mb_ctrl.ip_type[j] + , io96b_ctrl->io96b_0.mb_ctrl.ip_instance_id[j] + , CMD_GET_MEM_INFO, GET_MEM_TECHNOLOGY, 0, 0, 0, 0 + , 0, 0, 0, 0, &usr_resp); + + ddr_type_ret = + IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status) + & GENMASK(2, 0); + + if (!strcmp(io96b_ctrl->ddr_type, "UNKNOWN")) + io96b_ctrl->ddr_type = ddr_type_list[ddr_type_ret]; + + if (ddr_type_list[ddr_type_ret] != io96b_ctrl->ddr_type) { + printf("%s: Mismatch DDR type on IO96B_0\n", __func__); + return -ENOEXEC; + } + } + break; + case 1: + for (j = 0; j < io96b_ctrl->io96b_1.mb_ctrl.num_mem_interface; j++) { + io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr + , io96b_ctrl->io96b_1.mb_ctrl.ip_type[j] + , io96b_ctrl->io96b_1.mb_ctrl.ip_instance_id[j] + , CMD_GET_MEM_INFO, GET_MEM_TECHNOLOGY, 0, 0, 0, 0 + , 0, 0, 0, 0, &usr_resp); + + ddr_type_ret = + IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status) + & GENMASK(2, 0); + + if (!strcmp(io96b_ctrl->ddr_type, "UNKNOWN")) + io96b_ctrl->ddr_type = ddr_type_list[ddr_type_ret]; + + if (ddr_type_list[ddr_type_ret] != io96b_ctrl->ddr_type) { + printf("%s: Mismatch DDR type on IO96B_1\n", __func__); + return -ENOEXEC; + } + } + break; + } + } + + return 0; +} + +int get_mem_width_info(struct io96b_info *io96b_ctrl) +{ + struct io96b_mb_resp usr_resp; + int i, j; + u16 memory_size; + u16 total_memory_size = 0; + + /* Get all memory interface(s) total memory size on all instance(s) */ + for (i = 0; i < io96b_ctrl->num_instance; i++) { + switch (i) { + case 0: + memory_size = 0; + for (j = 0; j < io96b_ctrl->io96b_0.mb_ctrl.num_mem_interface; j++) { + io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr + , io96b_ctrl->io96b_0.mb_ctrl.ip_type[j] + , io96b_ctrl->io96b_0.mb_ctrl.ip_instance_id[j] + , CMD_GET_MEM_INFO, GET_MEM_WIDTH_INFO, 0, 0, 0, 0 + , 0, 0, 0, 2, &usr_resp); + + memory_size = memory_size + + (usr_resp.cmd_resp_data_1 & GENMASK(7, 0)); + } + + if (!memory_size) { + printf("%s: Failed to get valid memory size\n", __func__); + return -ENOEXEC; + } + + io96b_ctrl->io96b_0.size = memory_size; + + break; + case 1: + memory_size = 0; + for (j = 0; j < io96b_ctrl->io96b_1.mb_ctrl.num_mem_interface; j++) { + io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr + , io96b_ctrl->io96b_1.mb_ctrl.ip_type[j] + , io96b_ctrl->io96b_1.mb_ctrl.ip_instance_id[j] + , CMD_GET_MEM_INFO, GET_MEM_WIDTH_INFO, 0, 0, 0, 0 + , 0, 0, 0, 2, &usr_resp); + + memory_size = memory_size + + (usr_resp.cmd_resp_data_1 & GENMASK(7, 0)); + } + + if (!memory_size) { + printf("%s: Failed to get valid memory size\n", __func__); + return -ENOEXEC; + } + + io96b_ctrl->io96b_1.size = memory_size; + + break; + } + + total_memory_size = total_memory_size + memory_size; + } + + if (!total_memory_size) { + printf("%s: Failed to get valid memory size\n", __func__); + return -ENOEXEC; + } + + io96b_ctrl->overall_size = total_memory_size; + + return 0; +} + +int ecc_enable_status(struct io96b_info *io96b_ctrl) +{ + struct io96b_mb_resp usr_resp; + int i, j; + bool ecc_stat_set = false; + bool ecc_stat; + + /* Initialize ECC status */ + io96b_ctrl->ecc_status = false; + + /* Get and ensure all memory interface(s) same ECC status */ + for (i = 0; i < io96b_ctrl->num_instance; i++) { + switch (i) { + case 0: + for (j = 0; j < io96b_ctrl->io96b_0.mb_ctrl.num_mem_interface; j++) { + debug("%s: ECC_ENABLE_STATUS\n", __func__); + io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr + , io96b_ctrl->io96b_0.mb_ctrl.ip_type[j] + , io96b_ctrl->io96b_0.mb_ctrl.ip_instance_id[j] + , CMD_TRIG_CONTROLLER_OP, ECC_ENABLE_STATUS, 0, 0, 0 + , 0, 0, 0, 0, 0, &usr_resp); + + ecc_stat = ((IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status) + & GENMASK(1, 0)) == 0 ? false : true); + + if (!ecc_stat_set) { + io96b_ctrl->ecc_status = ecc_stat; + ecc_stat_set = true; + } + + if (ecc_stat != io96b_ctrl->ecc_status) { + printf("%s: Mismatch DDR ECC status on IO96B_0\n" + , __func__); + return -ENOEXEC; + } + } + break; + case 1: + for (j = 0; j < io96b_ctrl->io96b_1.mb_ctrl.num_mem_interface; j++) { + debug("%s: ECC_ENABLE_STATUS\n", __func__); + io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr + , io96b_ctrl->io96b_1.mb_ctrl.ip_type[j] + , io96b_ctrl->io96b_1.mb_ctrl.ip_instance_id[j] + , CMD_TRIG_CONTROLLER_OP, ECC_ENABLE_STATUS, 0, 0, 0 + , 0, 0, 0, 0, 0, &usr_resp); + + ecc_stat = ((IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status) + & GENMASK(1, 0)) == 0 ? false : true); + + if (!ecc_stat_set) { + io96b_ctrl->ecc_status = ecc_stat; + ecc_stat_set = true; + } + + if (ecc_stat != io96b_ctrl->ecc_status) { + printf("%s: Mismatch DDR ECC status on IO96B_1\n" + , __func__); + return -ENOEXEC; + } + } + break; + } + } + return 0; +} + +int bist_mem_init_start(struct io96b_info *io96b_ctrl) +{ + struct io96b_mb_resp usr_resp; + int i, j; + bool bist_start, bist_success; + u32 start; + + /* Full memory initialization BIST performed on all memory interface(s) */ + for (i = 0; i < io96b_ctrl->num_instance; i++) { + switch (i) { + case 0: + for (j = 0; j < io96b_ctrl->io96b_0.mb_ctrl.num_mem_interface; j++) { + bist_start = false; + bist_success = false; + + /* Start memory initialization BIST on full memory address */ + io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr + , io96b_ctrl->io96b_0.mb_ctrl.ip_type[j] + , io96b_ctrl->io96b_0.mb_ctrl.ip_instance_id[j] + , CMD_TRIG_CONTROLLER_OP, BIST_MEM_INIT_START, 0x40 + , 0, 0, 0, 0, 0, 0, 0, &usr_resp); + + bist_start = + (IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status) + & BIT(0)); + + if (!bist_start) { + printf("%s: Failed to initialized memory on IO96B_0\n" + , __func__); + printf("%s: BIST_MEM_INIT_START Error code 0x%x\n", __func__ + , (IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status) + & GENMASK(2, 1)) > 0x1); + return -ENOEXEC; + } + + /* Polling for the initiated memory initialization BIST status */ + start = get_timer(0); + while (!bist_success) { + io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr + , io96b_ctrl->io96b_0.mb_ctrl.ip_type[j] + , io96b_ctrl->io96b_0.mb_ctrl.ip_instance_id[j] + , CMD_TRIG_CONTROLLER_OP, BIST_MEM_INIT_STATUS, 0 + , 0, 0, 0, 0, 0, 0, 0, &usr_resp); + + bist_success = (IOSSM_CMD_RESPONSE_DATA_SHORT + (usr_resp.cmd_resp_status) & BIT(0)); + + if (!bist_success && (get_timer(start) > TIMEOUT)) { + printf("%s: Timeout initialize memory on IO96B_0\n" + , __func__); + printf("%s: BIST_MEM_INIT_STATUS Error code 0x%x\n" + , __func__, (IOSSM_CMD_RESPONSE_DATA_SHORT + (usr_resp.cmd_resp_status) + & GENMASK(2, 1)) > 0x1); + return -ETIMEDOUT; + } + + udelay(1); + } + } + + debug("%s: Memory initialized successfully on IO96B_0\n", __func__); + break; + case 1: + for (j = 0; j < io96b_ctrl->io96b_1.mb_ctrl.num_mem_interface; j++) { + bist_start = false; + bist_success = false; + + /* Start memory initialization BIST on full memory address */ + io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr + , io96b_ctrl->io96b_1.mb_ctrl.ip_type[j] + , io96b_ctrl->io96b_1.mb_ctrl.ip_instance_id[j] + , CMD_TRIG_CONTROLLER_OP, BIST_MEM_INIT_START, 0x40 + , 0, 0, 0, 0, 0, 0, 0, &usr_resp); + + bist_start = + (IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status) + & BIT(0)); + + if (!bist_start) { + printf("%s: Failed to initialized memory on IO96B_1\n" + , __func__); + printf("%s: BIST_MEM_INIT_START Error code 0x%x\n", __func__ + , (IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status) + & GENMASK(2, 1)) > 0x1); + return -ENOEXEC; + } + + /* Polling for the initiated memory initialization BIST status */ + start = get_timer(0); + while (!bist_success) { + io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr + , io96b_ctrl->io96b_1.mb_ctrl.ip_type[j] + , io96b_ctrl->io96b_1.mb_ctrl.ip_instance_id[j] + , CMD_TRIG_CONTROLLER_OP, BIST_MEM_INIT_STATUS, 0 + , 0, 0, 0, 0, 0, 0, 0, &usr_resp); + + bist_success = (IOSSM_CMD_RESPONSE_DATA_SHORT + (usr_resp.cmd_resp_status) & BIT(0)); + + if (!bist_success && (get_timer(start) > TIMEOUT)) { + printf("%s: Timeout initialize memory on IO96B_1\n" + , __func__); + printf("%s: BIST_MEM_INIT_STATUS Error code 0x%x\n" + , __func__, (IOSSM_CMD_RESPONSE_DATA_SHORT + (usr_resp.cmd_resp_status) + & GENMASK(2, 1)) > 0x1); + return -ETIMEDOUT; + } + + udelay(1); + } + } + + debug("%s: Memory initialized successfully on IO96B_1\n", __func__); + break; + } + } + return 0; +} diff --git a/drivers/ddr/altera/iossm_mailbox.h b/drivers/ddr/altera/iossm_mailbox.h new file mode 100644 index 0000000000..8c57126c3e --- /dev/null +++ b/drivers/ddr/altera/iossm_mailbox.h @@ -0,0 +1,141 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 Intel Corporation + */ + +#define TIMEOUT_10000MS 10000 +#define TIMEOUT TIMEOUT_10000MS +#define IOSSM_STATUS_CAL_SUCCESS BIT(0) +#define IOSSM_STATUS_CAL_FAIL BIT(1) +#define IOSSM_STATUS_CAL_BUSY BIT(2) +#define IOSSM_STATUS_COMMAND_RESPONSE_READY BIT(0) +#define IOSSM_CMD_RESPONSE_STATUS_OFFSET 0x45C +#define IOSSM_CMD_RESPONSE_DATA_0_OFFSET 0x458 +#define IOSSM_CMD_RESPONSE_DATA_1_OFFSET 0x454 +#define IOSSM_CMD_RESPONSE_DATA_2_OFFSET 0x450 +#define IOSSM_CMD_REQ_OFFSET 0x43C +#define IOSSM_CMD_PARAM_0_OFFSET 0x438 +#define IOSSM_CMD_PARAM_1_OFFSET 0x434 +#define IOSSM_CMD_PARAM_2_OFFSET 0x430 +#define IOSSM_CMD_PARAM_3_OFFSET 0x42C +#define IOSSM_CMD_PARAM_4_OFFSET 0x428 +#define IOSSM_CMD_PARAM_5_OFFSET 0x424 +#define IOSSM_CMD_PARAM_6_OFFSET 0x420 +#define IOSSM_STATUS_OFFSET 0x400 +#define IOSSM_CMD_RESPONSE_DATA_SHORT_MASK GENMASK(31, 16) +#define IOSSM_CMD_RESPONSE_DATA_SHORT(data) (((data) & IOSSM_CMD_RESPONSE_DATA_SHORT_MASK) >> 16) +#define MAX_IO96B_SUPPORTED 2 +#define MAX_MEM_INTERFACES_SUPPORTED 2 + +/* supported mailbox command type */ +enum iossm_mailbox_cmd_type { + CMD_NOP, + CMD_GET_SYS_INFO, + CMD_GET_MEM_INFO, + CMD_GET_MEM_CAL_INFO, + CMD_TRIG_CONTROLLER_OP, + CMD_TRIG_MEM_CAL_OP +}; + +/* supported mailbox command opcode */ +enum iossm_mailbox_cmd_opcode { + GET_MEM_INTF_INFO = 0x0001, + GET_MEM_TECHNOLOGY, + GET_MEMCLK_FREQ_KHZ, + GET_MEM_WIDTH_INFO, + ECC_ENABLE_SET = 0x0101, + ECC_ENABLE_STATUS, + ECC_INTERRUPT_STATUS, + ECC_INTERRUPT_ACK, + ECC_INTERRUPT_MASK, + ECC_WRITEBACK_ENABLE, + ECC_SCRUB_IN_PROGRESS_STATUS = 0x0201, + ECC_SCRUB_MODE_0_START, + ECC_SCRUB_MODE_1_START, + BIST_STANDARD_MODE_START = 0x0301, + BIST_RESULTS_STATUS, + BIST_MEM_INIT_START, + BIST_MEM_INIT_STATUS, + BIST_SET_DATA_PATTERN_UPPER, + BIST_SET_DATA_PATTERN_LOWER, + TRIG_MEM_CAL = 0x000a, + GET_MEM_CAL_STATUS +}; + +/* + * IOSSM mailbox required information + * + * @num_mem_interface: Number of memory interfaces instantiated + * @ip_type: IP type implemented on the IO96B + * @ip_instance_id: IP identifier for every IP instance implemented on the IO96B + */ +struct io96b_mb_ctrl { + u32 num_mem_interface; + u32 ip_type[2]; + u32 ip_instance_id[2]; +}; + +/* + * IOSSM mailbox response outputs + * + * @cmd_resp_status: Command Interface status + * @cmd_resp_data_*: More spaces for command response + */ +struct io96b_mb_resp { + u32 cmd_resp_status; + u32 cmd_resp_data_0; + u32 cmd_resp_data_1; + u32 cmd_resp_data_2; +}; + +/* + * IO96B instance specific information + * + * @size: Memory size + * @io96b_csr_addr: IO96B instance CSR address + * @cal_status: IO96B instance calibration status + * @mb_ctrl: IOSSM mailbox required information + */ +struct io96b_instance { + u16 size; + phys_addr_t io96b_csr_addr; + bool cal_status; + struct io96b_mb_ctrl mb_ctrl; +}; + +/* + * Overall IO96B instance(s) information + * + * @num_instance: Number of instance(s) assigned to HPS + * @overall_cal_status: Overall calibration status for all IO96B instance(s) + * @ddr_type: DDR memory type + * @ecc_status: ECC enable status (false = disabled, true = enabled) + * @overall_size: Total DDR memory size + * @io96b_0: IO96B 0 instance specific information + * @io96b_1: IO96B 1 instance specific information + */ +struct io96b_info { + u8 num_instance; + bool overall_cal_status; + const char *ddr_type; + bool ecc_status; + u16 overall_size; + struct io96b_instance io96b_0; + struct io96b_instance io96b_1; +}; + +int io96b_mb_req(phys_addr_t io96b_csr_addr, u32 ip_type, u32 instance_id + , u32 usr_cmd_type, u32 usr_cmd_opcode, u32 cmd_param_0 + , u32 cmd_param_1, u32 cmd_param_2, u32 cmd_param_3, u32 cmd_param_4 + , u32 cmd_param_5, u32 cmd_param_6, u32 resp_data_len + , struct io96b_mb_resp *resp); + +/* Supported IOSSM mailbox function */ +void io96b_mb_init(struct io96b_info *io96b_ctrl); +int io96b_cal_status(phys_addr_t addr); +void init_mem_cal(struct io96b_info *io96b_ctrl); +int trig_mem_cal(struct io96b_info *io96b_ctrl); +int get_mem_technology(struct io96b_info *io96b_ctrl); +int get_mem_width_info(struct io96b_info *io96b_ctrl); +int ecc_enable_status(struct io96b_info *io96b_ctrl); +int bist_mem_init_start(struct io96b_info *io96b_ctrl); diff --git a/drivers/ddr/altera/sdram_agilex5.c b/drivers/ddr/altera/sdram_agilex5.c new file mode 100644 index 0000000000..e8e3f258b9 --- /dev/null +++ b/drivers/ddr/altera/sdram_agilex5.c @@ -0,0 +1,329 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019-2023 Intel Corporation + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "iossm_mailbox.h" +#include "sdram_soc64.h" +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +/* MPFE NOC registers */ +#define F2SDRAM_SIDEBAND_FLAGOUTSET0 0x50 +#define F2SDRAM_SIDEBAND_FLAGOUTSTATUS0 0x58 +#define SIDEBANDMGR_FLAGOUTSET0_REG SOCFPGA_F2SDRAM_MGR_ADDRESS +\ + F2SDRAM_SIDEBAND_FLAGOUTSET0 +#define SIDEBANDMGR_FLAGOUTSTATUS0_REG SOCFPGA_F2SDRAM_MGR_ADDRESS +\ + F2SDRAM_SIDEBAND_FLAGOUTSTATUS0 + +/* Reset type */ +enum reset_type { + POR_RESET, + WARM_RESET, + COLD_RESET, + NCONFIG, + JTAG_CONFIG, + RSU_RECONFIG +}; + +static enum reset_type get_reset_type(u32 reg) +{ + return (reg & ALT_SYSMGR_SCRATCH_REG_3_DDR_RESET_TYPE_MASK) >> + ALT_SYSMGR_SCRATCH_REG_3_DDR_RESET_TYPE_SHIFT; +} + +int set_mpfe_config(void) +{ + /* Set mpfe_lite_active */ + setbits_le32(socfpga_get_sysmgr_addr() + SYSMGR_SOC64_MPFE_CONFIG, BIT(8)); + + debug("%s: mpfe_config: 0x%x\n", __func__, + readl(socfpga_get_sysmgr_addr() + SYSMGR_SOC64_MPFE_CONFIG)); + + return 0; +} + +bool is_ddr_init_hang(void) +{ + u32 reg = readl(socfpga_get_sysmgr_addr() + + SYSMGR_SOC64_BOOT_SCRATCH_POR0); + + if (reg & ALT_SYSMGR_SCRATCH_REG_POR_0_DDR_PROGRESS_MASK) + return true; + + return false; +} + +void ddr_init_inprogress(bool start) +{ + if (start) + setbits_le32(socfpga_get_sysmgr_addr() + + SYSMGR_SOC64_BOOT_SCRATCH_POR0, + ALT_SYSMGR_SCRATCH_REG_POR_0_DDR_PROGRESS_MASK); + else + clrbits_le32(socfpga_get_sysmgr_addr() + + SYSMGR_SOC64_BOOT_SCRATCH_POR0, + ALT_SYSMGR_SCRATCH_REG_POR_0_DDR_PROGRESS_MASK); +} + +int populate_ddr_handoff(struct udevice *dev, struct io96b_info *io96b_ctrl) +{ + struct altera_sdram_plat *plat = dev_get_plat(dev); + fdt_addr_t addr; + int i; + u32 len = SOC64_HANDOFF_SDRAM_LEN; + u32 handoff_table[len]; + + /* Read handoff for DDR configuration */ + socfpga_handoff_read((void *)SOC64_HANDOFF_SDRAM, handoff_table, len); + + /* Read handoff - dual port */ + plat->dualport = handoff_table[0] & BIT(0); + debug("%s: dualport from handoff: 0x%x\n", __func__, plat->dualport); + + /* Read handoff - dual EMIF */ + plat->dualemif = handoff_table[0] & BIT(1); + debug("%s: dualemif from handoff: 0x%x\n", __func__, plat->dualemif); + + if (plat->dualemif) + io96b_ctrl->num_instance = 2; + else + io96b_ctrl->num_instance = 1; + + /* Assign IO96B CSR base address if it is valid */ + for (i = 0; i < io96b_ctrl->num_instance; i++) { + addr = dev_read_addr_index(dev, i + 1); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + switch (i) { + case 0: + io96b_ctrl->io96b_0.io96b_csr_addr = addr; + debug("%s: IO96B 0x%llx CSR enabled\n", __func__ + , io96b_ctrl->io96b_0.io96b_csr_addr); + break; + case 1: + io96b_ctrl->io96b_1.io96b_csr_addr = addr; + debug("%s: IO96B 0x%llx CSR enabled\n", __func__ + , io96b_ctrl->io96b_1.io96b_csr_addr); + break; + default: + printf("%s: Invalid IO96B CSR\n", __func__); + } + } + + return 0; +} + +int config_mpfe_sideband_mgr(struct udevice *dev) +{ + struct altera_sdram_plat *plat = dev_get_plat(dev); + + /* Dual port setting */ + if (plat->dualport) + setbits_le32(SIDEBANDMGR_FLAGOUTSET0_REG, BIT(4)); + + /* Dual EMIF setting */ + if (plat->dualemif) { + set_mpfe_config(); + setbits_le32(SIDEBANDMGR_FLAGOUTSET0_REG, BIT(5)); + } + + debug("%s: SIDEBANDMGR_FLAGOUTSTATUS0: 0x%x\n", __func__, + readl(SIDEBANDMGR_FLAGOUTSTATUS0_REG)); + + return 0; +} + +bool hps_ocram_dbe_status(void) +{ + u32 reg = readl(socfpga_get_sysmgr_addr() + + SYSMGR_SOC64_BOOT_SCRATCH_COLD3); + + if (reg & ALT_SYSMGR_SCRATCH_REG_3_OCRAM_DBE_MASK) + return true; + + return false; +} + +bool ddr_ecc_dbe_status(void) +{ + u32 reg = readl(socfpga_get_sysmgr_addr() + + SYSMGR_SOC64_BOOT_SCRATCH_COLD3); + + if (reg & ALT_SYSMGR_SCRATCH_REG_3_DDR_DBE_MASK) + return true; + + return false; +} + +int sdram_mmr_init_full(struct udevice *dev) +{ + int ret; + phys_size_t hw_size; + struct bd_info bd = {0}; + struct altera_sdram_plat *plat = dev_get_plat(dev); + struct altera_sdram_priv *priv = dev_get_priv(dev); + struct io96b_info *io96b_ctrl = malloc(sizeof(*io96b_ctrl)); + + u32 reg = readl(socfpga_get_sysmgr_addr() + SYSMGR_SOC64_BOOT_SCRATCH_COLD3); + enum reset_type reset_t = get_reset_type(reg); + bool full_mem_init = false; + + /* DDR initialization progress status tracking */ + bool is_ddr_hang_be4_rst = is_ddr_init_hang(); + + debug("DDR: SDRAM init in progress ...\n"); + ddr_init_inprogress(true); + + debug("DDR: Address MPFE 0x%llx\n", plat->mpfe_base_addr); + + /* Populating DDR handoff data */ + debug("DDR: Checking SDRAM configuration in progress ...\n"); + ret = populate_ddr_handoff(dev, io96b_ctrl); + if (ret) { + printf("DDR: Failed to populate DDR handoff\n"); + free(io96b_ctrl); + return ret; + } + + /* Configuring MPFE sideband manager registers - dual port & dual emif*/ + ret = config_mpfe_sideband_mgr(dev); + if (ret) { + printf("DDR: Failed to configure dual port dual emif\n"); + free(io96b_ctrl); + return ret; + } + + /* Ensure calibration status passing */ + init_mem_cal(io96b_ctrl); + + /* Initiate IOSSM mailbox */ + io96b_mb_init(io96b_ctrl); + + /* Need to trigger re-calibration for DDR DBE */ + if (ddr_ecc_dbe_status()) { + io96b_ctrl->io96b_0.cal_status = false; + io96b_ctrl->io96b_1.cal_status = false; + io96b_ctrl->overall_cal_status = io96b_ctrl->io96b_0.cal_status || + io96b_ctrl->io96b_1.cal_status; + } + + /* Trigger re-calibration if calibration failed */ + if (!(io96b_ctrl->overall_cal_status)) { + printf("DDR: Re-calibration in progress...\n"); + trig_mem_cal(io96b_ctrl); + } + + printf("DDR: Calibration success\n"); + + /* DDR type, DDR size and ECC status) */ + ret = get_mem_technology(io96b_ctrl); + if (ret) { + printf("DDR: Failed to get DDR type\n"); + free(io96b_ctrl); + return ret; + } + + ret = get_mem_width_info(io96b_ctrl); + if (ret) { + printf("DDR: Failed to get DDR size\n"); + free(io96b_ctrl); + return ret; + } + + hw_size = (phys_size_t)io96b_ctrl->overall_size * SZ_1G / SZ_8; + + /* Get bank configuration from devicetree */ + ret = fdtdec_decode_ram_size(gd->fdt_blob, NULL, 0, NULL, + (phys_size_t *)&gd->ram_size, &bd); + if (ret) { + puts("DDR: Failed to decode memory node\n"); + free(io96b_ctrl); + return -ENXIO; + } + + if (gd->ram_size != hw_size) { + printf("DDR: Warning: DRAM size from device tree (%lld MiB)\n", + gd->ram_size >> 20); + printf(" mismatch with hardware (%lld MiB).\n", + hw_size >> 20); + } + + if (gd->ram_size > hw_size) { + printf("DDR: Error: DRAM size from device tree is greater\n"); + printf(" than hardware size.\n"); + hang(); + } + + printf("%s: %lld MiB\n", io96b_ctrl->ddr_type, gd->ram_size >> 20); + + ret = ecc_enable_status(io96b_ctrl); + if (ret) { + printf("DDR: Failed to get DDR ECC status\n"); + free(io96b_ctrl); + return ret; + } + + /* Is HPS cold or warm reset? If yes, Skip full memory initialization if ECC + * enabled to preserve memory content + */ + if (io96b_ctrl->ecc_status) { + full_mem_init = hps_ocram_dbe_status() | ddr_ecc_dbe_status() | + is_ddr_hang_be4_rst; + if (full_mem_init || !(reset_t == WARM_RESET || reset_t == COLD_RESET)) { + ret = bist_mem_init_start(io96b_ctrl); + if (ret) { + printf("DDR: Failed to fully initialize DDR memory\n"); + free(io96b_ctrl); + return ret; + } + } + + printf("SDRAM-ECC: Initialized success\n"); + } + + sdram_size_check(&bd); + printf("DDR: size check success\n"); + + sdram_set_firewall(&bd); + + /* Firewall setting for MPFE CSR */ + /* IO96B0_reg */ + writel(0x1, 0x18000d00); + /* IO96B1_reg */ + writel(0x1, 0x18000d04); + /* noc_csr */ + writel(0x1, 0x18000d08); + + printf("DDR: firewall init success\n"); + + priv->info.base = bd.bi_dram[0].start; + priv->info.size = gd->ram_size; + + /* Ending DDR driver initialization success tracking */ + ddr_init_inprogress(false); + + printf("DDR: init success\n"); + + free(io96b_ctrl); + + return 0; +} diff --git a/drivers/ddr/altera/sdram_soc64.c b/drivers/ddr/altera/sdram_soc64.c index 4716abfc9a..0fee07fcaf 100644 --- a/drivers/ddr/altera/sdram_soc64.c +++ b/drivers/ddr/altera/sdram_soc64.c @@ -28,6 +28,7 @@ #define PGTABLE_OFF 0x4000 +#if !IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX5) u32 hmc_readl(struct altera_sdram_plat *plat, u32 reg) { return readl(plat->iomhc + reg); @@ -99,8 +100,9 @@ int emif_reset(struct altera_sdram_plat *plat) debug("DDR: %s triggered successly\n", __func__); return 0; } +#endif -#if !IS_ENABLED(CONFIG_TARGET_SOCFPGA_N5X) +#if !(IS_ENABLED(CONFIG_TARGET_SOCFPGA_N5X) || IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX5)) int poll_hmc_clock_status(void) { return wait_for_bit_le32((const void *)(socfpga_get_sysmgr_addr() + @@ -246,13 +248,13 @@ phys_size_t sdram_calculate_size(struct altera_sdram_plat *plat) DRAMADDRW_CFG_ROW_ADDR_WIDTH(dramaddrw) + DRAMADDRW_CFG_COL_ADDR_WIDTH(dramaddrw)); - size *= (2 << (hmc_ecc_readl(plat, DDRIOCTRL) & + size *= ((phys_size_t)2 << (hmc_ecc_readl(plat, DDRIOCTRL) & DDR_HMC_DDRIOCTRL_IOSIZE_MSK)); return size; } -void sdram_set_firewall(struct bd_info *bd) +static void sdram_set_firewall_non_f2sdram(struct bd_info *bd) { u32 i; phys_size_t value; @@ -288,7 +290,7 @@ void sdram_set_firewall(struct bd_info *bd) FW_MPU_DDR_SCR_NONMPUREGION0ADDR_BASEEXT + (i * 4 * sizeof(u32))); - /* Setting non-secure MPU limit and limit extexded */ + /* Setting non-secure MPU limit and limit extended */ value = bd->bi_dram[i].start + bd->bi_dram[i].size - 1; lower = lower_32_bits(value); @@ -301,7 +303,7 @@ void sdram_set_firewall(struct bd_info *bd) FW_MPU_DDR_SCR_MPUREGION0ADDR_LIMITEXT + (i * 4 * sizeof(u32))); - /* Setting non-secure Non-MPU limit and limit extexded */ + /* Setting non-secure Non-MPU limit and limit extended */ FW_MPU_DDR_SCR_WRITEL(lower, FW_MPU_DDR_SCR_NONMPUREGION0ADDR_LIMIT + (i * 4 * sizeof(u32))); @@ -314,6 +316,60 @@ void sdram_set_firewall(struct bd_info *bd) } } +static void sdram_set_firewall_f2sdram(struct bd_info *bd) +{ + u32 i; + phys_size_t value; + u32 lower, upper; + + for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { + if (!bd->bi_dram[i].size) + continue; + + value = bd->bi_dram[i].start; + + /* Keep first 1MB of SDRAM memory region as secure region when + * using ATF flow, where the ATF code is located. + */ + if (IS_ENABLED(CONFIG_SPL_ATF) && i == 0) + value += SZ_1M; + + /* Setting base and base extended */ + lower = lower_32_bits(value); + upper = upper_32_bits(value); + FW_F2SDRAM_DDR_SCR_WRITEL(lower, + FW_F2SDRAM_DDR_SCR_REGION0ADDR_BASE + + (i * 4 * sizeof(u32))); + FW_F2SDRAM_DDR_SCR_WRITEL(upper & 0xff, + FW_F2SDRAM_DDR_SCR_REGION0ADDR_BASEEXT + + (i * 4 * sizeof(u32))); + + /* Setting limit and limit extended */ + value = bd->bi_dram[i].start + bd->bi_dram[i].size - 1; + + lower = lower_32_bits(value); + upper = upper_32_bits(value); + + FW_F2SDRAM_DDR_SCR_WRITEL(lower, + FW_F2SDRAM_DDR_SCR_REGION0ADDR_LIMIT + + (i * 4 * sizeof(u32))); + FW_F2SDRAM_DDR_SCR_WRITEL(upper & 0xff, + FW_F2SDRAM_DDR_SCR_REGION0ADDR_LIMITEXT + + (i * 4 * sizeof(u32))); + + FW_F2SDRAM_DDR_SCR_WRITEL(BIT(i), FW_F2SDRAM_DDR_SCR_EN_SET); + } +} + +void sdram_set_firewall(struct bd_info *bd) +{ + sdram_set_firewall_non_f2sdram(bd); + +#if IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX5) + sdram_set_firewall_f2sdram(bd); +#endif +} + static int altera_sdram_of_to_plat(struct udevice *dev) { struct altera_sdram_plat *plat = dev_get_plat(dev); @@ -322,7 +378,12 @@ static int altera_sdram_of_to_plat(struct udevice *dev) /* These regs info are part of DDR handoff in bitstream */ #if IS_ENABLED(CONFIG_TARGET_SOCFPGA_N5X) return 0; -#endif +#elif IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX5) + addr = dev_read_addr_index(dev, 0); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + plat->mpfe_base_addr = addr; +#else addr = dev_read_addr_index(dev, 0); if (addr == FDT_ADDR_T_NONE) @@ -338,15 +399,15 @@ static int altera_sdram_of_to_plat(struct udevice *dev) if (addr == FDT_ADDR_T_NONE) return -EINVAL; plat->hmc = (void __iomem *)addr; - +#endif return 0; } static int altera_sdram_probe(struct udevice *dev) { - int ret; struct altera_sdram_priv *priv = dev_get_priv(dev); + int ret; ret = reset_get_bulk(dev, &priv->resets); if (ret) { dev_err(dev, "Can't get reset: %d\n", ret); @@ -385,6 +446,7 @@ static const struct udevice_id altera_sdram_ids[] = { { .compatible = "altr,sdr-ctl-s10" }, { .compatible = "intel,sdr-ctl-agilex" }, { .compatible = "intel,sdr-ctl-n5x" }, + { .compatible = "intel,sdr-ctl-agilex5" }, { /* sentinel */ } }; diff --git a/drivers/ddr/altera/sdram_soc64.h b/drivers/ddr/altera/sdram_soc64.h index 07a0f9f2ae..c96025f8b1 100644 --- a/drivers/ddr/altera/sdram_soc64.h +++ b/drivers/ddr/altera/sdram_soc64.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * Copyright (C) 2017-2019 Intel Corporation + * Copyright (C) 2017-2022 Intel Corporation */ #ifndef _SDRAM_SOC64_H_ @@ -14,11 +14,20 @@ struct altera_sdram_priv { struct reset_ctl_bulk resets; }; +#if IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX5) +struct altera_sdram_plat { + fdt_addr_t mpfe_base_addr; + bool dualport; + bool dualemif; +}; +#else + struct altera_sdram_plat { void __iomem *hmc; void __iomem *ddr_sch; void __iomem *iomhc; }; +#endif /* ECC HMC registers */ #define DDRIOCTRL 0x8 @@ -39,6 +48,8 @@ struct altera_sdram_plat { #define RSTHANDSHAKESTAT 0x218 #define DDR_HMC_DDRIOCTRL_IOSIZE_MSK 0x00000003 +#define DDR_HMC_DDRIOCTRL_MPFE_HMCA_DATA_RATE_MSK BIT(2) +#define DDR_HMC_DDRIOCTRL_MPFE_HMCA_DATA_RATE_SHIFT 2 #define DDR_HMC_DDRCALSTAT_CAL_MSK BIT(0) #define DDR_HMC_ECCCTL_AWB_CNT_RST_SET_MSK BIT(16) #define DDR_HMC_ECCCTL_CNT_RST_SET_MSK BIT(8) @@ -66,6 +77,7 @@ struct altera_sdram_plat { #define CTRLCFG0 0x28 #define CTRLCFG1 0x2c #define CTRLCFG3 0x34 +#define CTRLCFG5 0x3c #define DRAMTIMING0 0x50 #define CALTIMING0 0x7c #define CALTIMING1 0x80 @@ -79,6 +91,9 @@ struct altera_sdram_plat { #define NIOSRESERVED1 0x114 #define NIOSRESERVED2 0x118 +#define CTRLCFG3_CFG_CTRL_CMD_RATE_QUARTER BIT(2) +#define CTRLCFG5_CFG_CTRL_RC_EN_MASK BIT(8) + #define DRAMADDRW_CFG_COL_ADDR_WIDTH(x) \ (((x) >> 0) & 0x1F) #define DRAMADDRW_CFG_ROW_ADDR_WIDTH(x) \