Re: [PATCH v4 05/10] ram: cadence: add driver for Cadence EDAC
On Mon, Apr 17, 2023 at 07:32:30PM +0200, Marek Vasut wrote: On 3/8/23 21:26, Ralph Siemsen wrote: [...] +#define FUNCCTRL 0x00 +#define FUNCCTRL_MASKSDLOFS (0x18 << 16) +#define FUNCCTRL_DVDDQ_1_5V (1 << 8) +#define FUNCCTRL_RESET_N (1 << 0) +#define DLLCTRL0x04 +#define DLLCTRL_ASDLLOCK (1 << 26) +#define DLLCTRL_MFSL_500MHz (2 << 1) +#define DLLCTRL_MDLLSTBY (1 << 0) Use BIT() macro where applicable. Will do. + /* DDR PHY setup */ + phy_writel(DLLCTRL_MFSL_500MHz | DLLCTRL_MDLLSTBY, DLLCTRL); + phy_writel(0x0182, ZQCALCTRL); + if (ddr_type == RZN1_DDR3_DUAL_BANK) + phy_writel(0xAB330031, ZQODTCTRL); + else if (ddr_type == RZN1_DDR3_SINGLE_BANK) + phy_writel(0xAB320051, ZQODTCTRL); + else /* DDR2 */ + phy_writel(0xAB330071, ZQODTCTRL); + phy_writel(0xB545B544, RDCTRL); + phy_writel(0x00B0, RDTMG); + phy_writel(0x020A0806, OUTCTRL); + if (ddr_type == RZN1_DDR3_DUAL_BANK) + phy_writel(0x80005556, WLCTRL1); + else + phy_writel(0x80005C5D, WLCTRL1); + phy_writel(0x0101, FIFOINIT); + phy_writel(0x4545, DQCALOFS1); Is there any macro which defines those magic bits in magic numbers ? If so, please use them. This init sequence came from the u-boot 2017 repo published by Renesas. There do not appear to be any macros to help with all these magic numbers. + /* DDR Controller is always in ASYNC mode */ + cdns_ddr_ctrl_init((void *)RZN1_DDR_BASE, 1, + ddr_00_87_async, ddr_350_374_async, + ddr_start_addr, CFG_SYS_SDRAM_SIZE, + priv->enable_ecc, priv->enable_8bit); + + rzn1_ddr3_single_bank((void *)RZN1_DDR_BASE); Can you obtain the DRAM base from DT ? I'll check if it is possible. + priv->syscon = syscon_regmap_lookup_by_phandle(dev, "syscon"); + if (IS_ERR(priv->syscon)) { + dev_err(dev, "No syscon node found\n"); + //return PTR_ERR(priv->syscon); This shouldn't be commented out, right ? Does indeed look like an oversight. I'll fix it up, thanks for spotting! Ralph
Re: [PATCH v4 05/10] ram: cadence: add driver for Cadence EDAC
On 3/8/23 21:26, Ralph Siemsen wrote: [...] +#define FUNCCTRL 0x00 +#define FUNCCTRL_MASKSDLOFS (0x18 << 16) +#define FUNCCTRL_DVDDQ_1_5V (1 << 8) +#define FUNCCTRL_RESET_N (1 << 0) +#define DLLCTRL0x04 +#define DLLCTRL_ASDLLOCK (1 << 26) +#define DLLCTRL_MFSL_500MHz (2 << 1) +#define DLLCTRL_MDLLSTBY (1 << 0) Use BIT() macro where applicable. +#define ZQCALCTRL 0x08 +#define ZQCALCTRL_ZQCALEND(1 << 30) +#define ZQCALCTRL_ZQCALRSTB (1 << 0) +#define ZQODTCTRL 0x0c +#define RDCTRL 0x10 +#define RDTMG 0x14 +#define FIFOINIT 0x18 +#define FIFOINIT_RDPTINITEXE (1 << 8) +#define FIFOINIT_WRPTINITEXE (1 << 0) +#define OUTCTRL0x1c +#define OUTCTRL_ADCMDOE (1 << 0) +#define WLCTRL10x40 +#define WLCTRL1_WLSTR (1 << 24) +#define DQCALOFS1 0xe8 + +/* DDR PHY setup */ +void ddr_phy_init(struct cadence_ddr_info *priv, int ddr_type) +{ + u32 val; + + /* Disable DDR Controller clock and FlexWAY connection */ + clk_disable(&priv->hclk_ddrc); + clk_disable(&priv->clk_ddrc); + + clk_rzn1_reset_state(&priv->hclk_ddrc, 0); + clk_rzn1_reset_state(&priv->clk_ddrc, 0); + + /* Enable DDR Controller clock and FlexWAY connection */ + clk_enable(&priv->clk_ddrc); + clk_enable(&priv->hclk_ddrc); + + /* DDR PHY Soft reset assert */ + ddrc_writel(FUNCCTRL_MASKSDLOFS | FUNCCTRL_DVDDQ_1_5V, FUNCCTRL); + + clk_rzn1_reset_state(&priv->hclk_ddrc, 1); + clk_rzn1_reset_state(&priv->clk_ddrc, 1); + + /* DDR PHY setup */ + phy_writel(DLLCTRL_MFSL_500MHz | DLLCTRL_MDLLSTBY, DLLCTRL); + phy_writel(0x0182, ZQCALCTRL); + if (ddr_type == RZN1_DDR3_DUAL_BANK) + phy_writel(0xAB330031, ZQODTCTRL); + else if (ddr_type == RZN1_DDR3_SINGLE_BANK) + phy_writel(0xAB320051, ZQODTCTRL); + else /* DDR2 */ + phy_writel(0xAB330071, ZQODTCTRL); + phy_writel(0xB545B544, RDCTRL); + phy_writel(0x00B0, RDTMG); + phy_writel(0x020A0806, OUTCTRL); + if (ddr_type == RZN1_DDR3_DUAL_BANK) + phy_writel(0x80005556, WLCTRL1); + else + phy_writel(0x80005C5D, WLCTRL1); + phy_writel(0x0101, FIFOINIT); + phy_writel(0x4545, DQCALOFS1); Is there any macro which defines those magic bits in magic numbers ? If so, please use them. + /* Step 9 MDLL reset release */ + val = phy_readl(DLLCTRL); + val &= ~DLLCTRL_MDLLSTBY; + phy_writel(val, DLLCTRL); + + /* Step 12 Soft reset release */ + val = phy_readl(FUNCCTRL); + val |= FUNCCTRL_RESET_N; + phy_writel(val, FUNCCTRL); + + /* Step 13 FIFO pointer initialize */ + phy_writel(FIFOINIT_RDPTINITEXE | FIFOINIT_WRPTINITEXE, FIFOINIT); + + /* Step 14 Execute ZQ Calibration */ + val = phy_readl(ZQCALCTRL); + val |= ZQCALCTRL_ZQCALRSTB; + phy_writel(val, ZQCALCTRL); + + /* Step 15 Wait for 200us or more, or wait for DFIINITCOMPLETE to be "1" */ + while (!(phy_readl(DLLCTRL) & DLLCTRL_ASDLLOCK)) + ; + while (!(phy_readl(ZQCALCTRL) & ZQCALCTRL_ZQCALEND)) + ; + + /* Step 16 Enable Address and Command output */ + val = phy_readl(OUTCTRL); + val |= OUTCTRL_ADCMDOE; + phy_writel(val, OUTCTRL); + + /* Step 17 Wait for 200us or more(from MRESETB=0) */ + udelay(200); +} [...] +int rzn1_dram_init(struct cadence_ddr_info *priv) +{ + u32 version; + u32 ddr_start_addr = 0; + + ddr_phy_init(priv, RZN1_DDR3_SINGLE_BANK); + + /* +* Override DDR PHY Interface (DFI) related settings +* DFI is the internal interface between the DDR controller and the DDR PHY. +* These settings are specific to the board and can't be known by the settings +* provided for each DDR model within the generated include. +*/ + ddr_350_374_async[351 - 350] = 0x001e; + ddr_350_374_async[352 - 350] = 0x1e68; + ddr_350_374_async[353 - 350] = 0x0220; + ddr_350_374_async[354 - 350] = 0x02000200; + ddr_350_374_async[355 - 350] = 0x0c30; + ddr_350_374_async[356 - 350] = 0x9808; + ddr_350_374_async[357 - 350] = 0x020a0706; + ddr_350_374_async[372 - 350] = 0x0100; + + /* +* On ES1.0 devices, the DDR start address that the DDR Controller sees +* is the physical address of the DDR. However, later devices changed it +* to be 0 in order to fix an issue with DDR out-of-range detection. +*/ +#define RZN1_SYSCTRL_REG_VERSION 412 + regmap_read(priv->syscon, RZN1_SYSCTRL_REG_VERSION, &version); + if (version == 0x10) + ddr_start_addr = RZN1_V_DDR_BASE; + + /* DDR Controller is always in ASYNC mode */ + cdns_ddr_ctrl_init((void *)RZN1_DDR_B
[PATCH v4 05/10] ram: cadence: add driver for Cadence EDAC
Driver for Cadence EDAC DDR controller, as found in the Renesas RZ/N1. Signed-off-by: Ralph Siemsen --- (no changes since v3) Changes in v3: - assorted small cleanups - support version 1.0 silicon (previously #if 0...) drivers/ram/Kconfig | 1 + drivers/ram/Makefile| 2 + drivers/ram/cadence/Kconfig | 12 + drivers/ram/cadence/Makefile| 1 + drivers/ram/cadence/ddr_async.c | 311 drivers/ram/cadence/ddr_ctrl.c | 414 drivers/ram/cadence/ddr_ctrl.h | 175 ++ 7 files changed, 916 insertions(+) create mode 100644 drivers/ram/cadence/Kconfig create mode 100644 drivers/ram/cadence/Makefile create mode 100644 drivers/ram/cadence/ddr_async.c create mode 100644 drivers/ram/cadence/ddr_ctrl.c create mode 100644 drivers/ram/cadence/ddr_ctrl.h diff --git a/drivers/ram/Kconfig b/drivers/ram/Kconfig index e085119963..2b6d8f1c7b 100644 --- a/drivers/ram/Kconfig +++ b/drivers/ram/Kconfig @@ -108,6 +108,7 @@ config IMXRT_SDRAM This driver is for the sdram memory interface with the SEMC. source "drivers/ram/aspeed/Kconfig" +source "drivers/ram/cadence/Kconfig" source "drivers/ram/rockchip/Kconfig" source "drivers/ram/sifive/Kconfig" source "drivers/ram/stm32mp1/Kconfig" diff --git a/drivers/ram/Makefile b/drivers/ram/Makefile index 83948e2c43..e2d5e730d1 100644 --- a/drivers/ram/Makefile +++ b/drivers/ram/Makefile @@ -22,3 +22,5 @@ obj-$(CONFIG_IMXRT_SDRAM) += imxrt_sdram.o obj-$(CONFIG_RAM_SIFIVE) += sifive/ obj-$(CONFIG_ARCH_OCTEON) += octeon/ + +obj-$(CONFIG_CADENCE_DDR_CTRL) += cadence/ diff --git a/drivers/ram/cadence/Kconfig b/drivers/ram/cadence/Kconfig new file mode 100644 index 00..2d5469cb8e --- /dev/null +++ b/drivers/ram/cadence/Kconfig @@ -0,0 +1,12 @@ +if RAM || SPL_RAM + +config CADENCE_DDR_CTRL + bool "Enable Cadence DDR controller" + depends on DM + help + Enable support for Cadence DDR controller, as found on + the Renesas RZ/N1 SoC. This controller has a large number + of registers which need to be programmed, mostly using values + obtained from Denali SOMA files via a TCL script. + +endif diff --git a/drivers/ram/cadence/Makefile b/drivers/ram/cadence/Makefile new file mode 100644 index 00..16c7fe8488 --- /dev/null +++ b/drivers/ram/cadence/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_CADENCE_DDR_CTRL) += ddr_async.o ddr_ctrl.o diff --git a/drivers/ram/cadence/ddr_async.c b/drivers/ram/cadence/ddr_async.c new file mode 100644 index 00..444eeb8ac7 --- /dev/null +++ b/drivers/ram/cadence/ddr_async.c @@ -0,0 +1,311 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * RZ/N1 DDR Controller initialisation + * + * The DDR Controller register values for a specific DDR device, mode and + * frequency are generated using a Cadence tool. + * + * Copyright (C) 2015 Renesas Electronics Europe Ltd + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ddr_ctrl.h" + +void clk_rzn1_reset_state(struct clk *clk, int on); + +extern u32 ddr_00_87_async[]; +extern u32 ddr_350_374_async[]; + +DECLARE_GLOBAL_DATA_PTR; + +struct cadence_ddr_info { + struct udevice *dev; + void __iomem *ddrc; + void __iomem *phy; + struct clk clk_ddrc; + struct clk hclk_ddrc; + struct regmap *syscon; + bool enable_ecc; + bool enable_8bit; +}; + +static inline u32 cadence_readl(void __iomem *addr, unsigned int offset) +{ + return readl(addr + offset); +} + +static inline void cadence_writel(void __iomem *addr, unsigned int offset, + u32 data) +{ + debug("%s: addr = 0x%p, value = 0x%08x\n", __func__, addr + offset, data); + writel(data, addr + offset); +} + +#define ddrc_readl(off)cadence_readl(priv->ddrc, off) +#define ddrc_writel(val, off) cadence_writel(priv->ddrc, off, val) + +#define phy_readl(off) cadence_readl(priv->phy, off) +#define phy_writel(val, off) cadence_writel(priv->phy, off, val) + +#define RZN1_DDR3_SINGLE_BANK 3 +#define RZN1_DDR3_DUAL_BANK 32 + +#define FUNCCTRL 0x00 +#define FUNCCTRL_MASKSDLOFS (0x18 << 16) +#define FUNCCTRL_DVDDQ_1_5V (1 << 8) +#define FUNCCTRL_RESET_N (1 << 0) +#define DLLCTRL0x04 +#define DLLCTRL_ASDLLOCK (1 << 26) +#define DLLCTRL_MFSL_500MHz (2 << 1) +#define DLLCTRL_MDLLSTBY (1 << 0) +#define ZQCALCTRL 0x08 +#define ZQCALCTRL_ZQCALEND(1 << 30) +#define ZQCALCTRL_ZQCALRSTB (1 << 0) +#define ZQODTCTRL 0x0c +#define RDCTRL 0x10 +#define RDTMG 0x14 +#define FIFOINIT 0x18 +#define FIFOINIT_RDPTINITEXE (1 << 8) +#define FIFOINIT_WRPTINITEXE (1 << 0) +#define OUTCTRL0x1c +#define OUTCTRL_ADCMDOE (1 << 0) +#define WLCTRL10x40 +#define WLCTRL1_WLSTR (1 << 24) +#define DQCALOFS1 0x