ram: stm32mp1: add driver

Add driver and binding for stm32mp1 ddr controller and phy

Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
master
Patrick Delaunay 6 years ago committed by Tom Rini
parent 2514c2d0e6
commit e70f70aa65
  1. 1
      MAINTAINERS
  2. 12
      arch/arm/mach-stm32mp/include/mach/ddr.h
  3. 299
      doc/device-tree-bindings/ram/st,stm32mp1-ddr.txt
  4. 2
      drivers/ram/Kconfig
  5. 1
      drivers/ram/Makefile
  6. 12
      drivers/ram/stm32mp1/Kconfig
  7. 8
      drivers/ram/stm32mp1/Makefile
  8. 496
      drivers/ram/stm32mp1/stm32mp1_ddr.c
  9. 210
      drivers/ram/stm32mp1/stm32mp1_ddr.h
  10. 365
      drivers/ram/stm32mp1/stm32mp1_ddr_regs.h
  11. 197
      drivers/ram/stm32mp1/stm32mp1_ram.c

@ -199,6 +199,7 @@ ARM STM STM32MP
M: Patrick Delaunay <patrick.delaunay@st.com>
S: Maintained
F: arch/arm/mach-stm32mp
F: ram/stm32mp1
ARM STM STV0991
M: Vikas Manocha <vikas.manocha@st.com>

@ -0,0 +1,12 @@
/*
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause
*/
#ifndef __MACH_STM32MP_DDR_H_
#define __MACH_STM32MP_DDR_H_
int board_ddr_power_init(void);
#endif

@ -0,0 +1,299 @@
ST,stm32mp1 DDR3/LPDDR2/LPDDR3 Controller (DDRCTRL and DDRPHYC)
--------------------
Required properties:
--------------------
- compatible : Should be "st,stm32mp1-ddr"
- reg : controleur (DDRCTRL) and phy (DDRPHYC) base address
- clocks : controller clocks handle
- clock-names : associated controller clock names
the "ddrphyc" clock is used to check the DDR frequency
at phy level according the expected value in "mem-speed" field
the next attributes are DDR parameters, they are generated by DDR tools
included in STM32 Cube tool
info attributes:
----------------
- st,mem-name : name for DDR configuration, simple string for information
- st,mem-speed : DDR expected speed for the setting in MHz
- st,mem-size : DDR mem size in byte
controlleur attributes:
-----------------------
- st,ctl-reg : controleur values depending of the DDR type
(DDR3/LPDDR2/LPDDR3)
for STM32MP15x: 25 values are requested in this order
MSTR
MRCTRL0
MRCTRL1
DERATEEN
DERATEINT
PWRCTL
PWRTMG
HWLPCTL
RFSHCTL0
RFSHCTL3
CRCPARCTL0
ZQCTL0
DFITMG0
DFITMG1
DFILPCFG0
DFIUPD0
DFIUPD1
DFIUPD2
DFIPHYMSTR
ODTMAP
DBG0
DBG1
DBGCMD
POISONCFG
PCCFG
- st,ctl-timing : controleur values depending of frequency and timing parameter
of DDR
for STM32MP15x: 12 values are requested in this order
RFSHTMG
DRAMTMG0
DRAMTMG1
DRAMTMG2
DRAMTMG3
DRAMTMG4
DRAMTMG5
DRAMTMG6
DRAMTMG7
DRAMTMG8
DRAMTMG14
ODTCFG
- st,ctl-map : controleur values depending of address mapping
for STM32MP15x: 9 values are requested in this order
ADDRMAP1
ADDRMAP2
ADDRMAP3
ADDRMAP4
ADDRMAP5
ADDRMAP6
ADDRMAP9
ADDRMAP10
ADDRMAP11
- st,ctl-perf : controleur values depending of performance and scheduling
for STM32MP15x: 17 values are requested in this order
SCHED
SCHED1
PERFHPR1
PERFLPR1
PERFWR1
PCFGR_0
PCFGW_0
PCFGQOS0_0
PCFGQOS1_0
PCFGWQOS0_0
PCFGWQOS1_0
PCFGR_1
PCFGW_1
PCFGQOS0_1
PCFGQOS1_1
PCFGWQOS0_1
PCFGWQOS1_1
phyc attributes:
----------------
- st,phy-reg : phy values depending of the DDR type (DDR3/LPDDR2/LPDDR3)
for STM32MP15x: 10 values are requested in this order
PGCR
ACIOCR
DXCCR
DSGCR
DCR
ODTCR
ZQ0CR1
DX0GCR
DX1GCR
DX2GCR
DX3GCR
- st,phy-timing : phy values depending of frequency and timing parameter of DDR
for STM32MP15x: 10 values are requested in this order
PTR0
PTR1
PTR2
DTPR0
DTPR1
DTPR2
MR0
MR1
MR2
MR3
- st,phy-cal : phy cal depending of calibration or tuning of DDR
for STM32MP15x: 12 values are requested in this order
DX0DLLCR
DX0DQTR
DX0DQSTR
DX1DLLCR
DX1DQTR
DX1DQSTR
DX2DLLCR
DX2DQTR
DX2DQSTR
DX3DLLCR
DX3DQTR
DX3DQSTR
Example:
/ {
soc {
u-boot,dm-spl;
ddr: ddr@0x5A003000{
u-boot,dm-spl;
u-boot,dm-pre-reloc;
compatible = "st,stm32mp1-ddr";
reg = <0x5A003000 0x550
0x5A004000 0x234>;
clocks = <&rcc_clk AXIDCG>,
<&rcc_clk DDRC1>,
<&rcc_clk DDRC2>,
<&rcc_clk DDRPHYC>,
<&rcc_clk DDRCAPB>,
<&rcc_clk DDRPHYCAPB>;
clock-names = "axidcg",
"ddrc1",
"ddrc2",
"ddrphyc",
"ddrcapb",
"ddrphycapb";
st,mem-name = "DDR3 2x4Gb 533MHz";
st,mem-speed = <533>;
st,mem-size = <0x40000000>;
st,ctl-reg = <
0x00040401 /*MSTR*/
0x00000010 /*MRCTRL0*/
0x00000000 /*MRCTRL1*/
0x00000000 /*DERATEEN*/
0x00800000 /*DERATEINT*/
0x00000000 /*PWRCTL*/
0x00400010 /*PWRTMG*/
0x00000000 /*HWLPCTL*/
0x00210000 /*RFSHCTL0*/
0x00000000 /*RFSHCTL3*/
0x00000000 /*CRCPARCTL0*/
0xC2000040 /*ZQCTL0*/
0x02050105 /*DFITMG0*/
0x00000202 /*DFITMG1*/
0x07000000 /*DFILPCFG0*/
0xC0400003 /*DFIUPD0*/
0x00000000 /*DFIUPD1*/
0x00000000 /*DFIUPD2*/
0x00000000 /*DFIPHYMSTR*/
0x00000001 /*ODTMAP*/
0x00000000 /*DBG0*/
0x00000000 /*DBG1*/
0x00000000 /*DBGCMD*/
0x00000000 /*POISONCFG*/
0x00000010 /*PCCFG*/
>;
st,ctl-timing = <
0x0080008A /*RFSHTMG*/
0x121B2414 /*DRAMTMG0*/
0x000D041B /*DRAMTMG1*/
0x0607080E /*DRAMTMG2*/
0x0050400C /*DRAMTMG3*/
0x07040407 /*DRAMTMG4*/
0x06060303 /*DRAMTMG5*/
0x02020002 /*DRAMTMG6*/
0x00000202 /*DRAMTMG7*/
0x00001005 /*DRAMTMG8*/
0x000D041B /*DRAMTMG1*/4
0x06000600 /*ODTCFG*/
>;
st,ctl-map = <
0x00080808 /*ADDRMAP1*/
0x00000000 /*ADDRMAP2*/
0x00000000 /*ADDRMAP3*/
0x00001F1F /*ADDRMAP4*/
0x07070707 /*ADDRMAP5*/
0x0F070707 /*ADDRMAP6*/
0x00000000 /*ADDRMAP9*/
0x00000000 /*ADDRMAP10*/
0x00000000 /*ADDRMAP11*/
>;
st,ctl-perf = <
0x00001201 /*SCHED*/
0x00001201 /*SCHED*/1
0x01000001 /*PERFHPR1*/
0x08000200 /*PERFLPR1*/
0x08000400 /*PERFWR1*/
0x00010000 /*PCFGR_0*/
0x00000000 /*PCFGW_0*/
0x02100B03 /*PCFGQOS0_0*/
0x00800100 /*PCFGQOS1_0*/
0x01100B03 /*PCFGWQOS0_0*/
0x01000200 /*PCFGWQOS1_0*/
0x00010000 /*PCFGR_1*/
0x00000000 /*PCFGW_1*/
0x02100B03 /*PCFGQOS0_1*/
0x00800000 /*PCFGQOS1_1*/
0x01100B03 /*PCFGWQOS0_1*/
0x01000200 /*PCFGWQOS1_1*/
>;
st,phy-reg = <
0x01442E02 /*PGCR*/
0x10400812 /*ACIOCR*/
0x00000C40 /*DXCCR*/
0xF200001F /*DSGCR*/
0x0000000B /*DCR*/
0x00010000 /*ODTCR*/
0x0000007B /*ZQ0CR1*/
0x0000CE81 /*DX0GCR*/
0x0000CE81 /*DX1GCR*/
0x0000CE81 /*DX2GCR*/
0x0000CE81 /*DX3GCR*/
>;
st,phy-timing = <
0x0022A41B /*PTR0*/
0x047C0740 /*PTR1*/
0x042D9C80 /*PTR2*/
0x369477D0 /*DTPR0*/
0x098A00D8 /*DTPR1*/
0x10023600 /*DTPR2*/
0x00000830 /*MR0*/
0x00000000 /*MR1*/
0x00000208 /*MR2*/
0x00000000 /*MR3*/
>;
st,phy-cal = <
0x40000000 /*DX0DLLCR*/
0xFFFFFFFF /*DX0DQTR*/
0x3DB02000 /*DX0DQSTR*/
0x40000000 /*DX1DLLCR*/
0xFFFFFFFF /*DX1DQTR*/
0x3DB02000 /*DX1DQSTR*/
0x40000000 /*DX2DLLCR*/
0xFFFFFFFF /*DX2DQTR*/
0x3DB02000 /*DX2DQSTR*/
0x40000000 /*DX3DLLCR*/
0xFFFFFFFF /*DX3DQTR*/
0x3DB02000 /*DX3DQSTR*/
>;
status = "okay";
};
};
};

@ -33,3 +33,5 @@ config STM32_SDRAM
STM32F7 family devices support flexible memory controller(FMC) to
support external memories like sdram, psram & nand.
This driver is for the sdram memory interface with the FMC.
source "drivers/ram/stm32mp1/Kconfig"

@ -6,6 +6,7 @@
#
obj-$(CONFIG_RAM) += ram-uclass.o
obj-$(CONFIG_SANDBOX) += sandbox_ram.o
obj-$(CONFIG_STM32MP1_DDR) += stm32mp1/
obj-$(CONFIG_STM32_SDRAM) += stm32_sdram.o
obj-$(CONFIG_ARCH_BMIPS) += bmips_ram.o

@ -0,0 +1,12 @@
config STM32MP1_DDR
bool "STM32MP1 DDR driver"
depends on DM && OF_CONTROL && ARCH_STM32MP
select RAM
select SPL_RAM if SPL
default y
help
activate STM32MP1 DDR controller driver for STM32MP1 soc
family: support for LPDDR2, LPDDR3 and DDR3
the SDRAM parameters for controleur and phy need to be provided
in device tree (computed by DDR tuning tools)

@ -0,0 +1,8 @@
#
# Copyright (C) 2018, STMicroelectronics - All Rights Reserved
#
# SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause
#
obj-y += stm32mp1_ram.o
obj-y += stm32mp1_ddr.o

@ -0,0 +1,496 @@
/*
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause
*/
#include <common.h>
#include <clk.h>
#include <ram.h>
#include <reset.h>
#include <timer.h>
#include <asm/io.h>
#include <asm/arch/ddr.h>
#include <linux/iopoll.h>
#include "stm32mp1_ddr.h"
#include "stm32mp1_ddr_regs.h"
#define RCC_DDRITFCR 0xD8
#define RCC_DDRITFCR_DDRCAPBRST (BIT(14))
#define RCC_DDRITFCR_DDRCAXIRST (BIT(15))
#define RCC_DDRITFCR_DDRCORERST (BIT(16))
#define RCC_DDRITFCR_DPHYAPBRST (BIT(17))
#define RCC_DDRITFCR_DPHYRST (BIT(18))
#define RCC_DDRITFCR_DPHYCTLRST (BIT(19))
struct reg_desc {
const char *name;
u16 offset; /* offset for base address */
u8 par_offset; /* offset for parameter array */
};
#define INVALID_OFFSET 0xFF
#define DDRCTL_REG(x, y) \
{#x,\
offsetof(struct stm32mp1_ddrctl, x),\
offsetof(struct y, x)}
#define DDRPHY_REG(x, y) \
{#x,\
offsetof(struct stm32mp1_ddrphy, x),\
offsetof(struct y, x)}
#define DDRCTL_REG_REG(x) DDRCTL_REG(x, stm32mp1_ddrctrl_reg)
static const struct reg_desc ddr_reg[] = {
DDRCTL_REG_REG(mstr),
DDRCTL_REG_REG(mrctrl0),
DDRCTL_REG_REG(mrctrl1),
DDRCTL_REG_REG(derateen),
DDRCTL_REG_REG(derateint),
DDRCTL_REG_REG(pwrctl),
DDRCTL_REG_REG(pwrtmg),
DDRCTL_REG_REG(hwlpctl),
DDRCTL_REG_REG(rfshctl0),
DDRCTL_REG_REG(rfshctl3),
DDRCTL_REG_REG(crcparctl0),
DDRCTL_REG_REG(zqctl0),
DDRCTL_REG_REG(dfitmg0),
DDRCTL_REG_REG(dfitmg1),
DDRCTL_REG_REG(dfilpcfg0),
DDRCTL_REG_REG(dfiupd0),
DDRCTL_REG_REG(dfiupd1),
DDRCTL_REG_REG(dfiupd2),
DDRCTL_REG_REG(dfiphymstr),
DDRCTL_REG_REG(odtmap),
DDRCTL_REG_REG(dbg0),
DDRCTL_REG_REG(dbg1),
DDRCTL_REG_REG(dbgcmd),
DDRCTL_REG_REG(poisoncfg),
DDRCTL_REG_REG(pccfg),
};
#define DDRCTL_REG_TIMING(x) DDRCTL_REG(x, stm32mp1_ddrctrl_timing)
static const struct reg_desc ddr_timing[] = {
DDRCTL_REG_TIMING(rfshtmg),
DDRCTL_REG_TIMING(dramtmg0),
DDRCTL_REG_TIMING(dramtmg1),
DDRCTL_REG_TIMING(dramtmg2),
DDRCTL_REG_TIMING(dramtmg3),
DDRCTL_REG_TIMING(dramtmg4),
DDRCTL_REG_TIMING(dramtmg5),
DDRCTL_REG_TIMING(dramtmg6),
DDRCTL_REG_TIMING(dramtmg7),
DDRCTL_REG_TIMING(dramtmg8),
DDRCTL_REG_TIMING(dramtmg14),
DDRCTL_REG_TIMING(odtcfg),
};
#define DDRCTL_REG_MAP(x) DDRCTL_REG(x, stm32mp1_ddrctrl_map)
static const struct reg_desc ddr_map[] = {
DDRCTL_REG_MAP(addrmap1),
DDRCTL_REG_MAP(addrmap2),
DDRCTL_REG_MAP(addrmap3),
DDRCTL_REG_MAP(addrmap4),
DDRCTL_REG_MAP(addrmap5),
DDRCTL_REG_MAP(addrmap6),
DDRCTL_REG_MAP(addrmap9),
DDRCTL_REG_MAP(addrmap10),
DDRCTL_REG_MAP(addrmap11),
};
#define DDRCTL_REG_PERF(x) DDRCTL_REG(x, stm32mp1_ddrctrl_perf)
static const struct reg_desc ddr_perf[] = {
DDRCTL_REG_PERF(sched),
DDRCTL_REG_PERF(sched1),
DDRCTL_REG_PERF(perfhpr1),
DDRCTL_REG_PERF(perflpr1),
DDRCTL_REG_PERF(perfwr1),
DDRCTL_REG_PERF(pcfgr_0),
DDRCTL_REG_PERF(pcfgw_0),
DDRCTL_REG_PERF(pcfgqos0_0),
DDRCTL_REG_PERF(pcfgqos1_0),
DDRCTL_REG_PERF(pcfgwqos0_0),
DDRCTL_REG_PERF(pcfgwqos1_0),
DDRCTL_REG_PERF(pcfgr_1),
DDRCTL_REG_PERF(pcfgw_1),
DDRCTL_REG_PERF(pcfgqos0_1),
DDRCTL_REG_PERF(pcfgqos1_1),
DDRCTL_REG_PERF(pcfgwqos0_1),
DDRCTL_REG_PERF(pcfgwqos1_1),
};
#define DDRPHY_REG_REG(x) DDRPHY_REG(x, stm32mp1_ddrphy_reg)
static const struct reg_desc ddrphy_reg[] = {
DDRPHY_REG_REG(pgcr),
DDRPHY_REG_REG(aciocr),
DDRPHY_REG_REG(dxccr),
DDRPHY_REG_REG(dsgcr),
DDRPHY_REG_REG(dcr),
DDRPHY_REG_REG(odtcr),
DDRPHY_REG_REG(zq0cr1),
DDRPHY_REG_REG(dx0gcr),
DDRPHY_REG_REG(dx1gcr),
DDRPHY_REG_REG(dx2gcr),
DDRPHY_REG_REG(dx3gcr),
};
#define DDRPHY_REG_TIMING(x) DDRPHY_REG(x, stm32mp1_ddrphy_timing)
static const struct reg_desc ddrphy_timing[] = {
DDRPHY_REG_TIMING(ptr0),
DDRPHY_REG_TIMING(ptr1),
DDRPHY_REG_TIMING(ptr2),
DDRPHY_REG_TIMING(dtpr0),
DDRPHY_REG_TIMING(dtpr1),
DDRPHY_REG_TIMING(dtpr2),
DDRPHY_REG_TIMING(mr0),
DDRPHY_REG_TIMING(mr1),
DDRPHY_REG_TIMING(mr2),
DDRPHY_REG_TIMING(mr3),
};
#define DDRPHY_REG_CAL(x) DDRPHY_REG(x, stm32mp1_ddrphy_cal)
static const struct reg_desc ddrphy_cal[] = {
DDRPHY_REG_CAL(dx0dllcr),
DDRPHY_REG_CAL(dx0dqtr),
DDRPHY_REG_CAL(dx0dqstr),
DDRPHY_REG_CAL(dx1dllcr),
DDRPHY_REG_CAL(dx1dqtr),
DDRPHY_REG_CAL(dx1dqstr),
DDRPHY_REG_CAL(dx2dllcr),
DDRPHY_REG_CAL(dx2dqtr),
DDRPHY_REG_CAL(dx2dqstr),
DDRPHY_REG_CAL(dx3dllcr),
DDRPHY_REG_CAL(dx3dqtr),
DDRPHY_REG_CAL(dx3dqstr),
};
enum reg_type {
REG_REG,
REG_TIMING,
REG_PERF,
REG_MAP,
REGPHY_REG,
REGPHY_TIMING,
REGPHY_CAL,
REG_TYPE_NB
};
enum base_type {
DDR_BASE,
DDRPHY_BASE,
NONE_BASE
};
struct ddr_reg_info {
const char *name;
const struct reg_desc *desc;
u8 size;
enum base_type base;
};
#define DDRPHY_REG_CAL(x) DDRPHY_REG(x, stm32mp1_ddrphy_cal)
const struct ddr_reg_info ddr_registers[REG_TYPE_NB] = {
[REG_REG] = {
"static", ddr_reg, ARRAY_SIZE(ddr_reg), DDR_BASE},
[REG_TIMING] = {
"timing", ddr_timing, ARRAY_SIZE(ddr_timing), DDR_BASE},
[REG_PERF] = {
"perf", ddr_perf, ARRAY_SIZE(ddr_perf), DDR_BASE},
[REG_MAP] = {
"map", ddr_map, ARRAY_SIZE(ddr_map), DDR_BASE},
[REGPHY_REG] = {
"static", ddrphy_reg, ARRAY_SIZE(ddrphy_reg), DDRPHY_BASE},
[REGPHY_TIMING] = {
"timing", ddrphy_timing, ARRAY_SIZE(ddrphy_timing), DDRPHY_BASE},
[REGPHY_CAL] = {
"cal", ddrphy_cal, ARRAY_SIZE(ddrphy_cal), DDRPHY_BASE},
};
const char *base_name[] = {
[DDR_BASE] = "ctl",
[DDRPHY_BASE] = "phy",
};
static u32 get_base_addr(const struct ddr_info *priv, enum base_type base)
{
if (base == DDRPHY_BASE)
return (u32)priv->phy;
else
return (u32)priv->ctl;
}
static void set_reg(const struct ddr_info *priv,
enum reg_type type,
const void *param)
{
unsigned int i;
unsigned int *ptr, value;
enum base_type base = ddr_registers[type].base;
u32 base_addr = get_base_addr(priv, base);
const struct reg_desc *desc = ddr_registers[type].desc;
debug("init %s\n", ddr_registers[type].name);
for (i = 0; i < ddr_registers[type].size; i++) {
ptr = (unsigned int *)(base_addr + desc[i].offset);
if (desc[i].par_offset == INVALID_OFFSET) {
pr_err("invalid parameter offset for %s", desc[i].name);
} else {
value = *((u32 *)((u32)param +
desc[i].par_offset));
writel(value, ptr);
debug("[0x%x] %s= 0x%08x\n",
(u32)ptr, desc[i].name, value);
}
}
}
static void ddrphy_idone_wait(struct stm32mp1_ddrphy *phy)
{
u32 pgsr;
int ret;
ret = readl_poll_timeout(&phy->pgsr, pgsr,
pgsr & (DDRPHYC_PGSR_IDONE |
DDRPHYC_PGSR_DTERR |
DDRPHYC_PGSR_DTIERR |
DDRPHYC_PGSR_DFTERR |
DDRPHYC_PGSR_RVERR |
DDRPHYC_PGSR_RVEIRR),
1000000);
debug("\n[0x%08x] pgsr = 0x%08x ret=%d\n",
(u32)&phy->pgsr, pgsr, ret);
}
void stm32mp1_ddrphy_init(struct stm32mp1_ddrphy *phy, u32 pir)
{
pir |= DDRPHYC_PIR_INIT;
writel(pir, &phy->pir);
debug("[0x%08x] pir = 0x%08x -> 0x%08x\n",
(u32)&phy->pir, pir, readl(&phy->pir));
/* need to wait 10 configuration clock before start polling */
udelay(10);
/* Wait DRAM initialization and Gate Training Evaluation complete */
ddrphy_idone_wait(phy);
}
/* start quasi dynamic register update */
static void start_sw_done(struct stm32mp1_ddrctl *ctl)
{
clrbits_le32(&ctl->swctl, DDRCTRL_SWCTL_SW_DONE);
}
/* wait quasi dynamic register update */
static void wait_sw_done_ack(struct stm32mp1_ddrctl *ctl)
{
int ret;
u32 swstat;
setbits_le32(&ctl->swctl, DDRCTRL_SWCTL_SW_DONE);
ret = readl_poll_timeout(&ctl->swstat, swstat,
swstat & DDRCTRL_SWSTAT_SW_DONE_ACK,
1000000);
if (ret)
panic("Timeout initialising DRAM : DDR->swstat = %x\n",
swstat);
debug("[0x%08x] swstat = 0x%08x\n", (u32)&ctl->swstat, swstat);
}
/* wait quasi dynamic register update */
static void wait_operating_mode(struct ddr_info *priv, int mode)
{
u32 stat, val, mask, val2 = 0, mask2 = 0;
int ret;
mask = DDRCTRL_STAT_OPERATING_MODE_MASK;
val = mode;
/* self-refresh due to software => check also STAT.selfref_type */
if (mode == DDRCTRL_STAT_OPERATING_MODE_SR) {
mask |= DDRCTRL_STAT_SELFREF_TYPE_MASK;
stat |= DDRCTRL_STAT_SELFREF_TYPE_SR;
} else if (mode == DDRCTRL_STAT_OPERATING_MODE_NORMAL) {
/* normal mode: handle also automatic self refresh */
mask2 = DDRCTRL_STAT_OPERATING_MODE_MASK |
DDRCTRL_STAT_SELFREF_TYPE_MASK;
val2 = DDRCTRL_STAT_OPERATING_MODE_SR |
DDRCTRL_STAT_SELFREF_TYPE_ASR;
}
ret = readl_poll_timeout(&priv->ctl->stat, stat,
((stat & mask) == val) ||
(mask2 && ((stat & mask2) == val2)),
1000000);
if (ret)
panic("Timeout DRAM : DDR->stat = %x\n", stat);
debug("[0x%08x] stat = 0x%08x\n", (u32)&priv->ctl->stat, stat);
}
void stm32mp1_refresh_disable(struct stm32mp1_ddrctl *ctl)
{
start_sw_done(ctl);
/* quasi-dynamic register update*/
setbits_le32(&ctl->rfshctl3, DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH);
clrbits_le32(&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN);
clrbits_le32(&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
wait_sw_done_ack(ctl);
}
void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl,
u32 rfshctl3, u32 pwrctl)
{
start_sw_done(ctl);
if (!(rfshctl3 & DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH))
clrbits_le32(&ctl->rfshctl3, DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH);
if (pwrctl & DDRCTRL_PWRCTL_POWERDOWN_EN)
setbits_le32(&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN);
setbits_le32(&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
wait_sw_done_ack(ctl);
}
/* board-specific DDR power initializations. */
__weak int board_ddr_power_init(void)
{
return 0;
}
__maybe_unused
void stm32mp1_ddr_init(struct ddr_info *priv,
const struct stm32mp1_ddr_config *config)
{
u32 pir;
int ret;
ret = board_ddr_power_init();
if (ret)
panic("ddr power init failed\n");
debug("name = %s\n", config->info.name);
debug("speed = %d MHz\n", config->info.speed);
debug("size = 0x%x\n", config->info.size);
/*
* 1. Program the DWC_ddr_umctl2 registers
* 1.1 RESETS: presetn, core_ddrc_rstn, aresetn
*/
/* Assert All DDR part */
setbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAPBRST);
setbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAXIRST);
setbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCORERST);
setbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYAPBRST);
setbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYRST);
setbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYCTLRST);
/* 1.2. start CLOCK */
if (stm32mp1_ddr_clk_enable(priv, config->info.speed))
panic("invalid DRAM clock : %d MHz\n",
config->info.speed);
/* 1.3. deassert reset */
/* de-assert PHY rstn and ctl_rstn via DPHYRST and DPHYCTLRST */
clrbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYRST);
clrbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYCTLRST);
/* De-assert presetn once the clocks are active
* and stable via DDRCAPBRST bit
*/
clrbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAPBRST);
/* 1.4. wait 4 cycles for synchronization */
asm(" nop");
asm(" nop");
asm(" nop");
asm(" nop");
/* 1.5. initialize registers ddr_umctl2 */
/* Stop uMCTL2 before PHY is ready */
clrbits_le32(&priv->ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
debug("[0x%08x] dfimisc = 0x%08x\n",
(u32)&priv->ctl->dfimisc, readl(&priv->ctl->dfimisc));
set_reg(priv, REG_REG, &config->c_reg);
set_reg(priv, REG_TIMING, &config->c_timing);
set_reg(priv, REG_MAP, &config->c_map);
/* skip CTRL init, SDRAM init is done by PHY PUBL */
clrsetbits_le32(&priv->ctl->init0,
DDRCTRL_INIT0_SKIP_DRAM_INIT_MASK,
DDRCTRL_INIT0_SKIP_DRAM_INIT_NORMAL);
set_reg(priv, REG_PERF, &config->c_perf);
/* 2. deassert reset signal core_ddrc_rstn, aresetn and presetn */
clrbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCORERST);
clrbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAXIRST);
clrbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYAPBRST);
/* 3. start PHY init by accessing relevant PUBL registers
* (DXGCR, DCR, PTR*, MR*, DTPR*)
*/
set_reg(priv, REGPHY_REG, &config->p_reg);
set_reg(priv, REGPHY_TIMING, &config->p_timing);
set_reg(priv, REGPHY_CAL, &config->p_cal);
/* 4. Monitor PHY init status by polling PUBL register PGSR.IDONE
* Perform DDR PHY DRAM initialization and Gate Training Evaluation
*/
ddrphy_idone_wait(priv->phy);
/* 5. Indicate to PUBL that controller performs SDRAM initialization
* by setting PIR.INIT and PIR CTLDINIT and pool PGSR.IDONE
* DRAM init is done by PHY, init0.skip_dram.init = 1
*/
pir = DDRPHYC_PIR_DLLSRST | DDRPHYC_PIR_DLLLOCK | DDRPHYC_PIR_ZCAL |
DDRPHYC_PIR_ITMSRST | DDRPHYC_PIR_DRAMINIT | DDRPHYC_PIR_ICPC;
if (config->c_reg.mstr & DDRCTRL_MSTR_DDR3)
pir |= DDRPHYC_PIR_DRAMRST; /* only for DDR3 */
stm32mp1_ddrphy_init(priv->phy, pir);
/* 6. SET DFIMISC.dfi_init_complete_en to 1 */
/* Enable quasi-dynamic register programming*/
start_sw_done(priv->ctl);
setbits_le32(&priv->ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
wait_sw_done_ack(priv->ctl);
/* 7. Wait for DWC_ddr_umctl2 to move to normal operation mode
* by monitoring STAT.operating_mode signal
*/
/* wait uMCTL2 ready */
wait_operating_mode(priv, DDRCTRL_STAT_OPERATING_MODE_NORMAL);
debug("DDR DQS training : ");
/* 8. Disable Auto refresh and power down by setting
* - RFSHCTL3.dis_au_refresh = 1
* - PWRCTL.powerdown_en = 0
* - DFIMISC.dfiinit_complete_en = 0
*/
stm32mp1_refresh_disable(priv->ctl);
/* 9. Program PUBL PGCR to enable refresh during training and rank to train
* not done => keep the programed value in PGCR
*/
/* 10. configure PUBL PIR register to specify which training step to run */
/* warning : RVTRN is not supported by this PUBL */
stm32mp1_ddrphy_init(priv->phy, DDRPHYC_PIR_QSTRN);
/* 11. monitor PUB PGSR.IDONE to poll cpmpletion of training sequence */
ddrphy_idone_wait(priv->phy);
/* 12. set back registers in step 8 to the orginal values if desidered */
stm32mp1_refresh_restore(priv->ctl, config->c_reg.rfshctl3,
config->c_reg.pwrctl);
/* enable uMCTL2 AXI port 0 and 1 */
setbits_le32(&priv->ctl->pctrl_0, DDRCTRL_PCTRL_N_PORT_EN);
setbits_le32(&priv->ctl->pctrl_1, DDRCTRL_PCTRL_N_PORT_EN);
}

@ -0,0 +1,210 @@
/*
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause
*/
#ifndef _RAM_STM32MP1_DDR_H
#define _RAM_STM32MP1_DDR_H
enum stm32mp1_ddr_interact_step {
STEP_DDR_RESET,
STEP_CTL_INIT,
STEP_PHY_INIT,
STEP_DDR_READY,
STEP_RUN,
};
/* DDR CTL and DDR PHY REGISTERS */
struct stm32mp1_ddrctl;
struct stm32mp1_ddrphy;
/**
* struct ddr_info
*
* @dev: pointer for the device
* @info: UCLASS RAM information
* @ctl: DDR controleur base address
* @clk: DDR clock
* @phy: DDR PHY base address
* @rcc: rcc base address
*/
struct ddr_info {
struct udevice *dev;
struct ram_info info;
struct clk clk;
struct stm32mp1_ddrctl *ctl;
struct stm32mp1_ddrphy *phy;
u32 rcc;
};
struct stm32mp1_ddrctrl_reg {
u32 mstr;
u32 mrctrl0;
u32 mrctrl1;
u32 derateen;
u32 derateint;
u32 pwrctl;
u32 pwrtmg;
u32 hwlpctl;
u32 rfshctl0;
u32 rfshctl3;
u32 crcparctl0;
u32 zqctl0;
u32 dfitmg0;
u32 dfitmg1;
u32 dfilpcfg0;
u32 dfiupd0;
u32 dfiupd1;
u32 dfiupd2;
u32 dfiphymstr;
u32 odtmap;
u32 dbg0;
u32 dbg1;
u32 dbgcmd;
u32 poisoncfg;
u32 pccfg;
};
struct stm32mp1_ddrctrl_timing {
u32 rfshtmg;
u32 dramtmg0;
u32 dramtmg1;
u32 dramtmg2;
u32 dramtmg3;
u32 dramtmg4;
u32 dramtmg5;
u32 dramtmg6;
u32 dramtmg7;
u32 dramtmg8;
u32 dramtmg14;
u32 odtcfg;
};
struct stm32mp1_ddrctrl_map {
u32 addrmap1;
u32 addrmap2;
u32 addrmap3;
u32 addrmap4;
u32 addrmap5;
u32 addrmap6;
u32 addrmap9;
u32 addrmap10;
u32 addrmap11;
};
struct stm32mp1_ddrctrl_perf {
u32 sched;
u32 sched1;
u32 perfhpr1;
u32 perflpr1;
u32 perfwr1;
u32 pcfgr_0;
u32 pcfgw_0;
u32 pcfgqos0_0;
u32 pcfgqos1_0;
u32 pcfgwqos0_0;
u32 pcfgwqos1_0;
u32 pcfgr_1;
u32 pcfgw_1;
u32 pcfgqos0_1;
u32 pcfgqos1_1;
u32 pcfgwqos0_1;
u32 pcfgwqos1_1;
};
struct stm32mp1_ddrphy_reg {
u32 pgcr;
u32 aciocr;
u32 dxccr;
u32 dsgcr;
u32 dcr;
u32 odtcr;
u32 zq0cr1;
u32 dx0gcr;
u32 dx1gcr;
u32 dx2gcr;
u32 dx3gcr;
};
struct stm32mp1_ddrphy_timing {
u32 ptr0;
u32 ptr1;
u32 ptr2;
u32 dtpr0;
u32 dtpr1;
u32 dtpr2;
u32 mr0;
u32 mr1;
u32 mr2;
u32 mr3;
};
struct stm32mp1_ddrphy_cal {
u32 dx0dllcr;
u32 dx0dqtr;
u32 dx0dqstr;
u32 dx1dllcr;
u32 dx1dqtr;
u32 dx1dqstr;
u32 dx2dllcr;
u32 dx2dqtr;
u32 dx2dqstr;
u32 dx3dllcr;
u32 dx3dqtr;
u32 dx3dqstr;
};
struct stm32mp1_ddr_info {
const char *name;
u16 speed; /* in MHZ */
u32 size; /* memory size in byte = col * row * width */
};
struct stm32mp1_ddr_config {
struct stm32mp1_ddr_info info;
struct stm32mp1_ddrctrl_reg c_reg;
struct stm32mp1_ddrctrl_timing c_timing;
struct stm32mp1_ddrctrl_map c_map;
struct stm32mp1_ddrctrl_perf c_perf;
struct stm32mp1_ddrphy_reg p_reg;
struct stm32mp1_ddrphy_timing p_timing;
struct stm32mp1_ddrphy_cal p_cal;
};
int stm32mp1_ddr_clk_enable(struct ddr_info *priv, u16 mem_speed);
void stm32mp1_ddrphy_init(struct stm32mp1_ddrphy *phy, u32 pir);
void stm32mp1_refresh_disable(struct stm32mp1_ddrctl *ctl);
void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl,
u32 rfshctl3,
u32 pwrctl);
void stm32mp1_ddr_init(
struct ddr_info *priv,
const struct stm32mp1_ddr_config *config);
int stm32mp1_dump_reg(const struct ddr_info *priv,
const char *name);
void stm32mp1_edit_reg(const struct ddr_info *priv,
char *name,
char *string);
int stm32mp1_dump_param(const struct stm32mp1_ddr_config *config,
const char *name);
void stm32mp1_edit_param(const struct stm32mp1_ddr_config *config,
char *name,
char *string);
void stm32mp1_dump_info(
const struct ddr_info *priv,
const struct stm32mp1_ddr_config *config);
bool stm32mp1_ddr_interactive(
void *priv,
enum stm32mp1_ddr_interact_step step,
const struct stm32mp1_ddr_config *config);
#endif

@ -0,0 +1,365 @@
/*
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause
*/
#ifndef _RAM_STM32MP1_DDR_REGS_H
#define _RAM_STM32MP1_DDR_REGS_H
/* DDR3/LPDDR2/LPDDR3 Controller (DDRCTRL) registers */
struct stm32mp1_ddrctl {
u32 mstr ; /* 0x0 Master*/
u32 stat; /* 0x4 Operating Mode Status*/
u8 reserved008[0x10 - 0x8];
u32 mrctrl0; /* 0x10 Control 0.*/
u32 mrctrl1; /* 0x14 Control 1*/
u32 mrstat; /* 0x18 Status*/
u32 reserved01c; /* 0x1c */
u32 derateen; /* 0x20 Temperature Derate Enable*/
u32 derateint; /* 0x24 Temperature Derate Interval*/
u8 reserved028[0x30 - 0x28];
u32 pwrctl; /* 0x30 Low Power Control*/
u32 pwrtmg; /* 0x34 Low Power Timing*/
u32 hwlpctl; /* 0x38 Hardware Low Power Control*/
u8 reserved03c[0x50 - 0x3C];
u32 rfshctl0; /* 0x50 Refresh Control 0*/
u32 reserved054; /* 0x54 Refresh Control 1*/
u32 reserved058; /* 0x58 Refresh Control 2*/
u32 reserved05C;
u32 rfshctl3; /* 0x60 Refresh Control 0*/
u32 rfshtmg; /* 0x64 Refresh Timing*/
u8 reserved068[0xc0 - 0x68];
u32 crcparctl0; /* 0xc0 CRC Parity Control0*/
u32 reserved0c4; /* 0xc4 CRC Parity Control1*/
u32 reserved0c8; /* 0xc8 CRC Parity Control2*/
u32 crcparstat; /* 0xcc CRC Parity Status*/
u32 init0; /* 0xd0 SDRAM Initialization 0*/
u32 init1; /* 0xd4 SDRAM Initialization 1*/
u32 init2; /* 0xd8 SDRAM Initialization 2*/
u32 init3; /* 0xdc SDRAM Initialization 3*/
u32 init4; /* 0xe0 SDRAM Initialization 4*/
u32 init5; /* 0xe4 SDRAM Initialization 5*/
u32 reserved0e8;
u32 reserved0ec;
u32 dimmctl; /* 0xf0 DIMM Control*/
u8 reserved0f4[0x100 - 0xf4];
u32 dramtmg0; /* 0x100 SDRAM Timing 0*/
u32 dramtmg1; /* 0x104 SDRAM Timing 1*/
u32 dramtmg2; /* 0x108 SDRAM Timing 2*/
u32 dramtmg3; /* 0x10c SDRAM Timing 3*/
u32 dramtmg4; /* 0x110 SDRAM Timing 4*/
u32 dramtmg5; /* 0x114 SDRAM Timing 5*/
u32 dramtmg6; /* 0x118 SDRAM Timing 6*/
u32 dramtmg7; /* 0x11c SDRAM Timing 7*/
u32 dramtmg8; /* 0x120 SDRAM Timing 8*/
u8 reserved124[0x138 - 0x124];
u32 dramtmg14; /* 0x138 SDRAM Timing 14*/
u32 dramtmg15; /* 0x13C SDRAM Timing 15*/
u8 reserved140[0x180 - 0x140];
u32 zqctl0; /* 0x180 ZQ Control 0*/
u32 zqctl1; /* 0x184 ZQ Control 1*/
u32 zqctl2; /* 0x188 ZQ Control 2*/
u32 zqstat; /* 0x18c ZQ Status*/
u32 dfitmg0; /* 0x190 DFI Timing 0*/
u32 dfitmg1; /* 0x194 DFI Timing 1*/
u32 dfilpcfg0; /* 0x198 DFI Low Power Configuration 0*/
u32 reserved19c;
u32 dfiupd0; /* 0x1a0 DFI Update 0*/
u32 dfiupd1; /* 0x1a4 DFI Update 1*/
u32 dfiupd2; /* 0x1a8 DFI Update 2*/
u32 reserved1ac;
u32 dfimisc; /* 0x1b0 DFI Miscellaneous Control*/
u8 reserved1b4[0x1bc - 0x1b4];
u32 dfistat; /* 0x1bc DFI Miscellaneous Control*/
u8 reserved1c0[0x1c4 - 0x1c0];
u32 dfiphymstr; /* 0x1c4 DFI PHY Master interface*/
u8 reserved1c8[0x204 - 0x1c8];
u32 addrmap1; /* 0x204 Address Map 1*/
u32 addrmap2; /* 0x208 Address Map 2*/
u32 addrmap3; /* 0x20c Address Map 3*/
u32 addrmap4; /* 0x210 Address Map 4*/
u32 addrmap5; /* 0x214 Address Map 5*/
u32 addrmap6; /* 0x218 Address Map 6*/
u8 reserved21c[0x224 - 0x21c];
u32 addrmap9; /* 0x224 Address Map 9*/
u32 addrmap10; /* 0x228 Address Map 10*/
u32 addrmap11; /* 0x22C Address Map 11*/
u8 reserved230[0x240 - 0x230];
u32 odtcfg; /* 0x240 ODT Configuration*/
u32 odtmap; /* 0x244 ODT/Rank Map*/
u8 reserved248[0x250 - 0x248];
u32 sched; /* 0x250 Scheduler Control*/
u32 sched1; /* 0x254 Scheduler Control 1*/
u32 reserved258;
u32 perfhpr1; /* 0x25c High Priority Read CAM 1*/
u32 reserved260;
u32 perflpr1; /* 0x264 Low Priority Read CAM 1*/
u32 reserved268;
u32 perfwr1; /* 0x26c Write CAM 1*/
u8 reserved27c[0x300 - 0x270];
u32 dbg0; /* 0x300 Debug 0*/
u32 dbg1; /* 0x304 Debug 1*/
u32 dbgcam; /* 0x308 CAM Debug*/
u32 dbgcmd; /* 0x30c Command Debug*/
u32 dbgstat; /* 0x310 Status Debug*/
u8 reserved314[0x320 - 0x314];
u32 swctl; /* 0x320 Software Programming Control Enable*/
u32 swstat; /* 0x324 Software Programming Control Status*/
u8 reserved328[0x36c - 0x328];
u32 poisoncfg; /* 0x36c AXI Poison Configuration Register*/
u32 poisonstat; /* 0x370 AXI Poison Status Register*/
u8 reserved374[0x3fc - 0x374];
/* Multi Port registers */
u32 pstat; /* 0x3fc Port Status*/
u32 pccfg; /* 0x400 Port Common Configuration*/
/* PORT 0 */
u32 pcfgr_0; /* 0x404 Configuration Read*/
u32 pcfgw_0; /* 0x408 Configuration Write*/
u8 reserved40c[0x490 - 0x40c];
u32 pctrl_0; /* 0x490 Port Control Register */
u32 pcfgqos0_0; /* 0x494 Read QoS Configuration 0*/
u32 pcfgqos1_0; /* 0x498 Read QoS Configuration 1*/
u32 pcfgwqos0_0; /* 0x49c Write QoS Configuration 0*/
u32 pcfgwqos1_0; /* 0x4a0 Write QoS Configuration 1*/
u8 reserved4a4[0x4b4 - 0x4a4];
/* PORT 1 */
u32 pcfgr_1; /* 0x4b4 Configuration Read*/
u32 pcfgw_1; /* 0x4b8 Configuration Write*/
u8 reserved4bc[0x540 - 0x4bc];
u32 pctrl_1; /* 0x540 Port 2 Control Register */
u32 pcfgqos0_1; /* 0x544 Read QoS Configuration 0*/
u32 pcfgqos1_1; /* 0x548 Read QoS Configuration 1*/
u32 pcfgwqos0_1; /* 0x54c Write QoS Configuration 0*/
u32 pcfgwqos1_1; /* 0x550 Write QoS Configuration 1*/
};
/* DDR Physical Interface Control (DDRPHYC) registers*/
struct stm32mp1_ddrphy {
u32 ridr; /* 0x00 R Revision Identification*/
u32 pir; /* 0x04 R/W PHY Initialization*/
u32 pgcr; /* 0x08 R/W PHY General Configuration*/
u32 pgsr; /* 0x0C PHY General Status*/
u32 dllgcr; /* 0x10 R/W DLL General Control*/
u32 acdllcr; /* 0x14 R/W AC DLL Control*/
u32 ptr0; /* 0x18 R/W PHY Timing 0*/
u32 ptr1; /* 0x1C R/W PHY Timing 1*/
u32 ptr2; /* 0x20 R/W PHY Timing 2*/
u32 aciocr; /* 0x24 AC I/O Configuration*/
u32 dxccr; /* 0x28 DATX8 Common Configuration*/
u32 dsgcr; /* 0x2C DDR System General Configuration*/
u32 dcr; /* 0x30 DRAM Configuration*/
u32 dtpr0; /* 0x34 DRAM Timing Parameters0*/
u32 dtpr1; /* 0x38 DRAM Timing Parameters1*/
u32 dtpr2; /* 0x3C DRAM Timing Parameters2*/
u32 mr0; /* 0x40 Mode 0*/
u32 mr1; /* 0x44 Mode 1*/
u32 mr2; /* 0x48 Mode 2*/
u32 mr3; /* 0x4C Mode 3*/
u32 odtcr; /* 0x50 ODT Configuration*/
u32 dtar; /* 0x54 data training address*/
u32 dtdr0; /* 0x58 */
u32 dtdr1; /* 0x5c */
u8 res1[0x0c0 - 0x060]; /* 0x60 */
u32 dcuar; /* 0xc0 Address*/
u32 dcudr; /* 0xc4 DCU Data*/
u32 dcurr; /* 0xc8 DCU Run*/
u32 dculr; /* 0xcc DCU Loop*/
u32 dcugcr; /* 0xd0 DCU General Configuration*/
u32 dcutpr; /* 0xd4 DCU Timing Parameters */
u32 dcusr0; /* 0xd8 DCU Status 0*/
u32 dcusr1; /* 0xdc DCU Status 1*/
u8 res2[0x100 - 0xe0]; /* 0xe0 */
u32 bistrr; /* 0x100 BIST Run*/
u32 bistmskr0; /* 0x104 BIST Mask 0*/
u32 bistmskr1; /* 0x108 BIST Mask 0*/
u32 bistwcr; /* 0x10c BIST Word Count*/
u32 bistlsr; /* 0x110 BIST LFSR Seed*/
u32 bistar0; /* 0x114 BIST Address 0*/
u32 bistar1; /* 0x118 BIST Address 1*/
u32 bistar2; /* 0x11c BIST Address 2*/
u32 bistupdr; /* 0x120 BIST User Data Pattern*/
u32 bistgsr; /* 0x124 BIST General Status*/
u32 bistwer; /* 0x128 BIST Word Error*/
u32 bistber0; /* 0x12c BIST Bit Error 0*/
u32 bistber1; /* 0x130 BIST Bit Error 1*/
u32 bistber2; /* 0x134 BIST Bit Error 2*/
u32 bistwcsr; /* 0x138 BIST Word Count Status*/
u32 bistfwr0; /* 0x13c BIST Fail Word 0*/
u32 bistfwr1; /* 0x140 BIST Fail Word 1*/
u8 res3[0x178 - 0x144]; /* 0x144 */
u32 gpr0; /* 0x178 General Purpose 0 (GPR0)*/
u32 gpr1; /* 0x17C General Purpose 1 (GPR1)*/
u32 zq0cr0; /* 0x180 zq 0 control 0 */
u32 zq0cr1; /* 0x184 zq 0 control 1 */
u32 zq0sr0; /* 0x188 zq 0 status 0 */
u32 zq0sr1; /* 0x18C zq 0 status 1 */
u8 res4[0x1C0 - 0x190]; /* 0x190 */
u32 dx0gcr; /* 0x1c0 Byte lane 0 General Configuration*/
u32 dx0gsr0; /* 0x1c4 Byte lane 0 General Status 0*/
u32 dx0gsr1; /* 0x1c8 Byte lane 0 General Status 1*/
u32 dx0dllcr; /* 0x1cc Byte lane 0 DLL Control*/
u32 dx0dqtr; /* 0x1d0 Byte lane 0 DQ Timing*/
u32 dx0dqstr; /* 0x1d4 Byte lane 0 DQS Timing*/
u8 res5[0x200 - 0x1d8]; /* 0x1d8 */
u32 dx1gcr; /* 0x200 Byte lane 1 General Configuration*/
u32 dx1gsr0; /* 0x204 Byte lane 1 General Status 0*/
u32 dx1gsr1; /* 0x208 Byte lane 1 General Status 1*/
u32 dx1dllcr; /* 0x20c Byte lane 1 DLL Control*/
u32 dx1dqtr; /* 0x210 Byte lane 1 DQ Timing*/
u32 dx1dqstr; /* 0x214 Byte lane 1 QS Timing*/
u8 res6[0x240 - 0x218]; /* 0x218 */
u32 dx2gcr; /* 0x240 Byte lane 2 General Configuration*/
u32 dx2gsr0; /* 0x244 Byte lane 2 General Status 0*/
u32 dx2gsr1; /* 0x248 Byte lane 2 General Status 1*/
u32 dx2dllcr; /* 0x24c Byte lane 2 DLL Control*/
u32 dx2dqtr; /* 0x250 Byte lane 2 DQ Timing*/
u32 dx2dqstr; /* 0x254 Byte lane 2 QS Timing*/
u8 res7[0x280 - 0x258]; /* 0x258 */
u32 dx3gcr; /* 0x280 Byte lane 3 General Configuration*/
u32 dx3gsr0; /* 0x284 Byte lane 3 General Status 0*/
u32 dx3gsr1; /* 0x288 Byte lane 3 General Status 1*/
u32 dx3dllcr; /* 0x28c Byte lane 3 DLL Control*/
u32 dx3dqtr; /* 0x290 Byte lane 3 DQ Timing*/
u32 dx3dqstr; /* 0x294 Byte lane 3 QS Timing*/
};
#define DXN(phy, offset, byte) ((u32)(phy) + (offset) + ((u32)(byte) * 0x40))
#define DXNGCR(phy, byte) DXN(phy, 0x1c0, byte)
#define DXNDLLCR(phy, byte) DXN(phy, 0x1cc, byte)
#define DXNDQTR(phy, byte) DXN(phy, 0x1d0, byte)
#define DXNDQSTR(phy, byte) DXN(phy, 0x1d4, byte)
/* DDRCTRL REGISTERS */
#define DDRCTRL_MSTR_DDR3 BIT(0)
#define DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK GENMASK(13, 12)
#define DDRCTRL_MSTR_DATA_BUS_WIDTH_FULL (0 << 12)
#define DDRCTRL_MSTR_DATA_BUS_WIDTH_HALF (1 << 12)
#define DDRCTRL_MSTR_DATA_BUS_WIDTH_QUARTER (2 << 12)
#define DDRCTRL_MSTR_DLL_OFF_MODE BIT(15)
#define DDRCTRL_STAT_OPERATING_MODE_MASK GENMASK(2, 0)
#define DDRCTRL_STAT_OPERATING_MODE_NORMAL 1
#define DDRCTRL_STAT_OPERATING_MODE_SR 3
#define DDRCTRL_STAT_SELFREF_TYPE_MASK GENMASK(5, 4)
#define DDRCTRL_STAT_SELFREF_TYPE_ASR (3 << 4)
#define DDRCTRL_STAT_SELFREF_TYPE_SR (2 << 4)
#define DDRCTRL_MRCTRL0_MR_TYPE_WRITE 0
/* only one rank supported */
#define DDRCTRL_MRCTRL0_MR_RANK_SHIFT 4
#define DDRCTRL_MRCTRL0_MR_RANK_ALL \
(0x1 << DDRCTRL_MRCTRL0_MR_RANK_SHIFT)
#define DDRCTRL_MRCTRL0_MR_ADDR_SHIFT 12
#define DDRCTRL_MRCTRL0_MR_ADDR_MASK GENMASK(15, 12)
#define DDRCTRL_MRCTRL0_MR_WR BIT(31)
#define DDRCTRL_MRSTAT_MR_WR_BUSY BIT(0)
#define DDRCTRL_PWRCTL_POWERDOWN_EN BIT(1)
#define DDRCTRL_PWRCTL_SELFREF_SW BIT(5)
#define DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH BIT(0)
#define DDRCTRL_RFSHTMG_T_RFC_NOM_X1_X32_MASK GENMASK(27, 16)
#define DDRCTRL_RFSHTMG_T_RFC_NOM_X1_X32_SHIFT 16
#define DDRCTRL_INIT0_SKIP_DRAM_INIT_MASK (0xC0000000)
#define DDRCTRL_INIT0_SKIP_DRAM_INIT_NORMAL (BIT(30))
#define DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN BIT(0)
#define DDRCTRL_DBG1_DIS_HIF BIT(1)
#define DDRCTRL_DBGCAM_WR_DATA_PIPELINE_EMPTY BIT(29)
#define DDRCTRL_DBGCAM_RD_DATA_PIPELINE_EMPTY BIT(28)
#define DDRCTRL_DBGCAM_DBG_WR_Q_EMPTY BIT(26)
#define DDRCTRL_DBGCAM_DBG_LPR_Q_DEPTH GENMASK(12, 8)
#define DDRCTRL_DBGCAM_DBG_HPR_Q_DEPTH GENMASK(4, 0)
#define DDRCTRL_DBGCAM_DATA_PIPELINE_EMPTY \
(DDRCTRL_DBGCAM_WR_DATA_PIPELINE_EMPTY | \
DDRCTRL_DBGCAM_RD_DATA_PIPELINE_EMPTY)
#define DDRCTRL_DBGCAM_DBG_Q_DEPTH \
(DDRCTRL_DBGCAM_DBG_WR_Q_EMPTY | \
DDRCTRL_DBGCAM_DBG_LPR_Q_DEPTH | \
DDRCTRL_DBGCAM_DBG_HPR_Q_DEPTH)
#define DDRCTRL_DBGCMD_RANK0_REFRESH BIT(0)
#define DDRCTRL_DBGSTAT_RANK0_REFRESH_BUSY BIT(0)
#define DDRCTRL_SWCTL_SW_DONE BIT(0)
#define DDRCTRL_SWSTAT_SW_DONE_ACK BIT(0)
#define DDRCTRL_PCTRL_N_PORT_EN BIT(0)
/* DDRPHYC registers */
#define DDRPHYC_PIR_INIT BIT(0)
#define DDRPHYC_PIR_DLLSRST BIT(1)
#define DDRPHYC_PIR_DLLLOCK BIT(2)
#define DDRPHYC_PIR_ZCAL BIT(3)
#define DDRPHYC_PIR_ITMSRST BIT(4)
#define DDRPHYC_PIR_DRAMRST BIT(5)
#define DDRPHYC_PIR_DRAMINIT BIT(6)
#define DDRPHYC_PIR_QSTRN BIT(7)
#define DDRPHYC_PIR_ICPC BIT(16)
#define DDRPHYC_PIR_ZCALBYP BIT(30)
#define DDRPHYC_PIR_INITSTEPS_MASK GENMASK(31, 7)
#define DDRPHYC_PGCR_DFTCMP BIT(2)
#define DDRPHYC_PGCR_PDDISDX BIT(24)
#define DDRPHYC_PGCR_RFSHDT_MASK GENMASK(28, 25)
#define DDRPHYC_PGSR_IDONE BIT(0)
#define DDRPHYC_PGSR_DTERR BIT(5)
#define DDRPHYC_PGSR_DTIERR BIT(6)
#define DDRPHYC_PGSR_DFTERR BIT(7)
#define DDRPHYC_PGSR_RVERR BIT(8)
#define DDRPHYC_PGSR_RVEIRR BIT(9)
#define DDRPHYC_DLLGCR_BPS200 BIT(23)
#define DDRPHYC_ACDLLCR_DLLDIS BIT(31)
#define DDRPHYC_ZQ0CRN_ZDATA_MASK GENMASK(27, 0)
#define DDRPHYC_ZQ0CRN_ZDATA_SHIFT 0
#define DDRPHYC_ZQ0CRN_ZDEN BIT(28)
#define DDRPHYC_DXNGCR_DXEN BIT(0)
#define DDRPHYC_DXNDLLCR_DLLDIS BIT(31)
#define DDRPHYC_DXNDLLCR_SDPHASE_MASK GENMASK(17, 14)
#define DDRPHYC_DXNDLLCR_SDPHASE_SHIFT 14
#define DDRPHYC_DXNDQTR_DQDLY_SHIFT(bit) (4 * (bit))
#define DDRPHYC_DXNDQTR_DQDLY_MASK GENMASK(3, 0)
#define DDRPHYC_DXNDQTR_DQDLY_LOW_MASK GENMASK(1, 0)
#define DDRPHYC_DXNDQTR_DQDLY_HIGH_MASK GENMASK(3, 2)
#define DDRPHYC_DXNDQSTR_DQSDLY_MASK GENMASK(22, 20)
#define DDRPHYC_DXNDQSTR_DQSDLY_SHIFT 20
#define DDRPHYC_DXNDQSTR_DQSNDLY_MASK GENMASK(25, 23)
#define DDRPHYC_DXNDQSTR_DQSNDLY_SHIFT 23
#define DDRPHYC_DXNDQSTR_R0DGSL_MASK GENMASK(2, 0)
#define DDRPHYC_DXNDQSTR_R0DGSL_SHIFT 0
#define DDRPHYC_DXNDQSTR_R0DGPS_MASK GENMASK(13, 12)
#define DDRPHYC_DXNDQSTR_R0DGPS_SHIFT 12
#define DDRPHYC_BISTRR_BDXSEL_MASK GENMASK(22, 19)
#define DDRPHYC_BISTRR_BDXSEL_SHIFT 19
#define DDRPHYC_BISTGSR_BDDONE BIT(0)
#define DDRPHYC_BISTGSR_BDXERR BIT(2)
#define DDRPHYC_BISTWCSR_DXWCNT_SHIFT 16
/* PWR registers */
#define PWR_CR3 0x00C
#define PWR_CR3_DDRSRDIS BIT(11)
#define PWR_CR3_DDRRETEN BIT(12)
#endif

@ -0,0 +1,197 @@
/*
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause
*/
#include <common.h>
#include <clk.h>
#include <dm.h>
#include <ram.h>
#include <regmap.h>
#include <syscon.h>
#include <asm/io.h>
#include "stm32mp1_ddr.h"
DECLARE_GLOBAL_DATA_PTR;
static const char *const clkname[] = {
"ddrc1",
"ddrc2",
"ddrcapb",
"ddrphycapb",
"ddrphyc" /* LAST clock => used for get_rate() */
};
int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint16_t mem_speed)
{
unsigned long ddrphy_clk;
unsigned long ddr_clk;
struct clk clk;
int ret;
int idx;
for (idx = 0; idx < ARRAY_SIZE(clkname); idx++) {
ret = clk_get_by_name(priv->dev, clkname[idx], &clk);
if (!ret)
ret = clk_enable(&clk);
if (ret) {
printf("error for %s : %d\n", clkname[idx], ret);
return ret;
}
}
priv->clk = clk;
ddrphy_clk = clk_get_rate(&priv->clk);
debug("DDR: mem_speed (%d MHz), RCC %d MHz\n",
mem_speed, (u32)(ddrphy_clk / 1000 / 1000));
/* max 10% frequency delta */
ddr_clk = abs(ddrphy_clk - mem_speed * 1000 * 1000);
if (ddr_clk > (mem_speed * 1000 * 100)) {
pr_err("DDR expected freq %d MHz, current is %d MHz\n",
mem_speed, (u32)(ddrphy_clk / 1000 / 1000));
return -EINVAL;
}
return 0;
}
static __maybe_unused int stm32mp1_ddr_setup(struct udevice *dev)
{
struct ddr_info *priv = dev_get_priv(dev);
int ret, idx;
struct clk axidcg;
struct stm32mp1_ddr_config config;
#define PARAM(x, y) \
{ x,\
offsetof(struct stm32mp1_ddr_config, y),\
sizeof(config.y) / sizeof(u32)}
#define CTL_PARAM(x) PARAM("st,ctl-"#x, c_##x)
#define PHY_PARAM(x) PARAM("st,phy-"#x, p_##x)
const struct {
const char *name; /* name in DT */
const u32 offset; /* offset in config struct */
const u32 size; /* size of parameters */
} param[] = {
CTL_PARAM(reg),
CTL_PARAM(timing),
CTL_PARAM(map),
CTL_PARAM(perf),
PHY_PARAM(reg),
PHY_PARAM(timing),
PHY_PARAM(cal)
};
config.info.speed = dev_read_u32_default(dev, "st,mem-speed", 0);
config.info.size = dev_read_u32_default(dev, "st,mem-size", 0);
config.info.name = dev_read_string(dev, "st,mem-name");
if (!config.info.name) {
debug("%s: no st,mem-name\n", __func__);
return -EINVAL;
}
printf("RAM: %s\n", config.info.name);
for (idx = 0; idx < ARRAY_SIZE(param); idx++) {
ret = dev_read_u32_array(dev, param[idx].name,
(void *)((u32)&config +
param[idx].offset),
param[idx].size);
debug("%s: %s[0x%x] = %d\n", __func__,
param[idx].name, param[idx].size, ret);
if (ret) {
pr_err("%s: Cannot read %s\n",
__func__, param[idx].name);
return -EINVAL;
}
}
ret = clk_get_by_name(dev, "axidcg", &axidcg);
if (ret) {
debug("%s: Cannot found axidcg\n", __func__);
return -EINVAL;
}
clk_disable(&axidcg); /* disable clock gating during init */
stm32mp1_ddr_init(priv, &config);
clk_enable(&axidcg); /* enable clock gating */
/* check size */
debug("%s : get_ram_size(%x, %x)\n", __func__,
(u32)priv->info.base, (u32)STM32_DDR_SIZE);
priv->info.size = get_ram_size((long *)priv->info.base,
STM32_DDR_SIZE);
debug("%s : %x\n", __func__, (u32)priv->info.size);
/* check memory access for all memory */
if (config.info.size != priv->info.size) {
printf("DDR invalid size : 0x%x, expected 0x%x\n",
priv->info.size, config.info.size);
return -EINVAL;
}
return 0;
}
static int stm32mp1_ddr_probe(struct udevice *dev)
{
struct ddr_info *priv = dev_get_priv(dev);
struct regmap *map;
int ret;
debug("STM32MP1 DDR probe\n");
priv->dev = dev;
ret = regmap_init_mem(dev, &map);
if (ret)
return ret;
priv->ctl = regmap_get_range(map, 0);
priv->phy = regmap_get_range(map, 1);
priv->rcc = STM32_RCC_BASE;
priv->info.base = STM32_DDR_BASE;
#if !defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD)
priv->info.size = 0;
return stm32mp1_ddr_setup(dev);
#else
priv->info.size = dev_read_u32_default(dev, "st,mem-size", 0);
return 0;
#endif
}
static int stm32mp1_ddr_get_info(struct udevice *dev, struct ram_info *info)
{
struct ddr_info *priv = dev_get_priv(dev);
*info = priv->info;
return 0;
}
static struct ram_ops stm32mp1_ddr_ops = {
.get_info = stm32mp1_ddr_get_info,
};
static const struct udevice_id stm32mp1_ddr_ids[] = {
{ .compatible = "st,stm32mp1-ddr" },
{ }
};
U_BOOT_DRIVER(ddr_stm32mp1) = {
.name = "stm32mp1_ddr",
.id = UCLASS_RAM,
.of_match = stm32mp1_ddr_ids,
.ops = &stm32mp1_ddr_ops,
.probe = stm32mp1_ddr_probe,
.priv_auto_alloc_size = sizeof(struct ddr_info),
};
Loading…
Cancel
Save