[PATCH 1/1] am65x_gp_evm: Support for ECC DDR with DMA priming

Ben Roytburd BRoytburd at relativityspace.com
Sat May 27 00:39:14 CEST 2023


>From e019ed98623c8c8388bef3082002d27d5ec9de40 Mon Sep 17 00:00:00 2001
From: broytburd <broytburd at relativityspace.com>
Date: Fri, 26 May 2023 09:14:14 -0700
Subject: [PATCH 1/1] am65x_gp_evm: Support for ECC DDR with DMA priming

Add support for configuring DDR4 memory on AM65x_GP_EVM SR1.0 with
ECC. Add register writes and memory priming function for
DDR initialization. Priming done using dma_memcpy from MSMC SRAM, bugfix
required for k3 udma driver to prevent dereferencing a null pointer
within unprimed DDR space.

Signed-off-by: broytburd <broytburd at relativityspace.com>
Cc: Tom Rini <trini at konsulko.com>
---
arch/arm/dts/k3-am654-base-board.dts |  5 +-
drivers/dma/ti/k3-udma.c             |  9 +++-
drivers/ram/k3-am654-ddrss.c         | 74 +++++++++++++++++++++++++++-
3 files changed, 81 insertions(+), 7 deletions(-)

diff --git a/arch/arm/dts/k3-am654-base-board.dts b/arch/arm/dts/k3-am654-base-board.dts
index cfbcebfa37..bd54c84359 100644
--- a/arch/arm/dts/k3-am654-base-board.dts
+++ b/arch/arm/dts/k3-am654-base-board.dts
@@ -20,9 +20,8 @@

               memory at 80000000 {
                             device_type = "memory";
-                             /* 4G RAM */
-                             reg = <0x00000000 0x80000000 0x00000000 0x80000000>,
-                                   <0x00000008 0x80000000 0x00000000 0x80000000>;
+                            /* 2G RAM */
+                            reg = <0x00000000 0x80000000 0x00000000 0x80000000>;
              };

               reserved-memory {
diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c
index 05c3a4311c..461162ab6c 100644
--- a/drivers/dma/ti/k3-udma.c
+++ b/drivers/dma/ti/k3-udma.c
@@ -1044,8 +1044,8 @@ static int udma_alloc_tchan_sci_req(struct udma_chan *uc)
static int udma_alloc_rchan_sci_req(struct udma_chan *uc)
{
              struct udma_dev *ud = uc->ud;
-              int fd_ring = k3_nav_ringacc_get_ring_id(uc->rflow->fd_ring);
-              int rx_ring = k3_nav_ringacc_get_ring_id(uc->rflow->r_ring);
+             int fd_ring = 0;
+             int rx_ring = 0;
              int tc_ring = k3_nav_ringacc_get_ring_id(uc->tchan->tc_ring);
              struct ti_sci_msg_rm_udmap_rx_ch_cfg req = { 0 };
              struct ti_sci_msg_rm_udmap_flow_cfg flow_req = { 0 };
@@ -1053,6 +1053,11 @@ static int udma_alloc_rchan_sci_req(struct udma_chan *uc)
              u32 mode;
              int ret;

+             if (!uc->rflow) {
+                            fd_ring = k3_nav_ringacc_get_ring_id(uc->rflow->fd_ring);
+                            rx_ring = k3_nav_ringacc_get_ring_id(uc->rflow->r_ring);
+             }
+
              if (uc->config.pkt_mode)
                             mode = TI_SCI_RM_UDMAP_CHAN_TYPE_PKT_PBRR;
              else
diff --git a/drivers/ram/k3-am654-ddrss.c b/drivers/ram/k3-am654-ddrss.c
index b8338f84a3..6f28cb856f 100644
--- a/drivers/ram/k3-am654-ddrss.c
+++ b/drivers/ram/k3-am654-ddrss.c
@@ -9,6 +9,7 @@
#include <common.h>
#include <clk.h>
#include <dm.h>
+#include <dma.h>
#include <log.h>
#include <ram.h>
#include <asm/io.h>
@@ -24,7 +25,20 @@ u32 wait_on_value(u32 read_bit_mask, u32 match_value, void *read_addr,
#define LDELAY 10000

 /* DDRSS PHY configuration register fixed values */
-#define DDRSS_DDRPHY_RANKIDR_RANK0          0
+#define DDRSS_DDRPHY_RANKIDR_RANK0 0x00000000
+#define DDRSS_DDRPHY_RANKIDR_RANK1 0x00010001
+
+/* Amount of DDR we wish to prime */
+#define DATA_BYTES 0x80000000
+
+/* Amount of MSMC memory we will use to prime */
+#define MSMC_BYTES 0x20000000
+
+/* Base address of DDR */
+static u32 *ddr_ptr = (uint32_t *)0x80000000;
+
+/* Base address of MSMC */
+static u32 *msmc_ptr = (uint32_t *)0x60000000;

 /**
  * struct am654_ddrss_desc - Description of ddrss integration.
@@ -49,6 +63,15 @@ struct am654_ddrss_desc {
              struct ddrss_params params;
};

+/**
+ * am654_prime_ecc(struct am654_ddrss_desc *ddrss) - Prime ECC
+ *
+ * Write a specified pattern to our entire DDR so that ECC timing
+ * parameters can be calibrated
+ *
+ */
+static int am654_prime_ecc(struct am654_ddrss_desc *ddrss);
+
static inline u32 ddrss_readl(void __iomem *addr, unsigned int offset)
{
              return readl(addr + offset);
@@ -172,6 +195,11 @@ static void am654_ddrss_ctrl_configuration(struct am654_ddrss_desc *ddrss)
              ddrss_ctl_writel(DDRSS_DDRCTL_ADDRMAP10, map->ddrctl_addrmap10);
              ddrss_ctl_writel(DDRSS_DDRCTL_ADDRMAP11, map->ddrctl_addrmap11);

+             ddrss_ctl_writel(DDRSS_DDRCTL_DQMAP0, map->ddrctl_dqmap0);
+             ddrss_ctl_writel(DDRSS_DDRCTL_DQMAP1, map->ddrctl_dqmap1);
+             ddrss_ctl_writel(DDRSS_DDRCTL_DQMAP4, map->ddrctl_dqmap4);
+             ddrss_ctl_writel(DDRSS_DDRCTL_DQMAP5, map->ddrctl_dqmap5);
+
              ddrss_ctl_writel(DDRSS_DDRCTL_ODTCFG, reg->ddrctl_odtcfg);
              ddrss_ctl_writel(DDRSS_DDRCTL_ODTMAP, reg->ddrctl_odtmap);

@@ -287,12 +315,14 @@ static void am654_ddrss_phy_configuration(struct am654_ddrss_desc *ddrss)
              ddrss_phy_writel(DDRSS_DDRPHY_DX1GCR4, cfg->ddrphy_dx1gcr4);
              ddrss_phy_writel(DDRSS_DDRPHY_DX2GCR4, cfg->ddrphy_dx2gcr4);
              ddrss_phy_writel(DDRSS_DDRPHY_DX3GCR4, cfg->ddrphy_dx3gcr4);
+             ddrss_phy_writel(DDRSS_DDRPHY_DX4GCR4, cfg->ddrphy_dx4gcr4);

               ddrss_phy_writel(DDRSS_DDRPHY_PGCR5, cfg->ddrphy_pgcr5);
              ddrss_phy_writel(DDRSS_DDRPHY_DX0GCR5, cfg->ddrphy_dx0gcr5);
              ddrss_phy_writel(DDRSS_DDRPHY_DX1GCR5, cfg->ddrphy_dx1gcr5);
              ddrss_phy_writel(DDRSS_DDRPHY_DX2GCR5, cfg->ddrphy_dx2gcr5);
              ddrss_phy_writel(DDRSS_DDRPHY_DX3GCR5, cfg->ddrphy_dx3gcr5);
+             ddrss_phy_writel(DDRSS_DDRPHY_DX4GCR5, cfg->ddrphy_dx4gcr5);

               ddrss_phy_writel(DDRSS_DDRPHY_RANKIDR, DDRSS_DDRPHY_RANKIDR_RANK0);

@@ -300,6 +330,16 @@ static void am654_ddrss_phy_configuration(struct am654_ddrss_desc *ddrss)
              ddrss_phy_writel(DDRSS_DDRPHY_DX1GTR0, cfg->ddrphy_dx1gtr0);
              ddrss_phy_writel(DDRSS_DDRPHY_DX2GTR0, cfg->ddrphy_dx2gtr0);
              ddrss_phy_writel(DDRSS_DDRPHY_DX3GTR0, cfg->ddrphy_dx3gtr0);
+             ddrss_phy_writel(DDRSS_DDRPHY_DX4GTR0, cfg->ddrphy_dx4gtr0);
+             ddrss_phy_writel(DDRSS_DDRPHY_ODTCR, cfg->ddrphy_odtcr);
+
+             ddrss_phy_writel(DDRSS_DDRPHY_RANKIDR, DDRSS_DDRPHY_RANKIDR_RANK1);
+
+             ddrss_phy_writel(DDRSS_DDRPHY_DX0GTR0, cfg->ddrphy_dx0gtr0);
+             ddrss_phy_writel(DDRSS_DDRPHY_DX1GTR0, cfg->ddrphy_dx1gtr0);
+             ddrss_phy_writel(DDRSS_DDRPHY_DX2GTR0, cfg->ddrphy_dx2gtr0);
+             ddrss_phy_writel(DDRSS_DDRPHY_DX3GTR0, cfg->ddrphy_dx3gtr0);
+             ddrss_phy_writel(DDRSS_DDRPHY_DX4GTR0, cfg->ddrphy_dx4gtr0);
              ddrss_phy_writel(DDRSS_DDRPHY_ODTCR, cfg->ddrphy_odtcr);

               ddrss_phy_writel(DDRSS_DDRPHY_DX8SL0IOCR, cfg->ddrphy_dx8sl0iocr);
@@ -543,13 +583,14 @@ int disable_dqs_pd(struct am654_ddrss_desc *ddrss)
int cleanup_training(struct am654_ddrss_desc *ddrss)
{
              u32 val;
-              u32 dgsl0, dgsl1, dgsl2, dgsl3, rddly, rd2wr_wr2rd;
+             u32 dgsl0, dgsl1, dgsl2, dgsl3, dgsl4, rddly, rd2wr_wr2rd;

               ddrss_phy_writel(DDRSS_DDRPHY_RANKIDR, 0x00000000);
              dgsl0 = (ddrss_phy_readl(DDRSS_DDRPHY_DX0GTR0) & 0x1F) >> 2;
              dgsl1 = (ddrss_phy_readl(DDRSS_DDRPHY_DX1GTR0) & 0x1F) >> 2;
              dgsl2 = (ddrss_phy_readl(DDRSS_DDRPHY_DX2GTR0) & 0x1F) >> 2;
              dgsl3 = (ddrss_phy_readl(DDRSS_DDRPHY_DX3GTR0) & 0x1F) >> 2;
+             dgsl4 = (ddrss_phy_readl(DDRSS_DDRPHY_DX4GTR0) & 0x1F) >> 2;

               rddly = dgsl0;
              if (dgsl1 < rddly)
@@ -558,6 +599,8 @@ int cleanup_training(struct am654_ddrss_desc *ddrss)
                             rddly = dgsl2;
              if (dgsl3 < rddly)
                             rddly = dgsl3;
+             if (dgsl4 < rddly)
+                            rddly = dgsl4;

               rddly += 5;

@@ -578,6 +621,10 @@ int cleanup_training(struct am654_ddrss_desc *ddrss)
              val |= (rddly << 20);
              ddrss_phy_writel(DDRSS_DDRPHY_DX3GCR0, val);

+             val = (ddrss_phy_readl(DDRSS_DDRPHY_DX4GCR0) & ~0xF00000);
+             val |= (rddly << 20);
+             ddrss_phy_writel(DDRSS_DDRPHY_DX4GCR0, val);
+
              /*
               * Add system latency derived from training back into rd2wr and wr2rd
               * rd2wr = RL + BL/2 + 1 + WR_PREAMBLE - WL + max(DXnGTR0.DGSL) / 2
@@ -591,6 +638,7 @@ int cleanup_training(struct am654_ddrss_desc *ddrss)
              dgsl1 = (ddrss_phy_readl(DDRSS_DDRPHY_DX1GTR0) & 0x1F);
              dgsl2 = (ddrss_phy_readl(DDRSS_DDRPHY_DX2GTR0) & 0x1F);
              dgsl3 = (ddrss_phy_readl(DDRSS_DDRPHY_DX3GTR0) & 0x1F);
+             dgsl4 = (ddrss_phy_readl(DDRSS_DDRPHY_DX4GTR0) & 0x1F);

               /* Find maximum value across all bytes */
              rd2wr_wr2rd = dgsl0;
@@ -600,6 +648,8 @@ int cleanup_training(struct am654_ddrss_desc *ddrss)
                             rd2wr_wr2rd = dgsl2;
              if (dgsl3 > rd2wr_wr2rd)
                             rd2wr_wr2rd = dgsl3;
+             if (dgsl4 > rd2wr_wr2rd)
+                            rd2wr_wr2rd = dgsl4;

               rd2wr_wr2rd >>= 1;

@@ -1071,6 +1121,10 @@ static int am654_ddrss_probe(struct udevice *dev)

               ret = am654_ddrss_init(ddrss);

+             // Only prime ECC if it is enabled
+             if (ddrss_ctl_readl(DDRSS_DDRCTL_ECCCFG0) & 0x4)
+                            ret = am654_prime_ecc(ddrss);
+
              return ret;
}

@@ -1096,3 +1150,19 @@ U_BOOT_DRIVER(am654_ddrss) = {
              .probe = am654_ddrss_probe,
              .priv_auto           = sizeof(struct am654_ddrss_desc),
};
+
+static int am654_prime_ecc(struct am654_ddrss_desc *ddrss)
+{
+             int ret;
+
+             // Use MSMC memory to prime DDR memory
+             for (int i = 0; i < (DATA_BYTES / MSMC_BYTES); i++) {
+                            ret = dma_memcpy(ddr_ptr + ((MSMC_BYTES / 4) * i), msmc_ptr, MSMC_BYTES);
+                            if (ret) {
+                                           dev_err(ddrss->dev, "DDR prime DMA Memcpy failed %d\n", ret);
+                                           return ret;
+                            }
+             }
+
+             return ret;
+}
--
2.25.1



More information about the U-Boot mailing list