ram: renesas: dbsc5: Add Renesas R-Car Gen5 DBSC5 driver

Add Renesas R-Car Gen5 DBSC5 DRAM controller driver. This driver is currently
capable of bringing LPDDR5X DRAM on Renesas R-Car X5H Ironhide board. Further
boards can be supported by supplying board specific DRAM configuration data
via dbsc5_get_board_data().

The driver reuses parts of previous DBSC5 driver, but due to hardware changes,
can not be fully integrated into existing DBSC and DRAM driver, therefore the
currentl DBSC and DRAM drivers are moved into R8A779G0 V4H specific files, and
the R8A78000 X5H files are added in parallel.

The Gen5 DBSC driver is meant to be used in RSIP context, while the Gen4 DBSC
driver is meant to be used in SPL, therefore the Kconfig conditionals have been
adjusted to match.

Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
This commit is contained in:
Marek Vasut
2026-06-16 05:38:25 +02:00
parent 93e5ca9261
commit a06d8334e5
15 changed files with 10518 additions and 14 deletions
+1 -1
View File
@@ -5,7 +5,7 @@
#include <asm/io.h>
#include <compiler.h>
#include <dbsc5.h>
#include <r8a779g0-dbsc5.h>
#include <spi.h>
#include <spi_flash.h>
#include <spl.h>
+3 -3
View File
@@ -1,7 +1,7 @@
config RAM_RENESAS_DBSC5
bool "Renesas R-Car V4H/V4M DBSC5 controller driver"
depends on SPL && RAM && (R8A779G0 || R8A779H0)
bool "Renesas R-Car V4H/V4M/X5H DBSC5 controller driver"
depends on RAM && (R8A78000 || (SPL && (R8A779G0 || R8A779H0)))
default n
help
Enable this to support the DBSC5 DRAM controller initialization
on Renesas R8A779G0/R8A779H0 SoCs.
on Renesas R8A779G0/R8A779H0/R8A78000 SoCs.
-2
View File
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0+
ifdef CONFIG_XPL_BUILD
obj-$(CONFIG_RAM_RENESAS_DBSC5) += dbsc5/
endif
obj-$(CONFIG_RZN1) += rzn1/
+3 -1
View File
@@ -1,3 +1,5 @@
# SPDX-License-Identifier: GPL-2.0+
obj-y += dbsc5.o dram.o qos.o rtvram.o
obj-$(CONFIG_R8A779G0) += r8a779g0-dbsc5.o r8a779g0-dram.o qos.o
obj-$(CONFIG_R8A78000) += r8a78000-dbsc5.o r8a78000-dram.o ecc.o
obj-y += rtvram.o
+168
View File
@@ -0,0 +1,168 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2026 Renesas Electronics Corp.
*/
#include <asm/io.h>
#include <dm.h>
#include <errno.h>
#include <ram.h>
#include <linux/sizes.h>
#define DBSC5_DBSC_CNT 8
#define DBSC_D_BASE(n) (0xe9900000 + ((n) * 0x4000))
#define DBSC_A_BASE(n) (0xe9800000 + ((n) * 0x8000))
#define DBSYSCNT 0x100
#define DBACEN 0x200
#define DBFSINTENB02A 0x7088
#define DBFSINTENB04A 0x7090
#define DBFSCONFAXI0 0x7400
#define DBFSDRAMECCAREA00 0x7450
#define DBFSCTRL01A 0x7604
#define DBFSCONF00A 0x7640
#define DBFSCONF01A 0x7644
#define DBFSCONF02A 0x7648
#define DBFSSTAT00A 0x7680
#define DBFSSTAT01A 0x7684
#define DBSYSCNT_ENABLE 0x1234
#define DBSYSCNT_DISABLE 0x0
#define DBACEN_ACCESS_DISABLE 0
#define DBACEN_ACCESS_ENABLE 1
#define ECM_BASE 0xb89a0000
#define ECMERRCTLR0 (ECM_BASE + 0x0)
#define ECMERRINCR0 (ECM_BASE + 0x200)
#define ECMERROMKR0 (ECM_BASE + 0x600)
#define ECMERRCTLR6 (ECM_BASE + (0x4 * 6))
#define ECMERRINCR6 (ECM_BASE + 0x200U + (0x4 * 6))
#define ECMERROMKR6 (ECM_BASE + 0x600U + (0x4 * 6))
#define ECMWPCNTR (ECM_BASE + 0xa00)
#define ECMWACNTR (ECM_BASE + 0xa04)
struct renesas_dbsc5_ecc_priv {
void __iomem *regs;
};
static void ecm_reg_unlock(void)
{
writel(0xacce0001, ECMWPCNTR);
}
static void ecm_reg_lock(void)
{
writel(0xacce0000, ECMWPCNTR);
}
static void ecm_reg_write(u32 adr, u32 val)
{
writel(0xacce0000 | (adr & 0xffff), ECMWACNTR);
writel(val, adr);
}
static int renesas_dbsc5_ecc_probe(struct udevice *dev)
{
int i;
ecm_reg_unlock();
for (i = 0; i < DBSC5_DBSC_CNT; i++) {
writel(DBSYSCNT_ENABLE, DBSC_D_BASE(i) + DBSYSCNT);
writel(DBSYSCNT_ENABLE, DBSC_A_BASE(i) + DBSYSCNT);
}
ecm_reg_write(ECMERRINCR0, readl(ECMERRINCR0) | 0xAAA);
ecm_reg_write(ECMERROMKR0, readl(ECMERROMKR0) | 0xAAA);
ecm_reg_write(ECMERRCTLR0, readl(ECMERRCTLR0) | 0xAAA);
ecm_reg_write(ECMERRINCR6, readl(ECMERRINCR6) | 0xA000);
ecm_reg_write(ECMERROMKR6, readl(ECMERROMKR6) | 0xA000);
ecm_reg_write(ECMERRCTLR6, readl(ECMERRCTLR6) | 0xA000);
for (i = 0; i < DBSC5_DBSC_CNT; i++)
writel(0xcccc, DBSC_A_BASE(i) + DBFSDRAMECCAREA00);
for (i = 0; i < DBSC5_DBSC_CNT; i++)
writel(DBACEN_ACCESS_DISABLE, DBSC_A_BASE(i) + DBACEN);
for (i = 0; i < DBSC5_DBSC_CNT; i++)
writel(0, DBSC_A_BASE(i) + DBFSCONF00A);
for (i = 0; i < DBSC5_DBSC_CNT; i++)
writel(0, DBSC_A_BASE(i) + DBFSCONF01A);
for (i = 0; i < DBSC5_DBSC_CNT; i++)
writel(0xcccb, DBSC_A_BASE(i) + DBFSCONF02A);
for (i = 0; i < DBSC5_DBSC_CNT; i++)
writel(0x1, DBSC_A_BASE(i) + DBFSCTRL01A);
u32 fsstat;
do {
fsstat = 0x1;
for (i = 0; i < DBSC5_DBSC_CNT; i++)
fsstat &= readl(DBSC_A_BASE(i) + DBFSSTAT01A);
} while (!(fsstat & 0x1));
for (i = 0; i < DBSC5_DBSC_CNT; i++)
writel(DBACEN_ACCESS_ENABLE, DBSC_A_BASE(i) + DBACEN);
for (i = 0; i < DBSC5_DBSC_CNT; i++)
setbits_le32(DBSC_A_BASE(i) + DBFSCONFAXI0, 0x100);
for (i = 0; i < DBSC5_DBSC_CNT; i++)
writel(0xff00ff00, DBSC_A_BASE(i) + DBFSINTENB02A);
for (i = 0; i < DBSC5_DBSC_CNT; i++)
writel(0xffffffff, DBSC_A_BASE(i) + DBFSINTENB04A);
ecm_reg_lock();
for (i = 0; i < DBSC5_DBSC_CNT; i++) {
writel(DBSYSCNT_DISABLE, DBSC_D_BASE(i) + DBSYSCNT);
writel(DBSYSCNT_DISABLE, DBSC_A_BASE(i) + DBSYSCNT);
}
return 0;
}
static int renesas_dbsc5_ecc_of_to_plat(struct udevice *dev)
{
struct renesas_dbsc5_ecc_priv *priv = dev_get_priv(dev);
priv->regs = dev_read_addr_ptr(dev);
if (!priv->regs)
return -EINVAL;
return 0;
}
static int renesas_dbsc5_ecc_get_info(struct udevice *dev,
struct ram_info *info)
{
struct renesas_dbsc5_ecc_priv *priv = dev_get_priv(dev);
info->base = (phys_addr_t)priv->regs;
info->size = 32 * SZ_1M;
return 0;
}
static const struct ram_ops renesas_dbsc5_ecc_ops = {
.get_info = renesas_dbsc5_ecc_get_info,
};
static const struct udevice_id renesas_dbsc5_ecc_ids[] = {
{ .compatible = "renesas,r8a78000-ecc" },
{ /* sentinel */ }
};
U_BOOT_DRIVER(renesas_dbsc5_ecc) = {
.name = "dbsc5_ecc",
.id = UCLASS_RAM,
.of_match = renesas_dbsc5_ecc_ids,
.of_to_plat = renesas_dbsc5_ecc_of_to_plat,
.ops = &renesas_dbsc5_ecc_ops,
.probe = renesas_dbsc5_ecc_probe,
.priv_auto = sizeof(struct renesas_dbsc5_ecc_priv),
};
+1 -1
View File
@@ -9,7 +9,7 @@
#include <hang.h>
#include <linux/sizes.h>
#include <ram.h>
#include "dbsc5.h"
#include "r8a779g0-dbsc5.h"
/* AXMM */
#define AXMM_ADSPLCR0 0x4008
@@ -10,7 +10,7 @@
#include <errno.h>
#include <linux/sizes.h>
#include <ram.h>
#include "dbsc5.h"
#include "r8a779g0-dbsc5.h"
static int renesas_dbsc5_probe(struct udevice *dev)
{
@@ -3,8 +3,8 @@
* Copyright (C) 2024 Renesas Electronics Corp.
*/
#ifndef __DRIVERS_RAM_RENESAS_DBSC5_DBSC5_H__
#define __DRIVERS_RAM_RENESAS_DBSC5_DBSC5_H__
#ifndef __DRIVERS_RAM_RENESAS_DBSC5_R8A779G0_DBSC5_H__
#define __DRIVERS_RAM_RENESAS_DBSC5_R8A779G0_DBSC5_H__
/*
* DBSC5 ... 0xe678_0000..0xe67fffff
@@ -26,4 +26,4 @@ struct renesas_dbsc5_data {
const char *otp_node;
};
#endif /* __DRIVERS_RAM_RENESAS_DBSC5_DBSC5_H__ */
#endif /* __DRIVERS_RAM_RENESAS_DBSC5_R8A779G0_DBSC5_H__ */
@@ -4,14 +4,14 @@
*/
#include <asm/io.h>
#include <dbsc5.h>
#include <r8a779g0-dbsc5.h>
#include <dm.h>
#include <errno.h>
#include <hang.h>
#include <ram.h>
#include <linux/iopoll.h>
#include <linux/sizes.h>
#include "dbsc5.h"
#include "r8a779g0-dbsc5.h"
/* Number of array elements in Data Slice */
#define DDR_PHY_SLICE_REGSET_SIZE_V4H 0x100
@@ -0,0 +1,76 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2026 Renesas Electronics Corp.
*
* Portions Copyright (C) 2026 Synopsys, Inc. Used with permission. All rights reserved.
*/
#include <asm/io.h>
#include <dm.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <errno.h>
#include <linux/sizes.h>
#include <ram.h>
#include "r8a78000-dbsc5.h"
static int renesas_dbsc5_probe(struct udevice *dev)
{
struct udevice *ddev, *vdev, *edev;
int ret;
ret = uclass_get_device_by_name(UCLASS_RAM, "dbsc5_dram", &ddev);
if (ret)
return ret;
ret = uclass_get_device_by_name(UCLASS_RAM, "ram@b8940000", &vdev);
if (ret)
return ret;
ret = uclass_get_device_by_name(UCLASS_RAM, "dbsc5_ecc", &edev);
if (ret)
return ret;
return 0;
}
int renesas_dbsc5_bind(struct udevice *dev)
{
struct udevice *ramdev, *eccdev;
struct driver *ramdrv, *eccdrv;
int ret;
ramdrv = lists_driver_lookup_name("dbsc5_dram");
if (!ramdrv)
return -ENOENT;
eccdrv = lists_driver_lookup_name("dbsc5_ecc");
if (!eccdrv)
return -ENOENT;
ret = device_bind_with_driver_data(dev, ramdrv, "dbsc5_dram",
dev_get_driver_data(dev),
dev_ofnode(dev), &ramdev);
if (ret)
return ret;
ret = device_bind_with_driver_data(dev, eccdrv, "dbsc5_ecc", 0,
dev_ofnode(dev), &eccdev);
if (ret)
device_unbind(ramdev);
return ret;
}
static const struct udevice_id renesas_dbsc5_ids[] = {
{ .compatible = "renesas,r8a78000-dbsc", },
{ /* sentinel */ }
};
U_BOOT_DRIVER(renesas_dbsc5) = {
.name = "dbsc5",
.id = UCLASS_NOP,
.of_match = renesas_dbsc5_ids,
.bind = renesas_dbsc5_bind,
.probe = renesas_dbsc5_probe,
};
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2026 Renesas Electronics Corp.
*
* Portions Copyright (C) 2026 Synopsys, Inc. Used with permission. All rights reserved.
*/
#ifndef __DRIVERS_RAM_RENESAS_DBSC5_R8A78000_DBSC5_H__
#define __DRIVERS_RAM_RENESAS_DBSC5_R8A78000_DBSC5_H__
struct renesas_dbsc5_data {
const char *clock_node;
const char *reset_node;
const char *otp_node;
};
#endif /* __DRIVERS_RAM_RENESAS_DBSC5_R8A78000_DBSC5_H__ */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+63
View File
@@ -0,0 +1,63 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2026 Renesas Electronics Corp.
*
* Portions Copyright (C) 2026 Synopsys, Inc. Used with permission. All rights reserved.
*/
#ifndef __INCLUDE_DBSC5_H__
#define __INCLUDE_DBSC5_H__
/* The number of channels X5H has */
#define DRAM_CH_CNT 16
/* The number of slices X5H has */
#define SLICE_CNT 2
/* The number of chip select X5H has */
#define CS_CNT 2
struct renesas_dbsc5_board_config {
u32 bdcfg_phyvalid;
u32 bdcfg_tx_drv;
u32 bdcfg_tx_ffc;
u32 bdcfg_rx_odt;
u8 bdcfg_rx_dfe;
u8 bdcfg_tx_odt;
u8 bdcfg_tx_ntodt;
u8 bdcfg_tx_dfe;
u8 bdcfg_rx_dca;
u8 bdcfg_rx_drv;
u32 bdcfg_rx_emphasis;
u8 bdcfg_tx_dca;
u8 bdcfg_ca_vref;
u32 bdcfg_rx_vref;
u32 bdcfg_rx_vref_step;
u32 bdcfg_tx_vref;
u8 bdcfg_rfm_chk;
/* Board parameter about channels */
struct {
/*
* 0x00: 4Gb dual channel die / 2Gb single channel die
* 0x01: 6Gb dual channel die / 3Gb single channel die
* 0x02: 8Gb dual channel die / 4Gb single channel die
* 0x03: 12Gb dual channel die / 6Gb single channel die
* 0x04: 16Gb dual channel die / 8Gb single channel die
* 0x05: 24Gb dual channel die / 12Gb single channel die
* 0x06: 32Gb dual channel die / 16Gb single channel die
* 0x07: 24Gb single channel die
* 0x08: 32Gb single channel die
* 0xFF: NO_MEMORY
*/
u8 bdcfg_ddr_density[CS_CNT];
/* SoC caX([6][5][4][3][2][1][0]) -> MEM caY: */
u32 bdcfg_ca_swap;
/* SoC dqsX([1][0]) -> MEM dqsY: */
u8 bdcfg_dqs_swap;
/* SoC dq([7][6][5][4][3][2][1][0]) -> MEM dqY/dm: (8 means DM) */
u32 bdcfg_dq_swap[SLICE_CNT];
/* SoC dm -> MEM dqY/dm: (8 means DM) */
u8 bdcfg_dm_swap[SLICE_CNT];
} ch[DRAM_CH_CNT];
};
#endif /* __INCLUDE_DBSC5_H__ */