[PATCH v4 05/10] ram: cadence: add driver for Cadence EDAC

Marek Vasut marek.vasut at mailbox.org
Mon Apr 17 19:32:30 CEST 2023


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 DLLCTRL		0x04
> +#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 OUTCTRL		0x1c
> +#define  OUTCTRL_ADCMDOE	(1 << 0)
> +#define WLCTRL1		0x40
> +#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(0x00000182, 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(0x000000B0, RDTMG);
> +	phy_writel(0x020A0806, OUTCTRL);
> +	if (ddr_type == RZN1_DDR3_DUAL_BANK)
> +		phy_writel(0x80005556, WLCTRL1);
> +	else
> +		phy_writel(0x80005C5D, WLCTRL1);
> +	phy_writel(0x00000101, FIFOINIT);
> +	phy_writel(0x00004545, 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] = 0x001e0000;
> +	ddr_350_374_async[352 - 350] = 0x1e680000;
> +	ddr_350_374_async[353 - 350] = 0x02000020;
> +	ddr_350_374_async[354 - 350] = 0x02000200;
> +	ddr_350_374_async[355 - 350] = 0x00000c30;
> +	ddr_350_374_async[356 - 350] = 0x00009808;
> +	ddr_350_374_async[357 - 350] = 0x020a0706;
> +	ddr_350_374_async[372 - 350] = 0x01000000;
> +
> +	/*
> +	 * 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_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 ?

> +	cdns_ddr_set_diff_cs_delays((void *)RZN1_DDR_BASE, 2, 7, 2, 2);
> +	cdns_ddr_set_same_cs_delays((void *)RZN1_DDR_BASE, 0, 7, 0, 0);
> +	cdns_ddr_set_odt_times((void *)RZN1_DDR_BASE, 5, 6, 6, 0, 4);
> +	cdns_ddr_ctrl_start((void *)RZN1_DDR_BASE);
> +
> +	ddr_phy_enable_wl(priv);
> +
> +	if (priv->enable_ecc) {
> +		/*
> +		 * Any read before a write will trigger an ECC un-correctable error,
> +		 * causing a data abort. However, this is also true for any read with a
> +		 * size less than the AXI bus width. So, the only sensible solution is
> +		 * to write to all of DDR now and take the hit...
> +		 */
> +		memset((void *)RZN1_V_DDR_BASE, 0xff, CFG_SYS_SDRAM_SIZE);
> +	}
> +
> +	return 0;
> +}
> +
> +static int cadence_ddr_get_info(struct udevice *udev, struct ram_info *info)
> +{
> +	info->base = 0;
> +	info->size = gd->ram_size;
> +
> +	return 0;
> +}
> +
> +static struct ram_ops cadence_ddr_ops = {
> +	.get_info = cadence_ddr_get_info,
> +};
> +
> +static int cadence_ddr_probe(struct udevice *dev)
> +{
> +	struct cadence_ddr_info *priv = dev_get_priv(dev);
> +	int ret;
> +
> +	priv->ddrc = dev_remap_addr_name(dev, "ddrc");
> +	if (!priv->ddrc) {
> +		dev_err(dev, "No reg property for Cadence DDR CTRL\n");
> +		return -EINVAL;
> +	}
> +
> +	priv->phy = dev_remap_addr_name(dev, "phy");
> +	if (!priv->phy) {
> +		dev_err(dev, "No reg property for Cadence DDR PHY\n");
> +		return -EINVAL;
> +	}
> +
> +	ret = clk_get_by_name(dev, "clk_ddrc", &priv->clk_ddrc);
> +	if (ret) {
> +		dev_err(dev, "No clock for Cadence DDR\n");
> +		return ret;
> +	}
> +
> +	ret = clk_get_by_name(dev, "hclk_ddrc", &priv->hclk_ddrc);
> +	if (ret) {
> +		dev_err(dev, "No HCLK for Cadence DDR\n");
> +		return ret;
> +	}
> +
> +	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 ?

> +	}
> +
> +	priv->enable_ecc = dev_read_bool(dev, "enable-ecc");
> +	priv->enable_8bit = dev_read_bool(dev, "enable-8bit");
> +
> +	rzn1_dram_init(priv);
> +
> +	return 0;
> +}
> +
> +static const struct udevice_id cadence_ddr_ids[] = {
> +	{ .compatible = "cadence,ddr-ctrl" },
> +	{ }
> +};
> +
> +U_BOOT_DRIVER(cadence_ddr) = {
> +	.name		= "cadence_ddr",
> +	.id		= UCLASS_RAM,
> +	.of_match	= cadence_ddr_ids,
> +	.ops		= &cadence_ddr_ops,
> +	.probe		= cadence_ddr_probe,
> +	.priv_auto	= sizeof(struct cadence_ddr_info),
> +	.flags		= DM_FLAG_PRE_RELOC,
> +};

[...]


More information about the U-Boot mailing list