- Add various STM32MP1 fixes for serial, env, clk, board, i2c ...

- Add STM32MP1 DDR driver update:
 	These update introduce the DDR interactive mode described in:
 	https://wiki.st.com/stm32mpu/index.php/U-Boot_SPL:_DDR_interactive_mode
 
 	This mode is used by the CubeMX: DDR tuning tool.
 	https://wiki.st.com/stm32mpu/index.php/STM32CubeMX
 
 	The DDR interactive mode is NOT activated by default because
 	it increase the SPL size and slow down the boot time
 	(200ms wait added).
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJc5rdIAAoJEMrHeC97M/+mw64P/0jD3C1jvtwkzFQ2DPvnSQEk
 iTZHMb91/9GncSY0S2Cgn8a2+m24F7YFLqibKSdduLLr/w98Zfi7kmO+ju/Kn+qE
 aG6iomyour8+Pr+1LMPolsKKM8lULSgrd4ALRA5CegNsXijvYEE7N8mPrBpdIQem
 BaM4HnQpbtxXU9J/rGHAVagLuHbJmwBvZBQTBAWfQdNR5+vGfplH2sF0cxJF5UTW
 06yBXrwjLW6PEVYZbzYiRQ5Gn7BnBe4nXrl4ReDtS5e4ueRKM166TZljvNCd60KI
 B49eLxd0wT2Zutsz1rT5c/LChXo3cr8FXM3csJ6J6cIBdfFF3frHbIEDM2jZTxJf
 jN7pAHpxbRdYS/GbWS5mSuUyKmxDPt6Kfd7LQUYX9qktqeLG9LfkrmLfGdCSiwkB
 64Z15DoHAuDMab+LlV+rz8ns3YAV0ruFryWfZ8udLWuX3G6NDmivafLR3dgNRdNB
 otkyCdIlq8GQUm3w+5r9wm7aGvHB3UtNYK870AnYA20vmn/WVuUBZ6yE+lce/QpV
 zFS4dgsdbn41EXO/O9TtwMyKT+/s138u2+L7CEegXiNneJmwzbJg3YPeMuaiF8Y2
 oYqlUmfVO/ZuoVvr5dwo4TY96nEhRf2Ul36spRdrx8wBZ0YdL+ByDO5Pcc2B9A+P
 M80QqlT64BJDJ1CqhW5m
 =meeB
 -----END PGP SIGNATURE-----

Merge tag 'u-boot-stm32-20190523' of https://github.com/pchotard/u-boot

- Add various STM32MP1 fixes for serial, env, clk, board, i2c ...

- Add STM32MP1 DDR driver update:
	These update introduce the DDR interactive mode described in:
	https://wiki.st.com/stm32mpu/index.php/U-Boot_SPL:_DDR_interactive_mode

	This mode is used by the CubeMX: DDR tuning tool.
	https://wiki.st.com/stm32mpu/index.php/STM32CubeMX

	The DDR interactive mode is NOT activated by default because
	it increase the SPL size and slow down the boot time
	(200ms wait added).
This commit is contained in:
Tom Rini 2019-05-24 08:13:27 -04:00
commit 866a78dc28
32 changed files with 4307 additions and 259 deletions

View File

@ -147,7 +147,7 @@ config SYS_MALLOC_F_LEN
config SYS_MALLOC_LEN
hex "Define memory for Dynamic allocation"
depends on ARCH_ZYNQ || ARCH_VERSAL
depends on ARCH_ZYNQ || ARCH_VERSAL || ARCH_STM32MP
help
This defines memory to be allocated for Dynamic allocation
TODO: Use for other architectures

View File

@ -1488,6 +1488,7 @@ config ARCH_STM32MP
imply CMD_DM
imply CMD_POWEROFF
imply ENV_VARS_UBOOT_RUNTIME_CONFIG
imply USE_PREBOOT
help
Support for STM32MP SoC family developed by STMicroelectronics,
MPUs based on ARM cortex A core

View File

@ -49,6 +49,9 @@ unsigned long long get_ticks(void)
ulong timer_get_boot_us(void)
{
if (!gd->arch.timer_rate_hz)
timer_init();
return lldiv(get_ticks(), gd->arch.timer_rate_hz / 1000000);
}

View File

@ -16,8 +16,8 @@
* address mapping : RBC
* Tc > + 85C : N
*/
#define DDR_MEM_NAME "DDR3-1066/888 bin G 1x4Gb 533MHz v1.43"
#define DDR_MEM_SPEED 533
#define DDR_MEM_NAME "DDR3-1066/888 bin G 1x4Gb 533MHz v1.44"
#define DDR_MEM_SPEED 533000
#define DDR_MEM_SIZE 0x20000000
#define DDR_MSTR 0x00041401
@ -108,11 +108,11 @@
#define DDR_DX1DLLCR 0x40000000
#define DDR_DX1DQTR 0xFFFFFFFF
#define DDR_DX1DQSTR 0x3DB02000
#define DDR_DX2GCR 0x0000CE81
#define DDR_DX2GCR 0x0000CE80
#define DDR_DX2DLLCR 0x40000000
#define DDR_DX2DQTR 0xFFFFFFFF
#define DDR_DX2DQSTR 0x3DB02000
#define DDR_DX3GCR 0x0000CE81
#define DDR_DX3GCR 0x0000CE80
#define DDR_DX3DLLCR 0x40000000
#define DDR_DX3DQTR 0xFFFFFFFF
#define DDR_DX3DQSTR 0x3DB02000

View File

@ -1,9 +1,8 @@
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
/*
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
*/
/* STM32MP157C ED1 and ED2 BOARD configuration
*
* STM32MP157C ED1 BOARD configuration
* 2x DDR3L 4Gb each, 16-bit, 533MHz, Single Die Package in flyby topology.
* Reference used NT5CC256M16DP-DI from NANYA
*
@ -15,10 +14,11 @@
* timing mode optimized
* Scheduling/QoS options : type = 2
* address mapping : RBC
* Tc > + 85C : N
*/
#define DDR_MEM_NAME "DDR3-1066 bin G 2x4Gb 533MHz v1.36"
#define DDR_MEM_SPEED 533
#define DDR_MEM_NAME "DDR3-1066/888 bin G 2x4Gb 533MHz v1.44"
#define DDR_MEM_SPEED 533000
#define DDR_MEM_SIZE 0x40000000
#define DDR_MSTR 0x00040401
@ -62,7 +62,7 @@
#define DDR_ADDRMAP11 0x00000000
#define DDR_ODTCFG 0x06000600
#define DDR_ODTMAP 0x00000001
#define DDR_SCHED 0x00001201
#define DDR_SCHED 0x00000C01
#define DDR_SCHED1 0x00000000
#define DDR_PERFHPR1 0x01000001
#define DDR_PERFLPR1 0x08000200
@ -74,15 +74,15 @@
#define DDR_PCCFG 0x00000010
#define DDR_PCFGR_0 0x00010000
#define DDR_PCFGW_0 0x00000000
#define DDR_PCFGQOS0_0 0x02100B03
#define DDR_PCFGQOS0_0 0x02100C03
#define DDR_PCFGQOS1_0 0x00800100
#define DDR_PCFGWQOS0_0 0x01100B03
#define DDR_PCFGWQOS0_0 0x01100C03
#define DDR_PCFGWQOS1_0 0x01000200
#define DDR_PCFGR_1 0x00010000
#define DDR_PCFGW_1 0x00000000
#define DDR_PCFGQOS0_1 0x02100B03
#define DDR_PCFGQOS1_1 0x00800100
#define DDR_PCFGWQOS0_1 0x01100B03
#define DDR_PCFGQOS0_1 0x02100C03
#define DDR_PCFGQOS1_1 0x00800040
#define DDR_PCFGWQOS0_1 0x01100C03
#define DDR_PCFGWQOS1_1 0x01000200
#define DDR_PGCR 0x01442E02
#define DDR_PTR0 0x0022AA5B
@ -100,7 +100,7 @@
#define DDR_MR2 0x00000208
#define DDR_MR3 0x00000000
#define DDR_ODTCR 0x00010000
#define DDR_ZQ0CR1 0x0000005B
#define DDR_ZQ0CR1 0x00000038
#define DDR_DX0GCR 0x0000CE81
#define DDR_DX0DLLCR 0x40000000
#define DDR_DX0DQTR 0xFFFFFFFF

View File

@ -17,12 +17,20 @@ config SPL
select SPL_DM_RESET
select SPL_SERIAL_SUPPORT
select SPL_SYSCON
imply BOOTSTAGE_STASH if SPL_BOOTSTAGE
imply SPL_BOOTSTAGE if BOOTSTAGE
imply SPL_DISPLAY_PRINT
imply SPL_LIBDISK_SUPPORT
config SYS_SOC
default "stm32mp"
config SYS_MALLOC_LEN
default 0x2000000
config ENV_SIZE
default 0x1000
config TARGET_STM32MP1
bool "Support stm32mp1xx"
select ARCH_SUPPORT_PSCI if !STM32MP1_TRUSTED
@ -33,6 +41,10 @@ config TARGET_STM32MP1
select STM32_RCC
select STM32_RESET
select SYS_ARCH_TIMER
imply BOOTCOUNT_LIMIT
imply BOOTSTAGE
imply CMD_BOOTCOUNT
imply CMD_BOOTSTAGE
imply SYSRESET_PSCI if STM32MP1_TRUSTED
imply SYSRESET_SYSCON if !STM32MP1_TRUSTED
help
@ -70,6 +82,18 @@ config SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION_MMC2
Partition on the second MMC to load U-Boot from when the MMC is being
used in raw mode
config BOOTSTAGE_STASH_ADDR
default 0xC3000000
if BOOTCOUNT_LIMIT
config SYS_BOOTCOUNT_SINGLEWORD
default y
# TAMP_BOOTCOUNT = TAMP_BACKUP_REGISTER(21)
config SYS_BOOTCOUNT_ADDR
default 0x5C00A154
endif
if DEBUG_UART
config DEBUG_UART_BOARD_INIT

View File

@ -7,9 +7,9 @@
#include <dm.h>
#include <misc.h>
#include <asm/io.h>
#include <linux/iopoll.h>
#include <asm/arch/stm32mp1_smc.h>
#include <linux/arm-smccc.h>
#include <linux/iopoll.h>
#define BSEC_OTP_MAX_VALUE 95

View File

@ -6,6 +6,13 @@
#ifndef __MACH_STM32MP_DDR_H_
#define __MACH_STM32MP_DDR_H_
int board_ddr_power_init(void);
/* DDR power initializations */
enum ddr_type {
STM32MP_DDR3,
STM32MP_LPDDR2,
STM32MP_LPDDR3,
};
int board_ddr_power_init(enum ddr_type ddr_type);
#endif

View File

@ -88,6 +88,7 @@ enum boot_device {
#define TAMP_BACKUP_MAGIC_NUMBER TAMP_BACKUP_REGISTER(4)
#define TAMP_BACKUP_BRANCH_ADDRESS TAMP_BACKUP_REGISTER(5)
#define TAMP_BOOT_CONTEXT TAMP_BACKUP_REGISTER(20)
#define TAMP_BOOTCOUNT TAMP_BACKUP_REGISTER(21)
#define TAMP_BOOT_MODE_MASK GENMASK(15, 8)
#define TAMP_BOOT_MODE_SHIFT 8

View File

@ -47,14 +47,14 @@ static u32 __secure stm32mp_get_gicd_base_address(void)
return (periphbase & CBAR_MASK) + GIC_DIST_OFFSET;
}
static void __secure stm32mp_smp_kick_all_cpus(void)
static void __secure stm32mp_raise_sgi0(int cpu)
{
u32 gic_dist_addr;
gic_dist_addr = stm32mp_get_gicd_base_address();
/* kick all CPUs (except this one) by writing to GICD_SGIR */
writel(1U << 24, gic_dist_addr + GICD_SGIR);
/* ask cpu with SGI0 */
writel((BIT(cpu) << 16), gic_dist_addr + GICD_SGIR);
}
void __secure psci_arch_cpu_entry(void)
@ -62,6 +62,9 @@ void __secure psci_arch_cpu_entry(void)
u32 cpu = psci_get_cpu_id();
psci_set_state(cpu, PSCI_AFFINITY_LEVEL_ON);
/* reset magic in TAMP register */
writel(0xFFFFFFFF, TAMP_BACKUP_MAGIC_NUMBER);
}
int __secure psci_features(u32 function_id, u32 psci_fid)
@ -127,6 +130,16 @@ int __secure psci_cpu_on(u32 function_id, u32 target_cpu, u32 pc,
if (psci_state[cpu] == PSCI_AFFINITY_LEVEL_ON)
return ARM_PSCI_RET_ALREADY_ON;
/* reset magic in TAMP register */
if (readl(TAMP_BACKUP_MAGIC_NUMBER))
writel(0xFFFFFFFF, TAMP_BACKUP_MAGIC_NUMBER);
/*
* ROM code need a first SGI0 after core reset
* core is ready when magic is set to 0 in ROM code
*/
while (readl(TAMP_BACKUP_MAGIC_NUMBER))
stm32mp_raise_sgi0(cpu);
/* store target PC and context id*/
psci_save(cpu, pc, context_id);
@ -142,7 +155,8 @@ int __secure psci_cpu_on(u32 function_id, u32 target_cpu, u32 pc,
writel(BOOT_API_A7_CORE0_MAGIC_NUMBER,
TAMP_BACKUP_MAGIC_NUMBER);
stm32mp_smp_kick_all_cpus();
/* Generate an IT to start the core */
stm32mp_raise_sgi0(cpu);
return ARM_PSCI_RET_SUCCESS;
}

View File

@ -38,9 +38,10 @@ void board_debug_uart_init(void)
#endif
#ifdef CONFIG_PMIC_STPMIC1
int board_ddr_power_init(void)
int board_ddr_power_init(enum ddr_type ddr_type)
{
struct udevice *dev;
bool buck3_at_1800000v = false;
int ret;
ret = uclass_get_device_by_driver(UCLASS_PMIC,
@ -49,53 +50,127 @@ int board_ddr_power_init(void)
/* No PMIC on board */
return 0;
/* VTT = Set LDO3 to sync mode */
ret = pmic_reg_read(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3));
if (ret < 0)
return ret;
switch (ddr_type) {
case STM32MP_DDR3:
/* VTT = Set LDO3 to sync mode */
ret = pmic_reg_read(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3));
if (ret < 0)
return ret;
ret &= ~STPMIC1_LDO3_MODE;
ret &= ~STPMIC1_LDO12356_VOUT_MASK;
ret |= STPMIC1_LDO_VOUT(STPMIC1_LDO3_DDR_SEL);
ret &= ~STPMIC1_LDO3_MODE;
ret &= ~STPMIC1_LDO12356_VOUT_MASK;
ret |= STPMIC1_LDO_VOUT(STPMIC1_LDO3_DDR_SEL);
ret = pmic_reg_write(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3),
ret);
if (ret < 0)
return ret;
ret = pmic_reg_write(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3),
ret);
if (ret < 0)
return ret;
/* VDD_DDR = Set BUCK2 to 1.35V */
ret = pmic_clrsetbits(dev,
STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK2),
STPMIC1_BUCK_VOUT_MASK,
STPMIC1_BUCK2_1350000V);
if (ret < 0)
return ret;
/* VDD_DDR = Set BUCK2 to 1.35V */
ret = pmic_clrsetbits(dev,
STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK2),
STPMIC1_BUCK_VOUT_MASK,
STPMIC1_BUCK2_1350000V);
if (ret < 0)
return ret;
/* Enable VDD_DDR = BUCK2 */
ret = pmic_clrsetbits(dev,
STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK2),
STPMIC1_BUCK_ENA, STPMIC1_BUCK_ENA);
if (ret < 0)
return ret;
/* Enable VDD_DDR = BUCK2 */
ret = pmic_clrsetbits(dev,
STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK2),
STPMIC1_BUCK_ENA, STPMIC1_BUCK_ENA);
if (ret < 0)
return ret;
mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
/* Enable VREF */
ret = pmic_clrsetbits(dev, STPMIC1_REFDDR_MAIN_CR,
STPMIC1_VREF_ENA, STPMIC1_VREF_ENA);
if (ret < 0)
return ret;
/* Enable VREF */
ret = pmic_clrsetbits(dev, STPMIC1_REFDDR_MAIN_CR,
STPMIC1_VREF_ENA, STPMIC1_VREF_ENA);
if (ret < 0)
return ret;
mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
/* Enable LDO3 */
ret = pmic_clrsetbits(dev,
STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3),
STPMIC1_LDO_ENA, STPMIC1_LDO_ENA);
if (ret < 0)
return ret;
/* Enable VTT = LDO3 */
ret = pmic_clrsetbits(dev,
STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3),
STPMIC1_LDO_ENA, STPMIC1_LDO_ENA);
if (ret < 0)
return ret;
mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
break;
case STM32MP_LPDDR2:
case STM32MP_LPDDR3:
/*
* configure VDD_DDR1 = LDO3
* Set LDO3 to 1.8V
* + bypass mode if BUCK3 = 1.8V
* + normal mode if BUCK3 != 1.8V
*/
ret = pmic_reg_read(dev,
STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK3));
if (ret < 0)
return ret;
if ((ret & STPMIC1_BUCK3_1800000V) == STPMIC1_BUCK3_1800000V)
buck3_at_1800000v = true;
ret = pmic_reg_read(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3));
if (ret < 0)
return ret;
ret &= ~STPMIC1_LDO3_MODE;
ret &= ~STPMIC1_LDO12356_VOUT_MASK;
ret |= STPMIC1_LDO3_1800000;
if (buck3_at_1800000v)
ret |= STPMIC1_LDO3_MODE;
ret = pmic_reg_write(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3),
ret);
if (ret < 0)
return ret;
/* VDD_DDR2 : Set BUCK2 to 1.2V */
ret = pmic_clrsetbits(dev,
STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK2),
STPMIC1_BUCK_VOUT_MASK,
STPMIC1_BUCK2_1200000V);
if (ret < 0)
return ret;
/* Enable VDD_DDR1 = LDO3 */
ret = pmic_clrsetbits(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3),
STPMIC1_LDO_ENA, STPMIC1_LDO_ENA);
if (ret < 0)
return ret;
mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
/* Enable VDD_DDR2 =BUCK2 */
ret = pmic_clrsetbits(dev,
STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK2),
STPMIC1_BUCK_ENA, STPMIC1_BUCK_ENA);
if (ret < 0)
return ret;
mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
/* Enable VREF */
ret = pmic_clrsetbits(dev, STPMIC1_REFDDR_MAIN_CR,
STPMIC1_VREF_ENA, STPMIC1_VREF_ENA);
if (ret < 0)
return ret;
mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
break;
default:
break;
};
return 0;
}

View File

@ -247,6 +247,7 @@ config USE_PREBOOT
config PREBOOT
string "preboot default value"
depends on USE_PREBOOT
default ""
help
This is the default of "preboot" environment variable.

View File

@ -124,6 +124,7 @@ endif
obj-y += cli.o
obj-$(CONFIG_FSL_DDR_INTERACTIVE) += cli_simple.o cli_readline.o
obj-$(CONFIG_STM32MP1_DDR_INTERACTIVE) += cli_simple.o cli_readline.o
obj-$(CONFIG_DFU_OVER_USB) += dfu.o
obj-y += command.o
obj-$(CONFIG_$(SPL_TPL_)LOG) += log.o

View File

@ -1,185 +1,186 @@
STMicroelectronics STM32MP1 clock tree initialization
=====================================================
The STM32MP clock tree initialization is based on device tree information
for RCC IP and on fixed clocks.
The STM32MP1 clock tree initialization is based on device tree information
for RCC IP node (st,stm32mp1-rcc) and on fixed-clock nodes.
-------------------------------
RCC CLOCK = st,stm32mp1-rcc-clk
-------------------------------
RCC IP = st,stm32mp1-rcc
========================
The RCC IP is both a reset and a clock controller but this documentation only
describes the fields added for clock tree initialization which are not present
in Linux binding.
in Linux binding for compatible "st,stm32mp1-rcc" defined in st,stm32mp1-rcc.txt
file.
Please refer to ../mfd/st,stm32-rcc.txt for all the other properties common
with Linux.
The added properties for clock tree initialization are:
Required properties:
- st,clksrc : The clock sources configuration array in a platform specific
order.
- compatible: Should be "st,stm32mp1-rcc-clk"
For the STM32MP15x family there are 9 clock sources selector which are
configured in the following order:
MPU AXI MCU PLL12 PLL3 PLL4 RTC MCO1 MCO2
- st,clksrc : The clock source in this order
Clock source configuration values are defined by macros CLK_<NAME>_<SOURCE>
from dt-bindings/clock/stm32mp1-clksrc.h.
for STM32MP15x: 9 clock sources are requested
MPU AXI MCU PLL12 PLL3 PLL4 RTC MCO1 MCO2
Example:
st,clksrc = <
CLK_MPU_PLL1P
CLK_AXI_PLL2P
CLK_MCU_PLL3P
CLK_PLL12_HSE
CLK_PLL3_HSE
CLK_PLL4_HSE
CLK_RTC_LSE
CLK_MCO1_DISABLED
CLK_MCO2_DISABLED
>;
with value equals to RCC clock specifier as defined in
dt-bindings/clock/stm32mp1-clksrc.h: CLK_<NAME>_<SOURCE>
- st,clkdiv : The clock main dividers value specified in an array
in a platform specific order.
- st,clkdiv : The div parameters in this order
for STM32MP15x: 11 dividers value are requested
When used, it shall describe the whole clock dividers tree.
For the STM32MP15x family there are 11 dividers values expected.
They shall be configured in the following order:
MPU AXI MCU APB1 APB2 APB3 APB4 APB5 RTC MCO1 MCO2
with DIV coding defined in RCC associated register RCC_xxxDIVR
most the case, it is:
The each divider value uses the DIV coding defined in RCC associated
register RCC_xxxDIVR. In most the case, it is:
0x0: not divided
0x1: division by 2
0x2: division by 4
0x3: division by 8
...
but for RTC MCO1 MCO2, the coding is different:
Note that for RTC MCO1 MCO2, the coding is different:
0x0: not divided
0x1: division by 2
0x2: division by 3
0x3: division by 4
...
Optional Properties:
- st,pll
PLL children node for PLL1 to PLL4 : (see ref manual for details)
with associated index 0 to 3 (st,pll@0 to st,pll@4)
PLLx is off when the associated node is absent
- Sub-nodes:
- cfg: The parameters for PLL configuration in this order:
DIVM DIVN DIVP DIVQ DIVR Output
with DIV value as defined in RCC spec:
0x0: bypass (division by 1)
0x1: division by 2
0x2: division by 3
0x3: division by 4
...
and Output = bitfield for each output value = 1:ON/0:OFF
BIT(0) => output P : DIVPEN
BIT(1) => output Q : DIVQEN
BIT(2) => output R : DIVREN
NB : macro PQR(p,q,r) can be used to build this value
with p,p,r = 0 or 1
- frac : Fractional part of the multiplication factor
(optional, PLL is in integer mode when absent)
- csg : Clock Spreading Generator (optional)
with parameters in this order:
MOD_PER INC_STEP SSCG_MODE
* MOD_PER: Modulation Period Adjustment
* INC_STEP: Modulation Depth Adjustment
* SSCG_MODE: Spread spectrum clock generator mode
you can use associated defines from stm32mp1-clksrc.h
* SSCG_MODE_CENTER_SPREAD = 0
* SSCG_MODE_DOWN_SPREAD = 1
- st,pkcs : used to configure the peripherals kernel clock selection
containing a list of peripheral kernel clock source identifier as defined
in the file dt-bindings/clock/stm32mp1-clksrc.h
Example:
st,clkdiv = <
1 /*MPU*/
0 /*AXI*/
0 /*MCU*/
1 /*APB1*/
1 /*APB2*/
1 /*APB3*/
1 /*APB4*/
2 /*APB5*/
23 /*RTC*/
0 /*MCO1*/
0 /*MCO2*/
>;
rcc: rcc@50000000 {
compatible = "syscon", "simple-mfd";
Optional Properties:
- st,pll : A specific PLL configuration, including frequency.
reg = <0x50000000 0x1000>;
PLL children nodes for PLL1 to PLL4 (see ref manual for details)
are listed with associated index 0 to 3 (st,pll@0 to st,pll@3).
PLLx is off when the associated node is absent.
rcc_clk: rcc-clk@50000000 {
#clock-cells = <1>;
compatible = "st,stm32mp1-rcc-clk";
Here are the available properties for each PLL node:
st,clksrc = < CLK_MPU_PLL1P
CLK_AXI_PLL2P
CLK_MCU_HSI
CLK_PLL12_HSE
CLK_PLL3_HSE
CLK_PLL4_HSE
CLK_RTC_HSE
CLK_MCO1_DISABLED
CLK_MCO2_DISABLED
>;
- cfg: The parameters for PLL configuration in the following order:
DIVM DIVN DIVP DIVQ DIVR Output.
st,clkdiv = <
1 /*MPU*/
0 /*AXI*/
0 /*MCU*/
1 /*APB1*/
1 /*APB2*/
1 /*APB3*/
1 /*APB4*/
5 /*APB5*/
23 /*RTC*/
0 /*MCO1*/
0 /*MCO2*/
>;
DIVx values are defined as in RCC spec:
0x0: bypass (division by 1)
0x1: division by 2
0x2: division by 3
0x3: division by 4
...
st,pll@0 {
cfg = < 1 53 0 0 0 1 >;
frac = < 0x810 >;
};
st,pll@1 {
cfg = < 1 43 1 0 0 PQR(0,1,1) >;
csg = < 10 20 1 >;
};
st,pll@2 {
cfg = < 2 85 3 13 3 0 >;
csg = < 10 20 SSCG_MODE_CENTER_SPREAD >;
};
st,pll@3 {
cfg = < 2 78 4 7 9 3 >;
};
st,pkcs = <
CLK_STGEN_HSE
CLK_CKPER_HSI
CLK_USBPHY_PLL2P
CLK_DSI_PLL2Q
>;
Output contains a bitfield for each output value (1:ON/0:OFF)
BIT(0) => output P : DIVPEN
BIT(1) => output Q : DIVQEN
BIT(2) => output R : DIVREN
NB: macro PQR(p,q,r) can be used to build this value
with p,q,r = 0 or 1.
- frac : Fractional part of the multiplication factor
(optional, PLL is in integer mode when absent).
- csg : Clock Spreading Generator (optional) with parameters in the
following order: MOD_PER INC_STEP SSCG_MODE.
MOD_PER: Modulation Period Adjustment
INC_STEP: Modulation Depth Adjustment
SSCG_MODE: Spread spectrum clock generator mode, with associated
defined from stm32mp1-clksrc.h:
- SSCG_MODE_CENTER_SPREAD = 0
- SSCG_MODE_DOWN_SPREAD = 1
Example:
st,pll@0 {
cfg = < 1 53 0 0 0 1 >;
frac = < 0x810 >;
};
st,pll@1 {
cfg = < 1 43 1 0 0 PQR(0,1,1) >;
csg = < 10 20 1 >;
};
st,pll@2 {
cfg = < 2 85 3 13 3 0 >;
csg = < 10 20 SSCG_MODE_CENTER_SPREAD >;
};
st,pll@3 {
cfg = < 2 78 4 7 9 3 >;
};
--------------------------
- st,pkcs : used to configure the peripherals kernel clock selection.
The property is a list of peripheral kernel clock source identifiers defined
by macros CLK_<KERNEL-CLOCK>_<PARENT-CLOCK> as defined by header file
dt-bindings/clock/stm32mp1-clksrc.h.
st,pkcs may not list all the kernel clocks and has no ordering requirements.
Example:
st,pkcs = <
CLK_STGEN_HSE
CLK_CKPER_HSI
CLK_USBPHY_PLL2P
CLK_DSI_PLL2Q
CLK_I2C46_HSI
CLK_UART1_HSI
CLK_UART24_HSI
>;
other clocks = fixed-clock
--------------------------
==========================
The clock tree is also based on 5 fixed-clock in clocks node
used to define the state of associated ST32MP1 oscillators:
- clk-lsi
- clk-lse
- clk-hsi
- clk-hse
- clk-csi
- clk-lsi
- clk-lse
- clk-hsi
- clk-hse
- clk-csi
At boot the clock tree initialization will
- enable the oscillator present in device tree
- disable HSI oscillator if the node is absent (always activated by bootrom)
- enable oscillators present in device tree
- disable HSI oscillator if the node is absent (always activated by bootrom)
Optional properties :
a) for external oscillator: "clk-lse", "clk-hse"
4 optional fields are managed
- "st,bypass" Configure the oscillator bypass mode (HSEBYP, LSEBYP)
- "st,digbypass" Configure the bypass mode as full-swing digital signal
(DIGBYP)
- "st,css" Activate the clock security system (HSECSSON, LSECSSON)
- "st,drive" (only for LSE) value of the drive for the oscillator
(see LSEDRV_ define in the file dt-bindings/clock/stm32mp1-clksrc.h)
Example board file:
4 optional fields are managed
- "st,bypass" configures the oscillator bypass mode (HSEBYP, LSEBYP)
- "st,digbypass" configures the bypass mode as full-swing digital
signal (DIGBYP)
- "st,css" activates the clock security system (HSECSSON, LSECSSON)
- "st,drive" (only for LSE) contains the value of the drive for the
oscillator (see LSEDRV_ defined in the file
dt-bindings/clock/stm32mp1-clksrc.h)
Example board file:
/ {
clocks {
clk_hse: clk-hse {
@ -200,13 +201,12 @@ a) for external oscillator: "clk-lse", "clk-hse"
b) for internal oscillator: "clk-hsi"
internally HSI clock is fixed to 64MHz for STM32MP157 soc
in device tree clk-hsi is the clock after HSIDIV (ck_hsi in RCC doc)
So this clock frequency is used to compute the expected HSI_DIV
for the clock tree initialisation
ex: for HSIDIV = /1
Internally HSI clock is fixed to 64MHz for STM32MP157 SoC.
In device tree, clk-hsi is the clock after HSIDIV (clk_hsi in RCC
doc). So this clock frequency is used to compute the expected HSI_DIV
for the clock tree initialization.
Example with HSIDIV = /1:
/ {
clocks {
clk_hsi: clk-hsi {
@ -216,8 +216,7 @@ b) for internal oscillator: "clk-hsi"
};
};
ex: for HSIDIV = /2
Example with HSIDIV = /2
/ {
clocks {
clk_hsi: clk-hsi {
@ -226,3 +225,151 @@ b) for internal oscillator: "clk-hsi"
clock-frequency = <32000000>;
};
};
Example of clock tree initialization
====================================
/ {
clocks {
u-boot,dm-pre-reloc;
clk_hse: clk-hse {
u-boot,dm-pre-reloc;
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <24000000>;
st,digbypass;
};
clk_hsi: clk-hsi {
u-boot,dm-pre-reloc;
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <64000000>;
};
clk_lse: clk-lse {
u-boot,dm-pre-reloc;
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <32768>;
};
clk_lsi: clk-lsi {
u-boot,dm-pre-reloc;
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <32000>;
};
clk_csi: clk-csi {
u-boot,dm-pre-reloc;
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <4000000>;
};
};
soc {
rcc: rcc@50000000 {
u-boot,dm-pre-reloc;
compatible = "st,stm32mp1-rcc", "syscon";
reg = <0x50000000 0x1000>;
#clock-cells = <1>;
#reset-cells = <1>;
interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
st,clksrc = <
CLK_MPU_PLL1P
CLK_AXI_PLL2P
CLK_MCU_PLL3P
CLK_PLL12_HSE
CLK_PLL3_HSE
CLK_PLL4_HSE
CLK_RTC_LSE
CLK_MCO1_DISABLED
CLK_MCO2_DISABLED
>;
st,clkdiv = <
1 /*MPU*/
0 /*AXI*/
0 /*MCU*/
1 /*APB1*/
1 /*APB2*/
1 /*APB3*/
1 /*APB4*/
2 /*APB5*/
23 /*RTC*/
0 /*MCO1*/
0 /*MCO2*/
>;
st,pkcs = <
CLK_CKPER_HSE
CLK_FMC_ACLK
CLK_QSPI_ACLK
CLK_ETH_DISABLED
CLK_SDMMC12_PLL4P
CLK_DSI_DSIPLL
CLK_STGEN_HSE
CLK_USBPHY_HSE
CLK_SPI2S1_PLL3Q
CLK_SPI2S23_PLL3Q
CLK_SPI45_HSI
CLK_SPI6_HSI
CLK_I2C46_HSI
CLK_SDMMC3_PLL4P
CLK_USBO_USBPHY
CLK_ADC_CKPER
CLK_CEC_LSE
CLK_I2C12_HSI
CLK_I2C35_HSI
CLK_UART1_HSI
CLK_UART24_HSI
CLK_UART35_HSI
CLK_UART6_HSI
CLK_UART78_HSI
CLK_SPDIF_PLL4P
CLK_FDCAN_PLL4Q
CLK_SAI1_PLL3Q
CLK_SAI2_PLL3Q
CLK_SAI3_PLL3Q
CLK_SAI4_PLL3Q
CLK_RNG1_LSI
CLK_RNG2_LSI
CLK_LPTIM1_PCLK1
CLK_LPTIM23_PCLK3
CLK_LPTIM45_LSE
>;
/* VCO = 1300.0 MHz => P = 650 (CPU) */
pll1: st,pll@0 {
cfg = < 2 80 0 0 0 PQR(1,0,0) >;
frac = < 0x800 >;
u-boot,dm-pre-reloc;
};
/* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU),
R = 533 (DDR) */
pll2: st,pll@1 {
cfg = < 2 65 1 0 0 PQR(1,1,1) >;
frac = < 0x1400 >;
u-boot,dm-pre-reloc;
};
/* VCO = 417.8 MHz => P = 209, Q = 24, R = 11 */
pll3: st,pll@2 {
cfg = < 1 33 1 16 36 PQR(1,1,1) >;
frac = < 0x1a04 >;
u-boot,dm-pre-reloc;
};
/* VCO = 594.0 MHz => P = 99, Q = 74, R = 74 */
pll4: st,pll@3 {
cfg = < 3 98 5 7 7 PQR(1,1,1) >;
u-boot,dm-pre-reloc;
};
};
};
};

View File

@ -16,7 +16,7 @@ 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-speed : DDR expected speed for the setting in kHz
- st,mem-size : DDR mem size in byte
@ -102,7 +102,7 @@ controlleur attributes:
phyc attributes:
----------------
- st,phy-reg : phy values depending of the DDR type (DDR3/LPDDR2/LPDDR3)
for STM32MP15x: 10 values are requested in this order
for STM32MP15x: 11 values are requested in this order
PGCR
ACIOCR
DXCCR
@ -173,7 +173,7 @@ Example:
"ddrphycapb";
st,mem-name = "DDR3 2x4Gb 533MHz";
st,mem-speed = <533>;
st,mem-speed = <533000>;
st,mem-size = <0x40000000>;
st,ctl-reg = <

View File

@ -1448,6 +1448,71 @@ static void pll_csg(struct stm32mp1_clk_priv *priv, int pll_id, u32 *csg)
setbits_le32(priv->base + pll[pll_id].pllxcr, RCC_PLLNCR_SSCG_CTRL);
}
static __maybe_unused int pll_set_rate(struct udevice *dev,
int pll_id,
int div_id,
unsigned long clk_rate)
{
struct stm32mp1_clk_priv *priv = dev_get_priv(dev);
unsigned int pllcfg[PLLCFG_NB];
ofnode plloff;
char name[12];
const struct stm32mp1_clk_pll *pll = priv->data->pll;
enum stm32mp1_plltype type = pll[pll_id].plltype;
int divm, divn, divy;
int ret;
ulong fck_ref;
u32 fracv;
u64 value;
if (div_id > _DIV_NB)
return -EINVAL;
sprintf(name, "st,pll@%d", pll_id);
plloff = dev_read_subnode(dev, name);
if (!ofnode_valid(plloff))
return -FDT_ERR_NOTFOUND;
ret = ofnode_read_u32_array(plloff, "cfg",
pllcfg, PLLCFG_NB);
if (ret < 0)
return -FDT_ERR_NOTFOUND;
fck_ref = pll_get_fref_ck(priv, pll_id);
divm = pllcfg[PLLCFG_M];
/* select output divider = 0: for _DIV_P, 1:_DIV_Q 2:_DIV_R */
divy = pllcfg[PLLCFG_P + div_id];
/* For: PLL1 & PLL2 => VCO is * 2 but ck_pll_y is also / 2
* So same final result than PLL2 et 4
* with FRACV
* Fck_pll_y = Fck_ref * ((DIVN + 1) + FRACV / 2^13)
* / (DIVy + 1) * (DIVM + 1)
* value = (DIVN + 1) * 2^13 + FRACV / 2^13
* = Fck_pll_y (DIVy + 1) * (DIVM + 1) * 2^13 / Fck_ref
*/
value = ((u64)clk_rate * (divy + 1) * (divm + 1)) << 13;
value = lldiv(value, fck_ref);
divn = (value >> 13) - 1;
if (divn < DIVN_MIN ||
divn > stm32mp1_pll[type].divn_max) {
pr_err("divn invalid = %d", divn);
return -EINVAL;
}
fracv = value - ((divn + 1) << 13);
pllcfg[PLLCFG_N] = divn;
/* reconfigure PLL */
pll_stop(priv, pll_id);
pll_config(priv, pll_id, pllcfg, fracv);
pll_start(priv, pll_id);
pll_output(priv, pll_id, pllcfg[PLLCFG_O]);
return 0;
}
static int set_clksrc(struct stm32mp1_clk_priv *priv, unsigned int clksrc)
{
u32 address = priv->base + (clksrc >> 4);
@ -1820,6 +1885,11 @@ static ulong stm32mp1_clk_set_rate(struct clk *clk, unsigned long clk_rate)
int p;
switch (clk->id) {
#if defined(STM32MP1_CLOCK_TREE_INIT) && \
defined(CONFIG_STM32MP1_DDR_INTERACTIVE)
case DDRPHYC:
break;
#endif
case LTDC_PX:
case DSI_PX:
break;
@ -1833,6 +1903,19 @@ static ulong stm32mp1_clk_set_rate(struct clk *clk, unsigned long clk_rate)
return -EINVAL;
switch (p) {
#if defined(STM32MP1_CLOCK_TREE_INIT) && \
defined(CONFIG_STM32MP1_DDR_INTERACTIVE)
case _PLL2_R: /* DDRPHYC */
{
/* only for change DDR clock in interactive mode */
ulong result;
set_clksrc(priv, CLK_AXI_HSI);
result = pll_set_rate(clk->dev, _PLL2, _DIV_R, clk_rate);
set_clksrc(priv, CLK_AXI_PLL2P);
return result;
}
#endif
case _PLL4_Q:
/* for LTDC_PX and DSI_PX case */
return pll_set_output_rate(clk->dev, _PLL4, _DIV_Q, clk_rate);

View File

@ -500,7 +500,7 @@ static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup,
af_delay_max = setup->analog_filter ?
STM32_I2C_ANALOG_FILTER_DELAY_MAX : 0;
sdadel_min = setup->fall_time - i2c_specs[setup->speed].hddat_min -
sdadel_min = i2c_specs[setup->speed].hddat_min + setup->fall_time -
af_delay_min - (setup->dnf + 3) * i2cclk;
sdadel_max = i2c_specs[setup->speed].vddat_max - setup->rise_time -
@ -540,8 +540,12 @@ static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup,
p_prev = p;
list_add_tail(&v->node, solutions);
break;
}
}
if (p_prev == p)
break;
}
}

View File

@ -10,3 +10,40 @@ config STM32MP1_DDR
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)
config STM32MP1_DDR_INTERACTIVE
bool "STM32MP1 DDR driver : interactive support"
depends on STM32MP1_DDR
help
activate interactive support in STM32MP1 DDR controller driver
used for DDR tuning tools
to enter in intercative mode type 'd' during SPL DDR driver
initialisation
config STM32MP1_DDR_INTERACTIVE_FORCE
bool "STM32MP1 DDR driver : force interactive mode"
depends on STM32MP1_DDR_INTERACTIVE
default n
help
force interactive mode in STM32MP1 DDR controller driver
skip the polling of character 'd' in console
useful when SPL is loaded in sysram
directly by programmer
config STM32MP1_DDR_TESTS
bool "STM32MP1 DDR driver : tests support"
depends on STM32MP1_DDR_INTERACTIVE
default y
help
activate test support for interactive support in
STM32MP1 DDR controller driver: command test
config STM32MP1_DDR_TUNING
bool "STM32MP1 DDR driver : support of tuning"
depends on STM32MP1_DDR_INTERACTIVE
default y
help
activate tuning command in STM32MP1 DDR interactive mode
used for DDR tuning tools
- DQ Deskew algorithm
- DQS Trimming

View File

@ -5,3 +5,11 @@
obj-y += stm32mp1_ram.o
obj-y += stm32mp1_ddr.o
obj-$(CONFIG_STM32MP1_DDR_INTERACTIVE) += stm32mp1_interactive.o
obj-$(CONFIG_STM32MP1_DDR_TESTS) += stm32mp1_tests.o
obj-$(CONFIG_STM32MP1_DDR_TUNING) += stm32mp1_tuning.o
ifneq ($(DDR_INTERACTIVE),)
CFLAGS_stm32mp1_interactive.o += -DCONFIG_STM32MP1_DDR_INTERACTIVE_FORCE=y
endif

View File

@ -41,8 +41,32 @@ struct reg_desc {
offsetof(struct stm32mp1_ddrphy, x),\
offsetof(struct y, x)}
#define DDR_REG_DYN(x) \
{#x,\
offsetof(struct stm32mp1_ddrctl, x),\
INVALID_OFFSET}
#define DDRPHY_REG_DYN(x) \
{#x,\
offsetof(struct stm32mp1_ddrphy, x),\
INVALID_OFFSET}
/***********************************************************
* PARAMETERS: value get from device tree :
* size / order need to be aligned with binding
* modification NOT ALLOWED !!!
***********************************************************/
#define DDRCTL_REG_REG_SIZE 25 /* st,ctl-reg */
#define DDRCTL_REG_TIMING_SIZE 12 /* st,ctl-timing */
#define DDRCTL_REG_MAP_SIZE 9 /* st,ctl-map */
#define DDRCTL_REG_PERF_SIZE 17 /* st,ctl-perf */
#define DDRPHY_REG_REG_SIZE 11 /* st,phy-reg */
#define DDRPHY_REG_TIMING_SIZE 10 /* st,phy-timing */
#define DDRPHY_REG_CAL_SIZE 12 /* st,phy-cal */
#define DDRCTL_REG_REG(x) DDRCTL_REG(x, stm32mp1_ddrctrl_reg)
static const struct reg_desc ddr_reg[] = {
static const struct reg_desc ddr_reg[DDRCTL_REG_REG_SIZE] = {
DDRCTL_REG_REG(mstr),
DDRCTL_REG_REG(mrctrl0),
DDRCTL_REG_REG(mrctrl1),
@ -71,7 +95,7 @@ static const struct reg_desc ddr_reg[] = {
};
#define DDRCTL_REG_TIMING(x) DDRCTL_REG(x, stm32mp1_ddrctrl_timing)
static const struct reg_desc ddr_timing[] = {
static const struct reg_desc ddr_timing[DDRCTL_REG_TIMING_SIZE] = {
DDRCTL_REG_TIMING(rfshtmg),
DDRCTL_REG_TIMING(dramtmg0),
DDRCTL_REG_TIMING(dramtmg1),
@ -87,7 +111,7 @@ static const struct reg_desc ddr_timing[] = {
};
#define DDRCTL_REG_MAP(x) DDRCTL_REG(x, stm32mp1_ddrctrl_map)
static const struct reg_desc ddr_map[] = {
static const struct reg_desc ddr_map[DDRCTL_REG_MAP_SIZE] = {
DDRCTL_REG_MAP(addrmap1),
DDRCTL_REG_MAP(addrmap2),
DDRCTL_REG_MAP(addrmap3),
@ -100,7 +124,7 @@ static const struct reg_desc ddr_map[] = {
};
#define DDRCTL_REG_PERF(x) DDRCTL_REG(x, stm32mp1_ddrctrl_perf)
static const struct reg_desc ddr_perf[] = {
static const struct reg_desc ddr_perf[DDRCTL_REG_PERF_SIZE] = {
DDRCTL_REG_PERF(sched),
DDRCTL_REG_PERF(sched1),
DDRCTL_REG_PERF(perfhpr1),
@ -121,7 +145,7 @@ static const struct reg_desc ddr_perf[] = {
};
#define DDRPHY_REG_REG(x) DDRPHY_REG(x, stm32mp1_ddrphy_reg)
static const struct reg_desc ddrphy_reg[] = {
static const struct reg_desc ddrphy_reg[DDRPHY_REG_REG_SIZE] = {
DDRPHY_REG_REG(pgcr),
DDRPHY_REG_REG(aciocr),
DDRPHY_REG_REG(dxccr),
@ -136,7 +160,7 @@ static const struct reg_desc ddrphy_reg[] = {
};
#define DDRPHY_REG_TIMING(x) DDRPHY_REG(x, stm32mp1_ddrphy_timing)
static const struct reg_desc ddrphy_timing[] = {
static const struct reg_desc ddrphy_timing[DDRPHY_REG_TIMING_SIZE] = {
DDRPHY_REG_TIMING(ptr0),
DDRPHY_REG_TIMING(ptr1),
DDRPHY_REG_TIMING(ptr2),
@ -150,7 +174,7 @@ static const struct reg_desc ddrphy_timing[] = {
};
#define DDRPHY_REG_CAL(x) DDRPHY_REG(x, stm32mp1_ddrphy_cal)
static const struct reg_desc ddrphy_cal[] = {
static const struct reg_desc ddrphy_cal[DDRPHY_REG_CAL_SIZE] = {
DDRPHY_REG_CAL(dx0dllcr),
DDRPHY_REG_CAL(dx0dqtr),
DDRPHY_REG_CAL(dx0dqstr),
@ -165,6 +189,45 @@ static const struct reg_desc ddrphy_cal[] = {
DDRPHY_REG_CAL(dx3dqstr),
};
/**************************************************************
* DYNAMIC REGISTERS: only used for debug purpose (read/modify)
**************************************************************/
#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE
static const struct reg_desc ddr_dyn[] = {
DDR_REG_DYN(stat),
DDR_REG_DYN(init0),
DDR_REG_DYN(dfimisc),
DDR_REG_DYN(dfistat),
DDR_REG_DYN(swctl),
DDR_REG_DYN(swstat),
DDR_REG_DYN(pctrl_0),
DDR_REG_DYN(pctrl_1),
};
#define DDR_REG_DYN_SIZE ARRAY_SIZE(ddr_dyn)
static const struct reg_desc ddrphy_dyn[] = {
DDRPHY_REG_DYN(pir),
DDRPHY_REG_DYN(pgsr),
DDRPHY_REG_DYN(zq0sr0),
DDRPHY_REG_DYN(zq0sr1),
DDRPHY_REG_DYN(dx0gsr0),
DDRPHY_REG_DYN(dx0gsr1),
DDRPHY_REG_DYN(dx1gsr0),
DDRPHY_REG_DYN(dx1gsr1),
DDRPHY_REG_DYN(dx2gsr0),
DDRPHY_REG_DYN(dx2gsr1),
DDRPHY_REG_DYN(dx3gsr0),
DDRPHY_REG_DYN(dx3gsr1),
};
#define DDRPHY_REG_DYN_SIZE ARRAY_SIZE(ddrphy_dyn)
#endif
/*****************************************************************
* REGISTERS ARRAY: used to parse device tree and interactive mode
*****************************************************************/
enum reg_type {
REG_REG,
REG_TIMING,
@ -173,6 +236,13 @@ enum reg_type {
REGPHY_REG,
REGPHY_TIMING,
REGPHY_CAL,
#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE
/* dynamic registers => managed in driver or not changed,
* can be dumped in interactive mode
*/
REG_DYN,
REGPHY_DYN,
#endif
REG_TYPE_NB
};
@ -193,19 +263,26 @@ struct ddr_reg_info {
const struct ddr_reg_info ddr_registers[REG_TYPE_NB] = {
[REG_REG] = {
"static", ddr_reg, ARRAY_SIZE(ddr_reg), DDR_BASE},
"static", ddr_reg, DDRCTL_REG_REG_SIZE, DDR_BASE},
[REG_TIMING] = {
"timing", ddr_timing, ARRAY_SIZE(ddr_timing), DDR_BASE},
"timing", ddr_timing, DDRCTL_REG_TIMING_SIZE, DDR_BASE},
[REG_PERF] = {
"perf", ddr_perf, ARRAY_SIZE(ddr_perf), DDR_BASE},
"perf", ddr_perf, DDRCTL_REG_PERF_SIZE, DDR_BASE},
[REG_MAP] = {
"map", ddr_map, ARRAY_SIZE(ddr_map), DDR_BASE},
"map", ddr_map, DDRCTL_REG_MAP_SIZE, DDR_BASE},
[REGPHY_REG] = {
"static", ddrphy_reg, ARRAY_SIZE(ddrphy_reg), DDRPHY_BASE},
"static", ddrphy_reg, DDRPHY_REG_REG_SIZE, DDRPHY_BASE},
[REGPHY_TIMING] = {
"timing", ddrphy_timing, ARRAY_SIZE(ddrphy_timing), DDRPHY_BASE},
"timing", ddrphy_timing, DDRPHY_REG_TIMING_SIZE, DDRPHY_BASE},
[REGPHY_CAL] = {
"cal", ddrphy_cal, ARRAY_SIZE(ddrphy_cal), DDRPHY_BASE},
"cal", ddrphy_cal, DDRPHY_REG_CAL_SIZE, DDRPHY_BASE},
#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE
[REG_DYN] = {
"dyn", ddr_dyn, DDR_REG_DYN_SIZE, DDR_BASE},
[REGPHY_DYN] = {
"dyn", ddrphy_dyn, DDRPHY_REG_DYN_SIZE, DDRPHY_BASE},
#endif
};
const char *base_name[] = {
@ -246,6 +323,231 @@ static void set_reg(const struct ddr_info *priv,
}
}
#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE
static void stm32mp1_dump_reg_desc(u32 base_addr, const struct reg_desc *desc)
{
unsigned int *ptr;
ptr = (unsigned int *)(base_addr + desc->offset);
printf("%s= 0x%08x\n", desc->name, readl(ptr));
}
static void stm32mp1_dump_param_desc(u32 par_addr, const struct reg_desc *desc)
{
unsigned int *ptr;
ptr = (unsigned int *)(par_addr + desc->par_offset);
printf("%s= 0x%08x\n", desc->name, readl(ptr));
}
static const struct reg_desc *found_reg(const char *name, enum reg_type *type)
{
unsigned int i, j;
const struct reg_desc *desc;
for (i = 0; i < ARRAY_SIZE(ddr_registers); i++) {
desc = ddr_registers[i].desc;
for (j = 0; j < ddr_registers[i].size; j++) {
if (strcmp(name, desc[j].name) == 0) {
*type = i;
return &desc[j];
}
}
}
*type = REG_TYPE_NB;
return NULL;
}
int stm32mp1_dump_reg(const struct ddr_info *priv,
const char *name)
{
unsigned int i, j;
const struct reg_desc *desc;
u32 base_addr;
enum base_type p_base;
enum reg_type type;
const char *p_name;
enum base_type filter = NONE_BASE;
int result = -1;
if (name) {
if (strcmp(name, base_name[DDR_BASE]) == 0)
filter = DDR_BASE;
else if (strcmp(name, base_name[DDRPHY_BASE]) == 0)
filter = DDRPHY_BASE;
}
for (i = 0; i < ARRAY_SIZE(ddr_registers); i++) {
p_base = ddr_registers[i].base;
p_name = ddr_registers[i].name;
if (!name || (filter == p_base || !strcmp(name, p_name))) {
result = 0;
desc = ddr_registers[i].desc;
base_addr = get_base_addr(priv, p_base);
printf("==%s.%s==\n", base_name[p_base], p_name);
for (j = 0; j < ddr_registers[i].size; j++)
stm32mp1_dump_reg_desc(base_addr, &desc[j]);
}
}
if (result) {
desc = found_reg(name, &type);
if (desc) {
p_base = ddr_registers[type].base;
base_addr = get_base_addr(priv, p_base);
stm32mp1_dump_reg_desc(base_addr, desc);
result = 0;
}
}
return result;
}
void stm32mp1_edit_reg(const struct ddr_info *priv,
char *name, char *string)
{
unsigned long *ptr, value;
enum reg_type type;
enum base_type base;
const struct reg_desc *desc;
u32 base_addr;
desc = found_reg(name, &type);
if (!desc) {
printf("%s not found\n", name);
return;
}
if (strict_strtoul(string, 16, &value) < 0) {
printf("invalid value %s\n", string);
return;
}
base = ddr_registers[type].base;
base_addr = get_base_addr(priv, base);
ptr = (unsigned long *)(base_addr + desc->offset);
writel(value, ptr);
printf("%s= 0x%08x\n", desc->name, readl(ptr));
}
static u32 get_par_addr(const struct stm32mp1_ddr_config *config,
enum reg_type type)
{
u32 par_addr = 0x0;
switch (type) {
case REG_REG:
par_addr = (u32)&config->c_reg;
break;
case REG_TIMING:
par_addr = (u32)&config->c_timing;
break;
case REG_PERF:
par_addr = (u32)&config->c_perf;
break;
case REG_MAP:
par_addr = (u32)&config->c_map;
break;
case REGPHY_REG:
par_addr = (u32)&config->p_reg;
break;
case REGPHY_TIMING:
par_addr = (u32)&config->p_timing;
break;
case REGPHY_CAL:
par_addr = (u32)&config->p_cal;
break;
case REG_DYN:
case REGPHY_DYN:
case REG_TYPE_NB:
par_addr = (u32)NULL;
break;
}
return par_addr;
}
int stm32mp1_dump_param(const struct stm32mp1_ddr_config *config,
const char *name)
{
unsigned int i, j;
const struct reg_desc *desc;
u32 par_addr;
enum base_type p_base;
enum reg_type type;
const char *p_name;
enum base_type filter = NONE_BASE;
int result = -EINVAL;
if (name) {
if (strcmp(name, base_name[DDR_BASE]) == 0)
filter = DDR_BASE;
else if (strcmp(name, base_name[DDRPHY_BASE]) == 0)
filter = DDRPHY_BASE;
}
for (i = 0; i < ARRAY_SIZE(ddr_registers); i++) {
par_addr = get_par_addr(config, i);
if (!par_addr)
continue;
p_base = ddr_registers[i].base;
p_name = ddr_registers[i].name;
if (!name || (filter == p_base || !strcmp(name, p_name))) {
result = 0;
desc = ddr_registers[i].desc;
printf("==%s.%s==\n", base_name[p_base], p_name);
for (j = 0; j < ddr_registers[i].size; j++)
stm32mp1_dump_param_desc(par_addr, &desc[j]);
}
}
if (result) {
desc = found_reg(name, &type);
if (desc) {
par_addr = get_par_addr(config, type);
if (par_addr) {
stm32mp1_dump_param_desc(par_addr, desc);
result = 0;
}
}
}
return result;
}
void stm32mp1_edit_param(const struct stm32mp1_ddr_config *config,
char *name, char *string)
{
unsigned long *ptr, value;
enum reg_type type;
const struct reg_desc *desc;
u32 par_addr;
desc = found_reg(name, &type);
if (!desc) {
printf("%s not found\n", name);
return;
}
if (strict_strtoul(string, 16, &value) < 0) {
printf("invalid value %s\n", string);
return;
}
par_addr = get_par_addr(config, type);
if (!par_addr) {
printf("no parameter %s\n", name);
return;
}
ptr = (unsigned long *)(par_addr + desc->par_offset);
writel(value, ptr);
printf("%s= 0x%08x\n", desc->name, readl(ptr));
}
#endif
__weak bool stm32mp1_ddr_interactive(void *priv,
enum stm32mp1_ddr_interact_step step,
const struct stm32mp1_ddr_config *config)
{
return false;
}
#define INTERACTIVE(step)\
stm32mp1_ddr_interactive(priv, step, config)
static void ddrphy_idone_wait(struct stm32mp1_ddrphy *phy)
{
u32 pgsr;
@ -312,7 +614,7 @@ static void wait_operating_mode(struct ddr_info *priv, int 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;
val |= 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 |
@ -355,7 +657,7 @@ void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl,
}
/* board-specific DDR power initializations. */
__weak int board_ddr_power_init(void)
__weak int board_ddr_power_init(enum ddr_type ddr_type)
{
return 0;
}
@ -365,15 +667,21 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
const struct stm32mp1_ddr_config *config)
{
u32 pir;
int ret;
int ret = -EINVAL;
ret = board_ddr_power_init();
if (config->c_reg.mstr & DDRCTRL_MSTR_DDR3)
ret = board_ddr_power_init(STM32MP_DDR3);
else if (config->c_reg.mstr & DDRCTRL_MSTR_LPDDR2)
ret = board_ddr_power_init(STM32MP_LPDDR2);
else if (config->c_reg.mstr & DDRCTRL_MSTR_LPDDR3)
ret = board_ddr_power_init(STM32MP_LPDDR3);
if (ret)
panic("ddr power init failed\n");
start:
debug("name = %s\n", config->info.name);
debug("speed = %d MHz\n", config->info.speed);
debug("speed = %d kHz\n", config->info.speed);
debug("size = 0x%x\n", config->info.size);
/*
* 1. Program the DWC_ddr_umctl2 registers
@ -389,7 +697,7 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
/* 1.2. start CLOCK */
if (stm32mp1_ddr_clk_enable(priv, config->info.speed))
panic("invalid DRAM clock : %d MHz\n",
panic("invalid DRAM clock : %d kHz\n",
config->info.speed);
/* 1.3. deassert reset */
@ -401,11 +709,12 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
*/
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.4. wait 128 cycles to permit initialization of end logic */
udelay(2);
/* for PCLK = 133MHz => 1 us is enough, 2 to allow lower frequency */
if (INTERACTIVE(STEP_DDR_RESET))
goto start;
/* 1.5. initialize registers ddr_umctl2 */
/* Stop uMCTL2 before PHY is ready */
@ -424,6 +733,9 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
set_reg(priv, REG_PERF, &config->c_perf);
if (INTERACTIVE(STEP_CTL_INIT))
goto start;
/* 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);
@ -436,6 +748,9 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
set_reg(priv, REGPHY_TIMING, &config->p_timing);
set_reg(priv, REGPHY_CAL, &config->p_cal);
if (INTERACTIVE(STEP_PHY_INIT))
goto start;
/* 4. Monitor PHY init status by polling PUBL register PGSR.IDONE
* Perform DDR PHY DRAM initialization and Gate Training Evaluation
*/
@ -492,4 +807,7 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
/* 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);
if (INTERACTIVE(STEP_DDR_READY))
goto start;
}

View File

@ -157,7 +157,7 @@ struct stm32mp1_ddrphy_cal {
struct stm32mp1_ddr_info {
const char *name;
u16 speed; /* in MHZ */
u32 speed; /* in kHZ */
u32 size; /* memory size in byte = col * row * width */
};
@ -172,7 +172,7 @@ struct stm32mp1_ddr_config {
struct stm32mp1_ddrphy_cal p_cal;
};
int stm32mp1_ddr_clk_enable(struct ddr_info *priv, u16 mem_speed);
int stm32mp1_ddr_clk_enable(struct ddr_info *priv, u32 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,

View File

@ -234,6 +234,8 @@ struct stm32mp1_ddrphy {
/* DDRCTRL REGISTERS */
#define DDRCTRL_MSTR_DDR3 BIT(0)
#define DDRCTRL_MSTR_LPDDR2 BIT(2)
#define DDRCTRL_MSTR_LPDDR3 BIT(3)
#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)
@ -330,6 +332,7 @@ struct stm32mp1_ddrphy {
#define DDRPHYC_DXNGCR_DXEN BIT(0)
#define DDRPHYC_DXNDLLCR_DLLSRST BIT(30)
#define DDRPHYC_DXNDLLCR_DLLDIS BIT(31)
#define DDRPHYC_DXNDLLCR_SDPHASE_MASK GENMASK(17, 14)
#define DDRPHYC_DXNDLLCR_SDPHASE_SHIFT 14

View File

@ -0,0 +1,483 @@
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
/*
* Copyright (C) 2019, STMicroelectronics - All Rights Reserved
*/
#include <common.h>
#include <console.h>
#include <cli.h>
#include <clk.h>
#include <malloc.h>
#include <ram.h>
#include <reset.h>
#include "stm32mp1_ddr.h"
#include "stm32mp1_tests.h"
DECLARE_GLOBAL_DATA_PTR;
enum ddr_command {
DDR_CMD_HELP,
DDR_CMD_INFO,
DDR_CMD_FREQ,
DDR_CMD_RESET,
DDR_CMD_PARAM,
DDR_CMD_PRINT,
DDR_CMD_EDIT,
DDR_CMD_STEP,
DDR_CMD_NEXT,
DDR_CMD_GO,
DDR_CMD_TEST,
DDR_CMD_TUNING,
DDR_CMD_UNKNOWN,
};
const char *step_str[] = {
[STEP_DDR_RESET] = "DDR_RESET",
[STEP_CTL_INIT] = "DDR_CTRL_INIT_DONE",
[STEP_PHY_INIT] = "DDR PHY_INIT_DONE",
[STEP_DDR_READY] = "DDR_READY",
[STEP_RUN] = "RUN"
};
enum ddr_command stm32mp1_get_command(char *cmd, int argc)
{
const char *cmd_string[DDR_CMD_UNKNOWN] = {
[DDR_CMD_HELP] = "help",
[DDR_CMD_INFO] = "info",
[DDR_CMD_FREQ] = "freq",
[DDR_CMD_RESET] = "reset",
[DDR_CMD_PARAM] = "param",
[DDR_CMD_PRINT] = "print",
[DDR_CMD_EDIT] = "edit",
[DDR_CMD_STEP] = "step",
[DDR_CMD_NEXT] = "next",
[DDR_CMD_GO] = "go",
#ifdef CONFIG_STM32MP1_DDR_TESTS
[DDR_CMD_TEST] = "test",
#endif
#ifdef CONFIG_STM32MP1_DDR_TUNING
[DDR_CMD_TUNING] = "tuning",
#endif
};
/* min and max number of argument */
const char cmd_arg[DDR_CMD_UNKNOWN][2] = {
[DDR_CMD_HELP] = { 0, 0 },
[DDR_CMD_INFO] = { 0, 255 },
[DDR_CMD_FREQ] = { 0, 1 },
[DDR_CMD_RESET] = { 0, 0 },
[DDR_CMD_PARAM] = { 0, 2 },
[DDR_CMD_PRINT] = { 0, 1 },
[DDR_CMD_EDIT] = { 2, 2 },
[DDR_CMD_STEP] = { 0, 1 },
[DDR_CMD_NEXT] = { 0, 0 },
[DDR_CMD_GO] = { 0, 0 },
#ifdef CONFIG_STM32MP1_DDR_TESTS
[DDR_CMD_TEST] = { 0, 255 },
#endif
#ifdef CONFIG_STM32MP1_DDR_TUNING
[DDR_CMD_TUNING] = { 0, 255 },
#endif
};
int i;
for (i = 0; i < DDR_CMD_UNKNOWN; i++)
if (!strcmp(cmd, cmd_string[i])) {
if (argc - 1 < cmd_arg[i][0]) {
printf("no enought argument (min=%d)\n",
cmd_arg[i][0]);
return DDR_CMD_UNKNOWN;
} else if (argc - 1 > cmd_arg[i][1]) {
printf("too many argument (max=%d)\n",
cmd_arg[i][1]);
return DDR_CMD_UNKNOWN;
} else {
return i;
}
}
printf("unknown command %s\n", cmd);
return DDR_CMD_UNKNOWN;
}
static void stm32mp1_do_usage(void)
{
const char *usage = {
"commands:\n\n"
"help displays help\n"
"info displays DDR information\n"
"info <param> <val> changes DDR information\n"
" with <param> = step, name, size or speed\n"
"freq displays the DDR PHY frequency in kHz\n"
"freq <freq> changes the DDR PHY frequency\n"
"param [type|reg] prints input parameters\n"
"param <reg> <val> edits parameters in step 0\n"
"print [type|reg] dumps registers\n"
"edit <reg> <val> modifies one register\n"
"step lists the available step\n"
"step <n> go to the step <n>\n"
"next goes to the next step\n"
"go continues the U-Boot SPL execution\n"
"reset reboots machine\n"
#ifdef CONFIG_STM32MP1_DDR_TESTS
"test [help] | <n> [...] lists (with help) or executes test <n>\n"
#endif
#ifdef CONFIG_STM32MP1_DDR_TUNING
"tuning [help] | <n> [...] lists (with help) or execute tuning <n>\n"
#endif
"\nwith for [type|reg]:\n"
" all registers if absent\n"
" <type> = ctl, phy\n"
" or one category (static, timing, map, perf, cal, dyn)\n"
" <reg> = name of the register\n"
};
puts(usage);
}
static bool stm32mp1_check_step(enum stm32mp1_ddr_interact_step step,
enum stm32mp1_ddr_interact_step expected)
{
if (step != expected) {
printf("invalid step %d:%s expecting %d:%s\n",
step, step_str[step],
expected,
step_str[expected]);
return false;
}
return true;
}
static void stm32mp1_do_info(struct ddr_info *priv,
struct stm32mp1_ddr_config *config,
enum stm32mp1_ddr_interact_step step,
int argc, char * const argv[])
{
unsigned long value;
static char *ddr_name;
if (argc == 1) {
printf("step = %d : %s\n", step, step_str[step]);
printf("name = %s\n", config->info.name);
printf("size = 0x%x\n", config->info.size);
printf("speed = %d kHz\n", config->info.speed);
return;
}
if (argc < 3) {
printf("no enought parameter\n");
return;
}
if (!strcmp(argv[1], "name")) {
u32 i, name_len = 0;
for (i = 2; i < argc; i++)
name_len += strlen(argv[i]) + 1;
if (ddr_name)
free(ddr_name);
ddr_name = malloc(name_len);
config->info.name = ddr_name;
if (!ddr_name) {
printf("alloc error, length %d\n", name_len);
return;
}
strcpy(ddr_name, argv[2]);
for (i = 3; i < argc; i++) {
strcat(ddr_name, " ");
strcat(ddr_name, argv[i]);
}
printf("name = %s\n", ddr_name);
return;
}
if (!strcmp(argv[1], "size")) {
if (strict_strtoul(argv[2], 16, &value) < 0) {
printf("invalid value %s\n", argv[2]);
} else {
config->info.size = value;
printf("size = 0x%x\n", config->info.size);
}
return;
}
if (!strcmp(argv[1], "speed")) {
if (strict_strtoul(argv[2], 10, &value) < 0) {
printf("invalid value %s\n", argv[2]);
} else {
config->info.speed = value;
printf("speed = %d kHz\n", config->info.speed);
value = clk_get_rate(&priv->clk);
printf("DDRPHY = %ld kHz\n", value / 1000);
}
return;
}
printf("argument %s invalid\n", argv[1]);
}
static bool stm32mp1_do_freq(struct ddr_info *priv,
int argc, char * const argv[])
{
unsigned long ddrphy_clk;
if (argc == 2) {
if (strict_strtoul(argv[1], 0, &ddrphy_clk) < 0) {
printf("invalid argument %s", argv[1]);
return false;
}
if (clk_set_rate(&priv->clk, ddrphy_clk * 1000)) {
printf("ERROR: update failed!\n");
return false;
}
}
ddrphy_clk = clk_get_rate(&priv->clk);
printf("DDRPHY = %ld kHz\n", ddrphy_clk / 1000);
if (argc == 2)
return true;
return false;
}
static void stm32mp1_do_param(enum stm32mp1_ddr_interact_step step,
const struct stm32mp1_ddr_config *config,
int argc, char * const argv[])
{
switch (argc) {
case 1:
stm32mp1_dump_param(config, NULL);
break;
case 2:
if (stm32mp1_dump_param(config, argv[1]))
printf("invalid argument %s\n",
argv[1]);
break;
case 3:
if (!stm32mp1_check_step(step, STEP_DDR_RESET))
return;
stm32mp1_edit_param(config, argv[1], argv[2]);
break;
}
}
static void stm32mp1_do_print(struct ddr_info *priv,
int argc, char * const argv[])
{
switch (argc) {
case 1:
stm32mp1_dump_reg(priv, NULL);
break;
case 2:
if (stm32mp1_dump_reg(priv, argv[1]))
printf("invalid argument %s\n",
argv[1]);
break;
}
}
static int stm32mp1_do_step(enum stm32mp1_ddr_interact_step step,
int argc, char * const argv[])
{
int i;
unsigned long value;
switch (argc) {
case 1:
for (i = 0; i < ARRAY_SIZE(step_str); i++)
printf("%d:%s\n", i, step_str[i]);
break;
case 2:
if ((strict_strtoul(argv[1], 0,
&value) < 0) ||
value >= ARRAY_SIZE(step_str)) {
printf("invalid argument %s\n",
argv[1]);
goto end;
}
if (value != STEP_DDR_RESET &&
value <= step) {
printf("invalid target %d:%s, current step is %d:%s\n",
(int)value, step_str[value],
step, step_str[step]);
goto end;
}
printf("step to %d:%s\n",
(int)value, step_str[value]);
return (int)value;
};
end:
return step;
}
#if defined(CONFIG_STM32MP1_DDR_TESTS) || defined(CONFIG_STM32MP1_DDR_TUNING)
static const char * const s_result[] = {
[TEST_PASSED] = "Pass",
[TEST_FAILED] = "Failed",
[TEST_ERROR] = "Error"
};
static void stm32mp1_ddr_subcmd(struct ddr_info *priv,
int argc, char *argv[],
const struct test_desc array[],
const int array_nb)
{
int i;
unsigned long value;
int result;
char string[50] = "";
if (argc == 1) {
printf("%s:%d\n", argv[0], array_nb);
for (i = 0; i < array_nb; i++)
printf("%d:%s:%s\n",
i, array[i].name, array[i].usage);
return;
}
if (argc > 1 && !strcmp(argv[1], "help")) {
printf("%s:%d\n", argv[0], array_nb);
for (i = 0; i < array_nb; i++)
printf("%d:%s:%s:%s\n", i,
array[i].name, array[i].usage, array[i].help);
return;
}
if ((strict_strtoul(argv[1], 0, &value) < 0) ||
value >= array_nb) {
sprintf(string, "invalid argument %s",
argv[1]);
result = TEST_FAILED;
goto end;
}
if (argc > (array[value].max_args + 2)) {
sprintf(string, "invalid nb of args %d, max %d",
argc - 2, array[value].max_args);
result = TEST_FAILED;
goto end;
}
printf("execute %d:%s\n", (int)value, array[value].name);
clear_ctrlc();
result = array[value].fct(priv->ctl, priv->phy,
string, argc - 2, &argv[2]);
end:
printf("Result: %s [%s]\n", s_result[result], string);
}
#endif
bool stm32mp1_ddr_interactive(void *priv,
enum stm32mp1_ddr_interact_step step,
const struct stm32mp1_ddr_config *config)
{
const char *prompt = "DDR>";
char buffer[CONFIG_SYS_CBSIZE];
char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */
int argc;
static int next_step = -1;
if (next_step < 0 && step == STEP_DDR_RESET) {
#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE_FORCE
gd->flags &= ~(GD_FLG_SILENT |
GD_FLG_DISABLE_CONSOLE);
next_step = STEP_DDR_RESET;
#else
unsigned long start = get_timer(0);
while (1) {
if (tstc() && (getc() == 'd')) {
next_step = STEP_DDR_RESET;
break;
}
if (get_timer(start) > 100)
break;
}
#endif
}
debug("** step %d ** %s / %d\n", step, step_str[step], next_step);
if (next_step < 0)
return false;
if (step < 0 || step > ARRAY_SIZE(step_str)) {
printf("** step %d ** INVALID\n", step);
return false;
}
printf("%d:%s\n", step, step_str[step]);
printf("%s\n", prompt);
if (next_step > step)
return false;
while (next_step == step) {
cli_readline_into_buffer(prompt, buffer, 0);
argc = cli_simple_parse_line(buffer, argv);
if (!argc)
continue;
switch (stm32mp1_get_command(argv[0], argc)) {
case DDR_CMD_HELP:
stm32mp1_do_usage();
break;
case DDR_CMD_INFO:
stm32mp1_do_info(priv,
(struct stm32mp1_ddr_config *)config,
step, argc, argv);
break;
case DDR_CMD_FREQ:
if (stm32mp1_do_freq(priv, argc, argv))
next_step = STEP_DDR_RESET;
break;
case DDR_CMD_RESET:
do_reset(NULL, 0, 0, NULL);
break;
case DDR_CMD_PARAM:
stm32mp1_do_param(step, config, argc, argv);
break;
case DDR_CMD_PRINT:
stm32mp1_do_print(priv, argc, argv);
break;
case DDR_CMD_EDIT:
stm32mp1_edit_reg(priv, argv[1], argv[2]);
break;
case DDR_CMD_GO:
next_step = STEP_RUN;
break;
case DDR_CMD_NEXT:
next_step = step + 1;
break;
case DDR_CMD_STEP:
next_step = stm32mp1_do_step(step, argc, argv);
break;
#ifdef CONFIG_STM32MP1_DDR_TESTS
case DDR_CMD_TEST:
if (!stm32mp1_check_step(step, STEP_DDR_READY))
continue;
stm32mp1_ddr_subcmd(priv, argc, argv, test, test_nb);
break;
#endif
#ifdef CONFIG_STM32MP1_DDR_TUNING
case DDR_CMD_TUNING:
if (!stm32mp1_check_step(step, STEP_DDR_READY))
continue;
stm32mp1_ddr_subcmd(priv, argc, argv,
tuning, tuning_nb);
break;
#endif
default:
break;
}
}
return next_step == STEP_DDR_RESET;
}

View File

@ -20,7 +20,7 @@ static const char *const clkname[] = {
"ddrphyc" /* LAST clock => used for get_rate() */
};
int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint16_t mem_speed)
int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint32_t mem_speed)
{
unsigned long ddrphy_clk;
unsigned long ddr_clk;
@ -43,13 +43,13 @@ int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint16_t mem_speed)
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));
debug("DDR: mem_speed (%d kHz), RCC %d kHz\n",
mem_speed, (u32)(ddrphy_clk / 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));
ddr_clk = abs(ddrphy_clk - mem_speed * 1000);
if (ddr_clk > (mem_speed * 100)) {
pr_err("DDR expected freq %d kHz, current is %d kHz\n",
mem_speed, (u32)(ddrphy_clk / 1000));
return -EINVAL;
}
@ -102,8 +102,8 @@ static __maybe_unused int stm32mp1_ddr_setup(struct udevice *dev)
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);
pr_err("%s: Cannot read %s, error=%d\n",
__func__, param[idx].name, ret);
return -EINVAL;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,34 @@
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
/*
* Copyright (C) 2019, STMicroelectronics - All Rights Reserved
*/
#ifndef _RAM_STM32MP1_TESTS_H_
#define _RAM_STM32MP1_TESTS_H_
#include "stm32mp1_ddr_regs.h"
enum test_result {
TEST_PASSED,
TEST_FAILED,
TEST_ERROR
};
struct test_desc {
enum test_result (*fct)(struct stm32mp1_ddrctl *ctl,
struct stm32mp1_ddrphy *phy,
char *string,
int argc, char *argv[]);
const char *name;
const char *usage;
const char *help;
u8 max_args;
};
extern const struct test_desc test[];
extern const int test_nb;
extern const struct test_desc tuning[];
extern const int tuning_nb;
#endif

File diff suppressed because it is too large Load Diff

View File

@ -269,7 +269,6 @@ static inline void _debug_uart_init(void)
_stm32_serial_setbrg(base, uart_info,
CONFIG_DEBUG_UART_CLOCK,
CONFIG_BAUDRATE);
printf("DEBUG done\n");
}
static inline void _debug_uart_putc(int c)
@ -278,7 +277,7 @@ static inline void _debug_uart_putc(int c)
struct stm32_uart_info *uart_info = _debug_uart_info();
while (_stm32_serial_putc(base, uart_info, c) == -EAGAIN)
WATCHDOG_RESET();
;
}
DEBUG_UART_FUNCS

2
env/Kconfig vendored
View File

@ -470,7 +470,7 @@ config ENV_EXT4_FILE
It's a string of the EXT4 file name. This file use to store the
environment (explicit path to the file)
if ARCH_ROCKCHIP || ARCH_SUNXI || ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_VERSAL || ARC
if ARCH_ROCKCHIP || ARCH_SUNXI || ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_VERSAL || ARC || ARCH_STM32MP
config ENV_OFFSET
hex "Environment Offset"

7
env/common.c vendored
View File

@ -23,7 +23,10 @@ DECLARE_GLOBAL_DATA_PTR;
#include <env_default.h>
struct hsearch_data env_htab = {
#if CONFIG_IS_ENABLED(ENV_SUPPORT)
/* defined in flags.c, only compile with ENV_SUPPORT */
.change_ok = env_flags_validate,
#endif
};
/*
@ -225,7 +228,9 @@ void env_relocate(void)
#if defined(CONFIG_NEEDS_MANUAL_RELOC)
env_reloc();
env_fix_drivers();
env_htab.change_ok += gd->reloc_off;
if (env_htab.change_ok)
env_htab.change_ok += gd->reloc_off;
#endif
if (gd->env_valid == ENV_INVALID) {
#if defined(CONFIG_ENV_IS_NOWHERE) || defined(CONFIG_SPL_BUILD)

View File

@ -22,11 +22,6 @@
#define CONFIG_ARMV7_SECURE_MAX_SIZE STM32_SYSRAM_SIZE
#endif
/*
* malloc() pool size
*/
#define CONFIG_SYS_MALLOC_LEN SZ_32M
/*
* Configuration of the external SRAM memory used by U-Boot
*/
@ -43,11 +38,6 @@
*/
#define CONFIG_SYS_LOAD_ADDR STM32_DDR_BASE
/*
* Env parameters
*/
#define CONFIG_ENV_SIZE SZ_4K
/* ATAGs */
#define CONFIG_CMDLINE_TAG
#define CONFIG_SETUP_MEMORY_TAGS
@ -95,8 +85,6 @@
* for nand boot, boot with on ubifs partition on nand
* for nor boot, use the default order
*/
#define CONFIG_PREBOOT
#define STM32MP_BOOTCMD "bootcmd_stm32mp=" \
"echo \"Boot over ${boot_device}${boot_instance}!\";" \
"if test ${boot_device} = serial || test ${boot_device} = usb;" \

View File

@ -14,6 +14,8 @@
#define HEADER_VERSION_V1 0x1
/* default option : bit0 => no signature */
#define HEADER_DEFAULT_OPTION (cpu_to_le32(0x00000001))
/* default binary type for U-Boot */
#define HEADER_TYPE_UBOOT (cpu_to_le32(0x00000000))
struct stm32_header {
uint32_t magic_number;
@ -29,7 +31,8 @@ struct stm32_header {
uint32_t option_flags;
uint32_t ecdsa_algorithm;
uint32_t ecdsa_public_key[64 / 4];
uint32_t padding[84 / 4];
uint32_t padding[83 / 4];
uint32_t binary_type;
};
static struct stm32_header stm32image_header;
@ -43,6 +46,7 @@ static void stm32image_default_header(struct stm32_header *ptr)
ptr->header_version[VER_MAJOR_IDX] = HEADER_VERSION_V1;
ptr->option_flags = HEADER_DEFAULT_OPTION;
ptr->ecdsa_algorithm = 1;
ptr->binary_type = HEADER_TYPE_UBOOT;
}
static uint32_t stm32image_checksum(void *start, uint32_t len)
@ -112,6 +116,8 @@ static void stm32image_print_header(const void *ptr)
le32_to_cpu(stm32hdr->image_checksum));
printf("Option : 0x%08x\n",
le32_to_cpu(stm32hdr->option_flags));
printf("BinaryType : 0x%08x\n",
le32_to_cpu(stm32hdr->binary_type));
}
static void stm32image_set_header(void *ptr, struct stat *sbuf, int ifd,