diff options
65 files changed, 12015 insertions, 0 deletions
| @@ -19,6 +19,9 @@ tools/cert_create/src/**/*.o  tools/cert_create/cert_create  tools/cert_create/cert_create.exe  tools/doimage/doimage +tools/stm32image/*.o +tools/stm32image/stm32image +tools/stm32image/stm32image.exe  # GNU GLOBAL files  GPATH diff --git a/acknowledgements.rst b/acknowledgements.rst index 5686a580..4d527f40 100644 --- a/acknowledgements.rst +++ b/acknowledgements.rst @@ -16,5 +16,7 @@ NXP Semiconductors  Marvell International Ltd. +STMicroelectronics +  Individuals  ----------- diff --git a/docs/plat/stm32mp1.rst b/docs/plat/stm32mp1.rst new file mode 100644 index 00000000..9e731a41 --- /dev/null +++ b/docs/plat/stm32mp1.rst @@ -0,0 +1,82 @@ +Trusted Firmware-A for STM32MP1 +=============================== + +STM32MP1 is a microprocessor designed by STMicroelectronics +based on a dual Arm Cortex-A7. +It is an Armv7-A platform, using dedicated code from TF-A. + + +Design +------ +The STM32MP1 resets in the ROM code of the Cortex-A7. +The primary boot core (core 0) executes the boot sequence while +secondary boot core (core 1) is kept in a holding pen loop. +The ROM code boot sequence loads the TF-A binary image from boot device +to embedded SRAM. + +The TF-A image must be properly formatted with a STM32 header structure +for ROM code is able to load this image. +Tool stm32image can be used to prepend this header to the generated TF-A binary. + +At compilation step, BL2, BL32 and DTB file are linked together in a single +binary. The stm32image tool is also generated and the header is added to TF-A +binary. This binary file with header is named tf-a-stm32mp157c-ev1.stm32. +It can then be copied in the first partition of the boot device. + + +Memory mapping +~~~~~~~~~~~~~~ + +:: + +    0x00000000 +-----------------+ +               |                 |   ROM +    0x00020000 +-----------------+ +               |                 | +               |       ...       | +               |                 | +    0x2FFC0000 +-----------------+ \ +               |                 | | +               |       ...       | | +               |                 | | +    0x2FFD8000 +-----------------+ | +               |    TF-A DTB     | | Embedded SRAM +    0x2FFDC000 +-----------------+ | +               |       BL2       | | +    0x2FFEF000 +-----------------+ | +               |       BL32      | | +    0x30000000 +-----------------+ / +               |                 | +               |       ...       | +               |                 | +    0x40000000 +-----------------+ +               |                 | +               |                 |   Devices +               |                 | +    0xC0000000 +-----------------+ \ +               |                 | | +    0xC0100000 +-----------------+ | +               |       BL33      | | Non-secure RAM (DDR) +               |       ...       | | +               |                 | | +    0xFFFFFFFF +-----------------+ / + + +Boot sequence +~~~~~~~~~~~~~ + +ROM code -> BL2 (compiled with BL2_AT_EL3) -> BL32 (SP_min) -> BL33 (U-Boot) + + +Build Instructions +------------------ + +To build: + +.. code:: bash + +    make CROSS_COMPILE=arm-linux-gnueabihf- PLAT=stm32mp1 ARCH=aarch32 ARM_ARCH_MAJOR=7 AARCH32_SP=sp_min + +The following build options are supported: + +- ``ENABLE_STACK_PROTECTOR``: To enable the stack protection. diff --git a/drivers/st/clk/stm32mp1_clk.c b/drivers/st/clk/stm32mp1_clk.c new file mode 100644 index 00000000..7dff98b1 --- /dev/null +++ b/drivers/st/clk/stm32mp1_clk.c @@ -0,0 +1,1611 @@ +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause + */ + +#include <arch.h> +#include <arch_helpers.h> +#include <assert.h> +#include <debug.h> +#include <delay_timer.h> +#include <dt-bindings/clock/stm32mp1-clks.h> +#include <dt-bindings/clock/stm32mp1-clksrc.h> +#include <errno.h> +#include <generic_delay_timer.h> +#include <libfdt.h> +#include <mmio.h> +#include <platform.h> +#include <stdint.h> +#include <stm32mp1_clk.h> +#include <stm32mp1_clkfunc.h> +#include <stm32mp1_dt.h> +#include <stm32mp1_private.h> +#include <stm32mp1_rcc.h> +#include <utils_def.h> + +#define MAX_HSI_HZ	64000000 + +#define TIMEOUT_200MS	(plat_get_syscnt_freq2() / 5U) +#define TIMEOUT_1S	plat_get_syscnt_freq2() + +#define PLLRDY_TIMEOUT	TIMEOUT_200MS +#define CLKSRC_TIMEOUT	TIMEOUT_200MS +#define CLKDIV_TIMEOUT	TIMEOUT_200MS +#define HSIDIV_TIMEOUT	TIMEOUT_200MS +#define OSCRDY_TIMEOUT	TIMEOUT_1S + +enum stm32mp1_parent_id { +/* Oscillators are defined in enum stm32mp_osc_id */ + +/* Other parent source */ +	_HSI_KER = NB_OSC, +	_HSE_KER, +	_HSE_KER_DIV2, +	_CSI_KER, +	_PLL1_P, +	_PLL1_Q, +	_PLL1_R, +	_PLL2_P, +	_PLL2_Q, +	_PLL2_R, +	_PLL3_P, +	_PLL3_Q, +	_PLL3_R, +	_PLL4_P, +	_PLL4_Q, +	_PLL4_R, +	_ACLK, +	_PCLK1, +	_PCLK2, +	_PCLK3, +	_PCLK4, +	_PCLK5, +	_HCLK6, +	_HCLK2, +	_CK_PER, +	_CK_MPU, +	_PARENT_NB, +	_UNKNOWN_ID = 0xff, +}; + +enum stm32mp1_parent_sel { +	_I2C46_SEL, +	_UART6_SEL, +	_UART24_SEL, +	_UART35_SEL, +	_UART78_SEL, +	_SDMMC12_SEL, +	_SDMMC3_SEL, +	_QSPI_SEL, +	_FMC_SEL, +	_USBPHY_SEL, +	_USBO_SEL, +	_STGEN_SEL, +	_PARENT_SEL_NB, +	_UNKNOWN_SEL = 0xff, +}; + +enum stm32mp1_pll_id { +	_PLL1, +	_PLL2, +	_PLL3, +	_PLL4, +	_PLL_NB +}; + +enum stm32mp1_div_id { +	_DIV_P, +	_DIV_Q, +	_DIV_R, +	_DIV_NB, +}; + +enum stm32mp1_clksrc_id { +	CLKSRC_MPU, +	CLKSRC_AXI, +	CLKSRC_PLL12, +	CLKSRC_PLL3, +	CLKSRC_PLL4, +	CLKSRC_RTC, +	CLKSRC_MCO1, +	CLKSRC_MCO2, +	CLKSRC_NB +}; + +enum stm32mp1_clkdiv_id { +	CLKDIV_MPU, +	CLKDIV_AXI, +	CLKDIV_APB1, +	CLKDIV_APB2, +	CLKDIV_APB3, +	CLKDIV_APB4, +	CLKDIV_APB5, +	CLKDIV_RTC, +	CLKDIV_MCO1, +	CLKDIV_MCO2, +	CLKDIV_NB +}; + +enum stm32mp1_pllcfg { +	PLLCFG_M, +	PLLCFG_N, +	PLLCFG_P, +	PLLCFG_Q, +	PLLCFG_R, +	PLLCFG_O, +	PLLCFG_NB +}; + +enum stm32mp1_pllcsg { +	PLLCSG_MOD_PER, +	PLLCSG_INC_STEP, +	PLLCSG_SSCG_MODE, +	PLLCSG_NB +}; + +enum stm32mp1_plltype { +	PLL_800, +	PLL_1600, +	PLL_TYPE_NB +}; + +struct stm32mp1_pll { +	uint8_t refclk_min; +	uint8_t refclk_max; +	uint8_t divn_max; +}; + +struct stm32mp1_clk_gate { +	uint16_t offset; +	uint8_t bit; +	uint8_t index; +	uint8_t set_clr; +	enum stm32mp1_parent_sel sel; +	enum stm32mp1_parent_id fixed; +	bool secure; +}; + +struct stm32mp1_clk_sel { +	uint16_t offset; +	uint8_t src; +	uint8_t msk; +	uint8_t nb_parent; +	const uint8_t *parent; +}; + +#define REFCLK_SIZE 4 +struct stm32mp1_clk_pll { +	enum stm32mp1_plltype plltype; +	uint16_t rckxselr; +	uint16_t pllxcfgr1; +	uint16_t pllxcfgr2; +	uint16_t pllxfracr; +	uint16_t pllxcr; +	uint16_t pllxcsgr; +	enum stm32mp_osc_id refclk[REFCLK_SIZE]; +}; + +struct stm32mp1_clk_data { +	const struct stm32mp1_clk_gate *gate; +	const struct stm32mp1_clk_sel *sel; +	const struct stm32mp1_clk_pll *pll; +	const int nb_gate; +}; + +struct stm32mp1_clk_priv { +	uint32_t base; +	const struct stm32mp1_clk_data *data; +	unsigned long osc[NB_OSC]; +	uint32_t pkcs_usb_value; +}; + +#define STM32MP1_CLK(off, b, idx, s)			\ +	{						\ +		.offset = (off),			\ +		.bit = (b),				\ +		.index = (idx),				\ +		.set_clr = 0,				\ +		.sel = (s),				\ +		.fixed = _UNKNOWN_ID,			\ +		.secure = 0,				\ +	} + +#define STM32MP1_CLK_F(off, b, idx, f)			\ +	{						\ +		.offset = (off),			\ +		.bit = (b),				\ +		.index = (idx),				\ +		.set_clr = 0,				\ +		.sel = _UNKNOWN_SEL,			\ +		.fixed = (f),				\ +		.secure = 0,				\ +	} + +#define STM32MP1_CLK_SET_CLR(off, b, idx, s)		\ +	{						\ +		.offset = (off),			\ +		.bit = (b),				\ +		.index = (idx),				\ +		.set_clr = 1,				\ +		.sel = (s),				\ +		.fixed = _UNKNOWN_ID,			\ +		.secure = 0,				\ +	} + +#define STM32MP1_CLK_SET_CLR_F(off, b, idx, f)		\ +	{						\ +		.offset = (off),			\ +		.bit = (b),				\ +		.index = (idx),				\ +		.set_clr = 1,				\ +		.sel = _UNKNOWN_SEL,			\ +		.fixed = (f),				\ +		.secure = 0,				\ +	} + +#define STM32MP1_CLK_SEC_SET_CLR(off, b, idx, s)	\ +	{						\ +		.offset = (off),			\ +		.bit = (b),				\ +		.index = (idx),				\ +		.set_clr = 1,				\ +		.sel = (s),				\ +		.fixed = _UNKNOWN_ID,			\ +		.secure = 1,				\ +	} + +#define STM32MP1_CLK_PARENT(idx, off, s, m, p)		\ +	[(idx)] = {					\ +		.offset = (off),			\ +		.src = (s),				\ +		.msk = (m),				\ +		.parent = (p),				\ +		.nb_parent = ARRAY_SIZE((p))		\ +	} + +#define STM32MP1_CLK_PLL(idx, type, off1, off2, off3,	\ +			 off4, off5, off6,		\ +			 p1, p2, p3, p4)		\ +	[(idx)] = {					\ +		.plltype = (type),			\ +		.rckxselr = (off1),			\ +		.pllxcfgr1 = (off2),			\ +		.pllxcfgr2 = (off3),			\ +		.pllxfracr = (off4),			\ +		.pllxcr = (off5),			\ +		.pllxcsgr = (off6),			\ +		.refclk[0] = (p1),			\ +		.refclk[1] = (p2),			\ +		.refclk[2] = (p3),			\ +		.refclk[3] = (p4),			\ +	} + +static const uint8_t stm32mp1_clks[][2] = { +	{CK_PER, _CK_PER}, +	{CK_MPU, _CK_MPU}, +	{CK_AXI, _ACLK}, +	{CK_HSE, _HSE}, +	{CK_CSI, _CSI}, +	{CK_LSI, _LSI}, +	{CK_LSE, _LSE}, +	{CK_HSI, _HSI}, +	{CK_HSE_DIV2, _HSE_KER_DIV2}, +}; + +static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { +	STM32MP1_CLK(RCC_DDRITFCR, 0, DDRC1, _UNKNOWN_SEL), +	STM32MP1_CLK(RCC_DDRITFCR, 1, DDRC1LP, _UNKNOWN_SEL), +	STM32MP1_CLK(RCC_DDRITFCR, 2, DDRC2, _UNKNOWN_SEL), +	STM32MP1_CLK(RCC_DDRITFCR, 3, DDRC2LP, _UNKNOWN_SEL), +	STM32MP1_CLK_F(RCC_DDRITFCR, 4, DDRPHYC, _PLL2_R), +	STM32MP1_CLK(RCC_DDRITFCR, 5, DDRPHYCLP, _UNKNOWN_SEL), +	STM32MP1_CLK(RCC_DDRITFCR, 6, DDRCAPB, _UNKNOWN_SEL), +	STM32MP1_CLK(RCC_DDRITFCR, 7, DDRCAPBLP, _UNKNOWN_SEL), +	STM32MP1_CLK(RCC_DDRITFCR, 8, AXIDCG, _UNKNOWN_SEL), +	STM32MP1_CLK(RCC_DDRITFCR, 9, DDRPHYCAPB, _UNKNOWN_SEL), +	STM32MP1_CLK(RCC_DDRITFCR, 10, DDRPHYCAPBLP, _UNKNOWN_SEL), + +	STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL), +	STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL), +	STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL), +	STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 17, UART5_K, _UART35_SEL), +	STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 18, UART7_K, _UART78_SEL), +	STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 19, UART8_K, _UART78_SEL), + +	STM32MP1_CLK_SET_CLR(RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL), + +	STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL), +	STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL), +	STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL), + +	STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL), +	STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5), +	STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 11, TZC1, _UNKNOWN_SEL), +	STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 12, TZC2, _UNKNOWN_SEL), +	STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL), + +	STM32MP1_CLK_SET_CLR(RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL), +	STM32MP1_CLK_SET_CLR(RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL), + +	STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL), +	STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL), +	STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL), +	STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 3, GPIOD, _UNKNOWN_SEL), +	STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 4, GPIOE, _UNKNOWN_SEL), +	STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 5, GPIOF, _UNKNOWN_SEL), +	STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 6, GPIOG, _UNKNOWN_SEL), +	STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 7, GPIOH, _UNKNOWN_SEL), +	STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 8, GPIOI, _UNKNOWN_SEL), +	STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_SEL), +	STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_SEL), + +	STM32MP1_CLK_SEC_SET_CLR(RCC_MP_AHB5ENSETR, 0, GPIOZ, _UNKNOWN_SEL), +	STM32MP1_CLK_SEC_SET_CLR(RCC_MP_AHB5ENSETR, 5, HASH1, _UNKNOWN_SEL), +	STM32MP1_CLK_SEC_SET_CLR(RCC_MP_AHB5ENSETR, 6, RNG1_K, _CSI_KER), +	STM32MP1_CLK_SEC_SET_CLR(RCC_MP_AHB5ENSETR, 8, BKPSRAM, _UNKNOWN_SEL), + +	STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 12, FMC_K, _FMC_SEL), +	STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 14, QSPI_K, _QSPI_SEL), +	STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 16, SDMMC1_K, _SDMMC12_SEL), +	STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 17, SDMMC2_K, _SDMMC12_SEL), +	STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL), + +	STM32MP1_CLK(RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL), +}; + +static const uint8_t i2c46_parents[] = {_PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER}; +static const uint8_t uart6_parents[] = {_PCLK2, _PLL4_Q, _HSI_KER, _CSI_KER, +					_HSE_KER}; +static const uint8_t uart24_parents[] = {_PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER, +					 _HSE_KER}; +static const uint8_t uart35_parents[] = {_PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER, +					 _HSE_KER}; +static const uint8_t uart78_parents[] = {_PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER, +					 _HSE_KER}; +static const uint8_t sdmmc12_parents[] = {_HCLK6, _PLL3_R, _PLL4_P, _HSI_KER}; +static const uint8_t sdmmc3_parents[] = {_HCLK2, _PLL3_R, _PLL4_P, _HSI_KER}; +static const uint8_t qspi_parents[] = {_ACLK, _PLL3_R, _PLL4_P, _CK_PER}; +static const uint8_t fmc_parents[] = {_ACLK, _PLL3_R, _PLL4_P, _CK_PER}; +static const uint8_t usbphy_parents[] = {_HSE_KER, _PLL4_R, _HSE_KER_DIV2}; +static const uint8_t usbo_parents[] = {_PLL4_R, _USB_PHY_48}; +static const uint8_t stgen_parents[] = {_HSI_KER, _HSE_KER}; + +static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { +	STM32MP1_CLK_PARENT(_I2C46_SEL, RCC_I2C46CKSELR, 0, 0x7, i2c46_parents), +	STM32MP1_CLK_PARENT(_UART6_SEL, RCC_UART6CKSELR, 0, 0x7, uart6_parents), +	STM32MP1_CLK_PARENT(_UART24_SEL, RCC_UART24CKSELR, 0, 0x7, +			    uart24_parents), +	STM32MP1_CLK_PARENT(_UART35_SEL, RCC_UART35CKSELR, 0, 0x7, +			    uart35_parents), +	STM32MP1_CLK_PARENT(_UART78_SEL, RCC_UART78CKSELR, 0, 0x7, +			    uart78_parents), +	STM32MP1_CLK_PARENT(_SDMMC12_SEL, RCC_SDMMC12CKSELR, 0, 0x7, +			    sdmmc12_parents), +	STM32MP1_CLK_PARENT(_SDMMC3_SEL, RCC_SDMMC3CKSELR, 0, 0x7, +			    sdmmc3_parents), +	STM32MP1_CLK_PARENT(_QSPI_SEL, RCC_QSPICKSELR, 0, 0xf, qspi_parents), +	STM32MP1_CLK_PARENT(_FMC_SEL, RCC_FMCCKSELR, 0, 0xf, fmc_parents), +	STM32MP1_CLK_PARENT(_USBPHY_SEL, RCC_USBCKSELR, 0, 0x3, usbphy_parents), +	STM32MP1_CLK_PARENT(_USBO_SEL, RCC_USBCKSELR, 4, 0x1, usbo_parents), +	STM32MP1_CLK_PARENT(_STGEN_SEL, RCC_STGENCKSELR, 0, 0x3, stgen_parents), +}; + +/* Define characteristic of PLL according type */ +#define DIVN_MIN	24 +static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = { +	[PLL_800] = { +		.refclk_min = 4, +		.refclk_max = 16, +		.divn_max = 99, +	}, +	[PLL_1600] = { +		.refclk_min = 8, +		.refclk_max = 16, +		.divn_max = 199, +	}, +}; + +/* PLLNCFGR2 register divider by output */ +static const uint8_t pllncfgr2[_DIV_NB] = { +	[_DIV_P] = RCC_PLLNCFGR2_DIVP_SHIFT, +	[_DIV_Q] = RCC_PLLNCFGR2_DIVQ_SHIFT, +	[_DIV_R] = RCC_PLLNCFGR2_DIVR_SHIFT +}; + +static const struct stm32mp1_clk_pll stm32mp1_clk_pll[_PLL_NB] = { +	STM32MP1_CLK_PLL(_PLL1, PLL_1600, +			 RCC_RCK12SELR, RCC_PLL1CFGR1, RCC_PLL1CFGR2, +			 RCC_PLL1FRACR, RCC_PLL1CR, RCC_PLL1CSGR, +			 _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID), +	STM32MP1_CLK_PLL(_PLL2, PLL_1600, +			 RCC_RCK12SELR, RCC_PLL2CFGR1, RCC_PLL2CFGR2, +			 RCC_PLL2FRACR, RCC_PLL2CR, RCC_PLL2CSGR, +			 _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID), +	STM32MP1_CLK_PLL(_PLL3, PLL_800, +			 RCC_RCK3SELR, RCC_PLL3CFGR1, RCC_PLL3CFGR2, +			 RCC_PLL3FRACR, RCC_PLL3CR, RCC_PLL3CSGR, +			 _HSI, _HSE, _CSI, _UNKNOWN_OSC_ID), +	STM32MP1_CLK_PLL(_PLL4, PLL_800, +			 RCC_RCK4SELR, RCC_PLL4CFGR1, RCC_PLL4CFGR2, +			 RCC_PLL4FRACR, RCC_PLL4CR, RCC_PLL4CSGR, +			 _HSI, _HSE, _CSI, _I2S_CKIN), +}; + +/* Prescaler table lookups for clock computation */ + +/* div = /1 /2 /4 /8 /16 : same divider for PMU and APBX */ +#define stm32mp1_mpu_div stm32mp1_mpu_apbx_div +#define stm32mp1_apbx_div stm32mp1_mpu_apbx_div +static const uint8_t stm32mp1_mpu_apbx_div[8] = { +	0, 1, 2, 3, 4, 4, 4, 4 +}; + +/* div = /1 /2 /3 /4 */ +static const uint8_t stm32mp1_axi_div[8] = { +	1, 2, 3, 4, 4, 4, 4, 4 +}; + +static const struct stm32mp1_clk_data stm32mp1_data = { +	.gate = stm32mp1_clk_gate, +	.sel = stm32mp1_clk_sel, +	.pll = stm32mp1_clk_pll, +	.nb_gate = ARRAY_SIZE(stm32mp1_clk_gate), +}; + +static struct stm32mp1_clk_priv stm32mp1_clk_priv_data; + +static unsigned long stm32mp1_clk_get_fixed(struct stm32mp1_clk_priv *priv, +					    enum stm32mp_osc_id idx) +{ +	if (idx >= NB_OSC) { +		return 0; +	} + +	return priv->osc[idx]; +} + +static int stm32mp1_clk_get_id(struct stm32mp1_clk_priv *priv, unsigned long id) +{ +	const struct stm32mp1_clk_gate *gate = priv->data->gate; +	int i; +	int nb_clks = priv->data->nb_gate; + +	for (i = 0; i < nb_clks; i++) { +		if (gate[i].index == id) { +			return i; +		} +	} + +	ERROR("%s: clk id %d not found\n", __func__, (uint32_t)id); + +	return -EINVAL; +} + +static enum stm32mp1_parent_sel +stm32mp1_clk_get_sel(struct stm32mp1_clk_priv *priv, int i) +{ +	const struct stm32mp1_clk_gate *gate = priv->data->gate; + +	return gate[i].sel; +} + +static enum stm32mp1_parent_id +stm32mp1_clk_get_fixed_parent(struct stm32mp1_clk_priv *priv, int i) +{ +	const struct stm32mp1_clk_gate *gate = priv->data->gate; + +	return gate[i].fixed; +} + +static int stm32mp1_clk_get_parent(struct stm32mp1_clk_priv *priv, +				   unsigned long id) +{ +	const struct stm32mp1_clk_sel *sel = priv->data->sel; +	uint32_t j, p_sel; +	int i; +	enum stm32mp1_parent_id p; +	enum stm32mp1_parent_sel s; + +	for (j = 0; j < ARRAY_SIZE(stm32mp1_clks); j++) { +		if (stm32mp1_clks[j][0] == id) { +			return (int)stm32mp1_clks[j][1]; +		} +	} + +	i = stm32mp1_clk_get_id(priv, id); +	if (i < 0) { +		return i; +	} + +	p = stm32mp1_clk_get_fixed_parent(priv, i); +	if (p < _PARENT_NB) { +		return (int)p; +	} + +	s = stm32mp1_clk_get_sel(priv, i); +	if (s >= _PARENT_SEL_NB) { +		return -EINVAL; +	} + +	p_sel = (mmio_read_32(priv->base + sel[s].offset) >> sel[s].src) & +		sel[s].msk; + +	if (p_sel < sel[s].nb_parent) { +		return (int)sel[s].parent[p_sel]; +	} + +	ERROR("%s: no parents defined for clk id %ld\n", __func__, id); + +	return -EINVAL; +} + +static unsigned long stm32mp1_pll_get_fref_ck(struct stm32mp1_clk_priv *priv, +					      enum stm32mp1_pll_id pll_id) +{ +	const struct stm32mp1_clk_pll *pll = priv->data->pll; +	uint32_t selr, src; +	unsigned long refclk; + +	selr = mmio_read_32(priv->base + pll[pll_id].rckxselr); +	src = selr & RCC_SELR_REFCLK_SRC_MASK; + +	refclk = stm32mp1_clk_get_fixed(priv, pll[pll_id].refclk[src]); + +	return refclk; +} + +/* + * pll_get_fvco() : return the VCO or (VCO / 2) frequency for the requested PLL + * - PLL1 & PLL2 => return VCO / 2 with Fpll_y_ck = FVCO / 2 * (DIVy + 1) + * - PLL3 & PLL4 => return VCO     with Fpll_y_ck = FVCO / (DIVy + 1) + * => in all cases Fpll_y_ck = pll_get_fvco() / (DIVy + 1) + */ +static unsigned long stm32mp1_pll_get_fvco(struct stm32mp1_clk_priv *priv, +					   enum stm32mp1_pll_id pll_id) +{ +	const struct stm32mp1_clk_pll *pll = priv->data->pll; +	unsigned long refclk, fvco; +	uint32_t cfgr1, fracr, divm, divn; + +	cfgr1 = mmio_read_32(priv->base + pll[pll_id].pllxcfgr1); +	fracr = mmio_read_32(priv->base + pll[pll_id].pllxfracr); + +	divm = (cfgr1 & (RCC_PLLNCFGR1_DIVM_MASK)) >> RCC_PLLNCFGR1_DIVM_SHIFT; +	divn = cfgr1 & RCC_PLLNCFGR1_DIVN_MASK; + +	refclk = stm32mp1_pll_get_fref_ck(priv, pll_id); + +	/* +	 * With FRACV : +	 *   Fvco = Fck_ref * ((DIVN + 1) + FRACV / 2^13) / (DIVM + 1) +	 * Without FRACV +	 *   Fvco = Fck_ref * ((DIVN + 1) / (DIVM + 1) +	 */ +	if ((fracr & RCC_PLLNFRACR_FRACLE) != 0U) { +		uint32_t fracv = (fracr & RCC_PLLNFRACR_FRACV_MASK) +			    >> RCC_PLLNFRACR_FRACV_SHIFT; +		unsigned long long numerator, denominator; + +		numerator = ((unsigned long long)divn + 1U) << 13; +		numerator = (refclk * numerator) + fracv; +		denominator = ((unsigned long long)divm + 1U)  << 13; +		fvco = (unsigned long)(numerator / denominator); +	} else { +		fvco = (unsigned long)(refclk * (divn + 1U) / (divm + 1U)); +	} + +	return fvco; +} + +static unsigned long stm32mp1_read_pll_freq(struct stm32mp1_clk_priv *priv, +					    enum stm32mp1_pll_id pll_id, +					    enum stm32mp1_div_id div_id) +{ +	const struct stm32mp1_clk_pll *pll = priv->data->pll; +	unsigned long dfout; +	uint32_t cfgr2, divy; + +	if (div_id >= _DIV_NB) { +		return 0; +	} + +	cfgr2 = mmio_read_32(priv->base + pll[pll_id].pllxcfgr2); +	divy = (cfgr2 >> pllncfgr2[div_id]) & RCC_PLLNCFGR2_DIVX_MASK; + +	dfout = stm32mp1_pll_get_fvco(priv, pll_id) / (divy + 1U); + +	return dfout; +} + +static unsigned long stm32mp1_clk_get(struct stm32mp1_clk_priv *priv, int p) +{ +	uint32_t reg, clkdiv; +	unsigned long clock = 0; + +	switch (p) { +	case _CK_MPU: +	/* MPU sub system */ +		reg = mmio_read_32(priv->base + RCC_MPCKSELR); +		switch (reg & RCC_SELR_SRC_MASK) { +		case RCC_MPCKSELR_HSI: +			clock = stm32mp1_clk_get_fixed(priv, _HSI); +			break; +		case RCC_MPCKSELR_HSE: +			clock = stm32mp1_clk_get_fixed(priv, _HSE); +			break; +		case RCC_MPCKSELR_PLL: +			clock = stm32mp1_read_pll_freq(priv, _PLL1, _DIV_P); +			break; +		case RCC_MPCKSELR_PLL_MPUDIV: +			clock = stm32mp1_read_pll_freq(priv, _PLL1, _DIV_P); + +			reg = mmio_read_32(priv->base + RCC_MPCKDIVR); +			clkdiv = reg & RCC_MPUDIV_MASK; +			if (clkdiv != 0U) { +				clock /= stm32mp1_mpu_div[clkdiv]; +			} + +			break; +		default: +			break; +		} +		break; +	/* AXI sub system */ +	case _ACLK: +	case _HCLK2: +	case _HCLK6: +	case _PCLK4: +	case _PCLK5: +		reg = mmio_read_32(priv->base + RCC_ASSCKSELR); +		switch (reg & RCC_SELR_SRC_MASK) { +		case RCC_ASSCKSELR_HSI: +			clock = stm32mp1_clk_get_fixed(priv, _HSI); +			break; +		case RCC_ASSCKSELR_HSE: +			clock = stm32mp1_clk_get_fixed(priv, _HSE); +			break; +		case RCC_ASSCKSELR_PLL: +			clock = stm32mp1_read_pll_freq(priv, _PLL2, _DIV_P); +			break; +		default: +			break; +		} + +		/* System clock divider */ +		reg = mmio_read_32(priv->base + RCC_AXIDIVR); +		clock /= stm32mp1_axi_div[reg & RCC_AXIDIV_MASK]; + +		switch (p) { +		case _PCLK4: +			reg = mmio_read_32(priv->base + RCC_APB4DIVR); +			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; +			break; +		case _PCLK5: +			reg = mmio_read_32(priv->base + RCC_APB5DIVR); +			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; +			break; +		default: +			break; +		} +		break; +	case _CK_PER: +		reg = mmio_read_32(priv->base + RCC_CPERCKSELR); +		switch (reg & RCC_SELR_SRC_MASK) { +		case RCC_CPERCKSELR_HSI: +			clock = stm32mp1_clk_get_fixed(priv, _HSI); +			break; +		case RCC_CPERCKSELR_HSE: +			clock = stm32mp1_clk_get_fixed(priv, _HSE); +			break; +		case RCC_CPERCKSELR_CSI: +			clock = stm32mp1_clk_get_fixed(priv, _CSI); +			break; +		default: +			break; +		} +		break; +	case _HSI: +	case _HSI_KER: +		clock = stm32mp1_clk_get_fixed(priv, _HSI); +		break; +	case _CSI: +	case _CSI_KER: +		clock = stm32mp1_clk_get_fixed(priv, _CSI); +		break; +	case _HSE: +	case _HSE_KER: +		clock = stm32mp1_clk_get_fixed(priv, _HSE); +		break; +	case _HSE_KER_DIV2: +		clock = stm32mp1_clk_get_fixed(priv, _HSE) >> 1; +		break; +	case _LSI: +		clock = stm32mp1_clk_get_fixed(priv, _LSI); +		break; +	case _LSE: +		clock = stm32mp1_clk_get_fixed(priv, _LSE); +		break; +	/* PLL */ +	case _PLL1_P: +		clock = stm32mp1_read_pll_freq(priv, _PLL1, _DIV_P); +		break; +	case _PLL1_Q: +		clock = stm32mp1_read_pll_freq(priv, _PLL1, _DIV_Q); +		break; +	case _PLL1_R: +		clock = stm32mp1_read_pll_freq(priv, _PLL1, _DIV_R); +		break; +	case _PLL2_P: +		clock = stm32mp1_read_pll_freq(priv, _PLL2, _DIV_P); +		break; +	case _PLL2_Q: +		clock = stm32mp1_read_pll_freq(priv, _PLL2, _DIV_Q); +		break; +	case _PLL2_R: +		clock = stm32mp1_read_pll_freq(priv, _PLL2, _DIV_R); +		break; +	case _PLL3_P: +		clock = stm32mp1_read_pll_freq(priv, _PLL3, _DIV_P); +		break; +	case _PLL3_Q: +		clock = stm32mp1_read_pll_freq(priv, _PLL3, _DIV_Q); +		break; +	case _PLL3_R: +		clock = stm32mp1_read_pll_freq(priv, _PLL3, _DIV_R); +		break; +	case _PLL4_P: +		clock = stm32mp1_read_pll_freq(priv, _PLL4, _DIV_P); +		break; +	case _PLL4_Q: +		clock = stm32mp1_read_pll_freq(priv, _PLL4, _DIV_Q); +		break; +	case _PLL4_R: +		clock = stm32mp1_read_pll_freq(priv, _PLL4, _DIV_R); +		break; +	/* Other */ +	case _USB_PHY_48: +		clock = stm32mp1_clk_get_fixed(priv, _USB_PHY_48); +		break; +	default: +		break; +	} + +	return clock; +} + +bool stm32mp1_clk_is_enabled(unsigned long id) +{ +	struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data; +	const struct stm32mp1_clk_gate *gate = priv->data->gate; +	int i = stm32mp1_clk_get_id(priv, id); + +	if (i < 0) { +		return false; +	} + +	return ((mmio_read_32(priv->base + gate[i].offset) & +		 BIT(gate[i].bit)) != 0U); +} + +int stm32mp1_clk_enable(unsigned long id) +{ +	struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data; +	const struct stm32mp1_clk_gate *gate = priv->data->gate; +	int i = stm32mp1_clk_get_id(priv, id); + +	if (i < 0) { +		return i; +	} + +	if (gate[i].set_clr != 0U) { +		mmio_write_32(priv->base + gate[i].offset, BIT(gate[i].bit)); +	} else { +		mmio_setbits_32(priv->base + gate[i].offset, BIT(gate[i].bit)); +	} + +	return 0; +} + +int stm32mp1_clk_disable(unsigned long id) +{ +	struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data; +	const struct stm32mp1_clk_gate *gate = priv->data->gate; +	int i = stm32mp1_clk_get_id(priv, id); + +	if (i < 0) { +		return i; +	} + +	if (gate[i].set_clr != 0U) { +		mmio_write_32(priv->base + gate[i].offset +			      + RCC_MP_ENCLRR_OFFSET, +			      BIT(gate[i].bit)); +	} else { +		mmio_clrbits_32(priv->base + gate[i].offset, BIT(gate[i].bit)); +	} + +	return 0; +} + +unsigned long stm32mp1_clk_get_rate(unsigned long id) +{ +	struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data; +	int p = stm32mp1_clk_get_parent(priv, id); +	unsigned long rate; + +	if (p < 0) { +		return 0; +	} + +	rate = stm32mp1_clk_get(priv, p); + +	return rate; +} + +static void stm32mp1_ls_osc_set(int enable, uint32_t rcc, uint32_t offset, +				uint32_t mask_on) +{ +	uint32_t address = rcc + offset; + +	if (enable != 0) { +		mmio_setbits_32(address, mask_on); +	} else { +		mmio_clrbits_32(address, mask_on); +	} +} + +static void stm32mp1_hs_ocs_set(int enable, uint32_t rcc, uint32_t mask_on) +{ +	if (enable != 0) { +		mmio_setbits_32(rcc + RCC_OCENSETR, mask_on); +	} else { +		mmio_setbits_32(rcc + RCC_OCENCLRR, mask_on); +	} +} + +static int stm32mp1_osc_wait(int enable, uint32_t rcc, uint32_t offset, +			     uint32_t mask_rdy) +{ +	unsigned long start; +	uint32_t mask_test; +	uint32_t address = rcc + offset; + +	if (enable != 0) { +		mask_test = mask_rdy; +	} else { +		mask_test = 0; +	} + +	start = get_timer(0); +	while ((mmio_read_32(address) & mask_rdy) != mask_test) { +		if (get_timer(start) > OSCRDY_TIMEOUT) { +			ERROR("OSC %x @ %x timeout for enable=%d : 0x%x\n", +			      mask_rdy, address, enable, mmio_read_32(address)); +			return -ETIMEDOUT; +		} +	} + +	return 0; +} + +static void stm32mp1_lse_enable(uint32_t rcc, bool bypass, uint32_t lsedrv) +{ +	uint32_t value; + +	if (bypass) { +		mmio_setbits_32(rcc + RCC_BDCR, RCC_BDCR_LSEBYP); +	} + +	/* +	 * Warning: not recommended to switch directly from "high drive" +	 * to "medium low drive", and vice-versa. +	 */ +	value = (mmio_read_32(rcc + RCC_BDCR) & RCC_BDCR_LSEDRV_MASK) >> +		RCC_BDCR_LSEDRV_SHIFT; + +	while (value != lsedrv) { +		if (value > lsedrv) { +			value--; +		} else { +			value++; +		} + +		mmio_clrsetbits_32(rcc + RCC_BDCR, +				   RCC_BDCR_LSEDRV_MASK, +				   value << RCC_BDCR_LSEDRV_SHIFT); +	} + +	stm32mp1_ls_osc_set(1, rcc, RCC_BDCR, RCC_BDCR_LSEON); +} + +static void stm32mp1_lse_wait(uint32_t rcc) +{ +	if (stm32mp1_osc_wait(1, rcc, RCC_BDCR, RCC_BDCR_LSERDY) != 0) { +		VERBOSE("%s: failed\n", __func__); +	} +} + +static void stm32mp1_lsi_set(uint32_t rcc, int enable) +{ +	stm32mp1_ls_osc_set(enable, rcc, RCC_RDLSICR, RCC_RDLSICR_LSION); +	if (stm32mp1_osc_wait(enable, rcc, RCC_RDLSICR, RCC_RDLSICR_LSIRDY) != +	    0) { +		VERBOSE("%s: failed\n", __func__); +	} +} + +static void stm32mp1_hse_enable(uint32_t rcc, bool bypass, bool css) +{ +	if (bypass) { +		mmio_setbits_32(rcc + RCC_OCENSETR, RCC_OCENR_HSEBYP); +	} + +	stm32mp1_hs_ocs_set(1, rcc, RCC_OCENR_HSEON); +	if (stm32mp1_osc_wait(1, rcc, RCC_OCRDYR, RCC_OCRDYR_HSERDY) != +	    0) { +		VERBOSE("%s: failed\n", __func__); +	} + +	if (css) { +		mmio_setbits_32(rcc + RCC_OCENSETR, RCC_OCENR_HSECSSON); +	} +} + +static void stm32mp1_csi_set(uint32_t rcc, int enable) +{ +	stm32mp1_ls_osc_set(enable, rcc, RCC_OCENSETR, RCC_OCENR_CSION); +	if (stm32mp1_osc_wait(enable, rcc, RCC_OCRDYR, RCC_OCRDYR_CSIRDY) != +	    0) { +		VERBOSE("%s: failed\n", __func__); +	} +} + +static void stm32mp1_hsi_set(uint32_t rcc, int enable) +{ +	stm32mp1_hs_ocs_set(enable, rcc, RCC_OCENR_HSION); +	if (stm32mp1_osc_wait(enable, rcc, RCC_OCRDYR, RCC_OCRDYR_HSIRDY) != +	    0) { +		VERBOSE("%s: failed\n", __func__); +	} +} + +static int stm32mp1_set_hsidiv(uint32_t rcc, uint8_t hsidiv) +{ +	unsigned long start; +	uint32_t address = rcc + RCC_OCRDYR; + +	mmio_clrsetbits_32(rcc + RCC_HSICFGR, +			   RCC_HSICFGR_HSIDIV_MASK, +			   RCC_HSICFGR_HSIDIV_MASK & (uint32_t)hsidiv); + +	start = get_timer(0); +	while ((mmio_read_32(address) & RCC_OCRDYR_HSIDIVRDY) == 0U) { +		if (get_timer(start) > HSIDIV_TIMEOUT) { +			ERROR("HSIDIV failed @ 0x%x: 0x%x\n", +			      address, mmio_read_32(address)); +			return -ETIMEDOUT; +		} +	} + +	return 0; +} + +static int stm32mp1_hsidiv(uint32_t rcc, unsigned long hsifreq) +{ +	uint8_t hsidiv; +	uint32_t hsidivfreq = MAX_HSI_HZ; + +	for (hsidiv = 0; hsidiv < 4U; hsidiv++) { +		if (hsidivfreq == hsifreq) { +			break; +		} + +		hsidivfreq /= 2U; +	} + +	if (hsidiv == 4U) { +		ERROR("Invalid clk-hsi frequency\n"); +		return -1; +	} + +	if (hsidiv != 0U) { +		return stm32mp1_set_hsidiv(rcc, hsidiv); +	} + +	return 0; +} + +static void stm32mp1_pll_start(struct stm32mp1_clk_priv *priv, +			       enum stm32mp1_pll_id pll_id) +{ +	const struct stm32mp1_clk_pll *pll = priv->data->pll; + +	mmio_write_32(priv->base + pll[pll_id].pllxcr, RCC_PLLNCR_PLLON); +} + +static int stm32mp1_pll_output(struct stm32mp1_clk_priv *priv, +			       enum stm32mp1_pll_id pll_id, uint32_t output) +{ +	const struct stm32mp1_clk_pll *pll = priv->data->pll; +	uint32_t pllxcr = priv->base + pll[pll_id].pllxcr; +	unsigned long start; + +	start = get_timer(0); +	/* Wait PLL lock */ +	while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) == 0U) { +		if (get_timer(start) > PLLRDY_TIMEOUT) { +			ERROR("PLL%d start failed @ 0x%x: 0x%x\n", +			      pll_id, pllxcr, mmio_read_32(pllxcr)); +			return -ETIMEDOUT; +		} +	} + +	/* Start the requested output */ +	mmio_setbits_32(pllxcr, output << RCC_PLLNCR_DIVEN_SHIFT); + +	return 0; +} + +static int stm32mp1_pll_stop(struct stm32mp1_clk_priv *priv, +			     enum stm32mp1_pll_id pll_id) +{ +	const struct stm32mp1_clk_pll *pll = priv->data->pll; +	uint32_t pllxcr = priv->base + pll[pll_id].pllxcr; +	unsigned long start; + +	/* Stop all output */ +	mmio_clrbits_32(pllxcr, RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | +			RCC_PLLNCR_DIVREN); + +	/* Stop PLL */ +	mmio_clrbits_32(pllxcr, RCC_PLLNCR_PLLON); + +	start = get_timer(0); +	/* Wait PLL stopped */ +	while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) != 0U) { +		if (get_timer(start) > PLLRDY_TIMEOUT) { +			ERROR("PLL%d stop failed @ 0x%x: 0x%x\n", +			      pll_id, pllxcr, mmio_read_32(pllxcr)); +			return -ETIMEDOUT; +		} +	} + +	return 0; +} + +static void stm32mp1_pll_config_output(struct stm32mp1_clk_priv *priv, +				       enum stm32mp1_pll_id pll_id, +				       uint32_t *pllcfg) +{ +	const struct stm32mp1_clk_pll *pll = priv->data->pll; +	uint32_t rcc = priv->base; +	uint32_t value; + +	value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) & +		RCC_PLLNCFGR2_DIVP_MASK; +	value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) & +		 RCC_PLLNCFGR2_DIVQ_MASK; +	value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) & +		 RCC_PLLNCFGR2_DIVR_MASK; +	mmio_write_32(rcc + pll[pll_id].pllxcfgr2, value); +} + +static int stm32mp1_pll_config(struct stm32mp1_clk_priv *priv, +			       enum stm32mp1_pll_id pll_id, +			       uint32_t *pllcfg, uint32_t fracv) +{ +	const struct stm32mp1_clk_pll *pll = priv->data->pll; +	uint32_t rcc = priv->base; +	enum stm32mp1_plltype type = pll[pll_id].plltype; +	unsigned long refclk; +	uint32_t ifrge = 0; +	uint32_t src, value; + +	src = mmio_read_32(priv->base + pll[pll_id].rckxselr) & +		RCC_SELR_REFCLK_SRC_MASK; + +	refclk = stm32mp1_clk_get_fixed(priv, pll[pll_id].refclk[src]) / +		 (pllcfg[PLLCFG_M] + 1U); + +	if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) || +	    (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) { +		return -EINVAL; +	} + +	if ((type == PLL_800) && (refclk >= 8000000U)) { +		ifrge = 1U; +	} + +	value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) & +		RCC_PLLNCFGR1_DIVN_MASK; +	value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) & +		 RCC_PLLNCFGR1_DIVM_MASK; +	value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) & +		 RCC_PLLNCFGR1_IFRGE_MASK; +	mmio_write_32(rcc + pll[pll_id].pllxcfgr1, value); + +	/* Fractional configuration */ +	value = 0; +	mmio_write_32(rcc + pll[pll_id].pllxfracr, value); + +	value = fracv << RCC_PLLNFRACR_FRACV_SHIFT; +	mmio_write_32(rcc + pll[pll_id].pllxfracr, value); + +	value |= RCC_PLLNFRACR_FRACLE; +	mmio_write_32(rcc + pll[pll_id].pllxfracr, value); + +	stm32mp1_pll_config_output(priv, pll_id, pllcfg); + +	return 0; +} + +static void stm32mp1_pll_csg(struct stm32mp1_clk_priv *priv, +			     enum stm32mp1_pll_id pll_id, +			     uint32_t *csg) +{ +	const struct stm32mp1_clk_pll *pll = priv->data->pll; +	uint32_t pllxcsg = 0; + +	pllxcsg |= (csg[PLLCSG_MOD_PER] << RCC_PLLNCSGR_MOD_PER_SHIFT) & +		    RCC_PLLNCSGR_MOD_PER_MASK; + +	pllxcsg |= (csg[PLLCSG_INC_STEP] << RCC_PLLNCSGR_INC_STEP_SHIFT) & +		    RCC_PLLNCSGR_INC_STEP_MASK; + +	pllxcsg |= (csg[PLLCSG_SSCG_MODE] << RCC_PLLNCSGR_SSCG_MODE_SHIFT) & +		    RCC_PLLNCSGR_SSCG_MODE_MASK; + +	mmio_write_32(priv->base + pll[pll_id].pllxcsgr, pllxcsg); +} + +static int stm32mp1_set_clksrc(struct stm32mp1_clk_priv *priv, +			       unsigned int clksrc) +{ +	uint32_t address = priv->base + (clksrc >> 4); +	unsigned long start; + +	mmio_clrsetbits_32(address, RCC_SELR_SRC_MASK, +			   clksrc & RCC_SELR_SRC_MASK); + +	start = get_timer(0); +	while ((mmio_read_32(address) & RCC_SELR_SRCRDY) == 0U) { +		if (get_timer(start) > CLKSRC_TIMEOUT) { +			ERROR("CLKSRC %x start failed @ 0x%x: 0x%x\n", +			      clksrc, address, mmio_read_32(address)); +			return -ETIMEDOUT; +		} +	} + +	return 0; +} + +static int stm32mp1_set_clkdiv(unsigned int clkdiv, uint32_t address) +{ +	unsigned long start; + +	mmio_clrsetbits_32(address, RCC_DIVR_DIV_MASK, +			   clkdiv & RCC_DIVR_DIV_MASK); + +	start = get_timer(0); +	while ((mmio_read_32(address) & RCC_DIVR_DIVRDY) == 0U) { +		if (get_timer(start) > CLKDIV_TIMEOUT) { +			ERROR("CLKDIV %x start failed @ 0x%x: 0x%x\n", +			      clkdiv, address, mmio_read_32(address)); +			return -ETIMEDOUT; +		} +	} + +	return 0; +} + +static void stm32mp1_mco_csg(struct stm32mp1_clk_priv *priv, +			     uint32_t clksrc, uint32_t clkdiv) +{ +	uint32_t address = priv->base + (clksrc >> 4); + +	/* +	 * Binding clksrc : +	 *      bit15-4 offset +	 *      bit3:   disable +	 *      bit2-0: MCOSEL[2:0] +	 */ +	if ((clksrc & 0x8U) != 0U) { +		mmio_clrbits_32(address, RCC_MCOCFG_MCOON); +	} else { +		mmio_clrsetbits_32(address, +				   RCC_MCOCFG_MCOSRC_MASK, +				   clksrc & RCC_MCOCFG_MCOSRC_MASK); +		mmio_clrsetbits_32(address, +				   RCC_MCOCFG_MCODIV_MASK, +				   clkdiv << RCC_MCOCFG_MCODIV_SHIFT); +		mmio_setbits_32(address, RCC_MCOCFG_MCOON); +	} +} + +static void stm32mp1_set_rtcsrc(struct stm32mp1_clk_priv *priv, +				unsigned int clksrc, bool lse_css) +{ +	uint32_t address = priv->base + RCC_BDCR; + +	if (((mmio_read_32(address) & RCC_BDCR_RTCCKEN) == 0U) || +	    (clksrc != (uint32_t)CLK_RTC_DISABLED)) { +		mmio_clrsetbits_32(address, +				   RCC_BDCR_RTCSRC_MASK, +				   clksrc << RCC_BDCR_RTCSRC_SHIFT); + +		mmio_setbits_32(address, RCC_BDCR_RTCCKEN); +	} + +	if (lse_css) { +		mmio_setbits_32(address, RCC_BDCR_LSECSSON); +	} +} + +#define CNTCVL_OFF	0x008 +#define CNTCVU_OFF	0x00C + +static void stm32mp1_stgen_config(struct stm32mp1_clk_priv *priv) +{ +	uintptr_t stgen; +	int p; +	uint32_t cntfid0; +	unsigned long rate; + +	stgen = fdt_get_stgen_base(); + +	cntfid0 = mmio_read_32(stgen + CNTFID_OFF); +	p = stm32mp1_clk_get_parent(priv, STGEN_K); +	rate = stm32mp1_clk_get(priv, p); + +	if (cntfid0 != rate) { +		unsigned long long counter; + +		mmio_clrbits_32(stgen + CNTCR_OFF, CNTCR_EN); +		counter = (unsigned long long) +			mmio_read_32(stgen + CNTCVL_OFF); +		counter |= ((unsigned long long) +			    (mmio_read_32(stgen + CNTCVU_OFF))) << 32; +		counter = (counter * rate / cntfid0); +		mmio_write_32(stgen + CNTCVL_OFF, (uint32_t)counter); +		mmio_write_32(stgen + CNTCVU_OFF, (uint32_t)(counter >> 32)); +		mmio_write_32(stgen + CNTFID_OFF, rate); +		mmio_setbits_32(stgen + CNTCR_OFF, CNTCR_EN); + +		write_cntfrq((u_register_t)rate); + +		/* Need to update timer with new frequency */ +		generic_delay_timer_init(); +	} +} + +void stm32mp1_stgen_increment(unsigned long long offset_in_ms) +{ +	uintptr_t stgen; +	unsigned long long cnt; + +	stgen = fdt_get_stgen_base(); + +	cnt = ((unsigned long long)mmio_read_32(stgen + CNTCVU_OFF) << 32) | +		mmio_read_32(stgen + CNTCVL_OFF); + +	cnt += (offset_in_ms * mmio_read_32(stgen + CNTFID_OFF)) / 1000U; + +	mmio_clrbits_32(stgen + CNTCR_OFF, CNTCR_EN); +	mmio_write_32(stgen + CNTCVL_OFF, (uint32_t)cnt); +	mmio_write_32(stgen + CNTCVU_OFF, (uint32_t)(cnt >> 32)); +	mmio_setbits_32(stgen + CNTCR_OFF, CNTCR_EN); +} + +static void stm32mp1_pkcs_config(struct stm32mp1_clk_priv *priv, uint32_t pkcs) +{ +	uint32_t address = priv->base + ((pkcs >> 4) & 0xFFFU); +	uint32_t value = pkcs & 0xFU; +	uint32_t mask = 0xFU; + +	if ((pkcs & BIT(31)) != 0U) { +		mask <<= 4; +		value <<= 4; +	} + +	mmio_clrsetbits_32(address, mask, value); +} + +int stm32mp1_clk_init(void) +{ +	struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data; +	uint32_t rcc = priv->base; +	unsigned int clksrc[CLKSRC_NB]; +	unsigned int clkdiv[CLKDIV_NB]; +	unsigned int pllcfg[_PLL_NB][PLLCFG_NB]; +	int plloff[_PLL_NB]; +	int ret, len; +	enum stm32mp1_pll_id i; +	bool lse_css = false; +	const uint32_t *pkcs_cell; + +	/* Check status field to disable security */ +	if (!fdt_get_rcc_secure_status()) { +		mmio_write_32(rcc + RCC_TZCR, 0); +	} + +	ret = fdt_rcc_read_uint32_array("st,clksrc", clksrc, +					(uint32_t)CLKSRC_NB); +	if (ret < 0) { +		return -FDT_ERR_NOTFOUND; +	} + +	ret = fdt_rcc_read_uint32_array("st,clkdiv", clkdiv, +					(uint32_t)CLKDIV_NB); +	if (ret < 0) { +		return -FDT_ERR_NOTFOUND; +	} + +	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { +		char name[12]; + +		sprintf(name, "st,pll@%d", i); +		plloff[i] = fdt_rcc_subnode_offset(name); + +		if (!fdt_check_node(plloff[i])) { +			continue; +		} + +		ret = fdt_read_uint32_array(plloff[i], "cfg", +					    pllcfg[i], (int)PLLCFG_NB); +		if (ret < 0) { +			return -FDT_ERR_NOTFOUND; +		} +	} + +	stm32mp1_mco_csg(priv, clksrc[CLKSRC_MCO1], clkdiv[CLKDIV_MCO1]); +	stm32mp1_mco_csg(priv, clksrc[CLKSRC_MCO2], clkdiv[CLKDIV_MCO2]); + +	/* +	 * Switch ON oscillator found in device-tree. +	 * Note: HSI already ON after BootROM stage. +	 */ +	if (priv->osc[_LSI] != 0U) { +		stm32mp1_lsi_set(rcc, 1); +	} +	if (priv->osc[_LSE] != 0U) { +		bool bypass; +		uint32_t lsedrv; + +		bypass = fdt_osc_read_bool(_LSE, "st,bypass"); +		lse_css = fdt_osc_read_bool(_LSE, "st,css"); +		lsedrv = fdt_osc_read_uint32_default(_LSE, "st,drive", +						     LSEDRV_MEDIUM_HIGH); +		stm32mp1_lse_enable(rcc, bypass, lsedrv); +	} +	if (priv->osc[_HSE] != 0U) { +		bool bypass, css; + +		bypass = fdt_osc_read_bool(_LSE, "st,bypass"); +		css = fdt_osc_read_bool(_LSE, "st,css"); +		stm32mp1_hse_enable(rcc, bypass, css); +	} +	/* +	 * CSI is mandatory for automatic I/O compensation (SYSCFG_CMPCR) +	 * => switch on CSI even if node is not present in device tree +	 */ +	stm32mp1_csi_set(rcc, 1); + +	/* Come back to HSI */ +	ret = stm32mp1_set_clksrc(priv, CLK_MPU_HSI); +	if (ret != 0) { +		return ret; +	} +	ret = stm32mp1_set_clksrc(priv, CLK_AXI_HSI); +	if (ret != 0) { +		return ret; +	} + +	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { +		if (i == _PLL4) +			continue; +		ret = stm32mp1_pll_stop(priv, i); +		if (ret != 0) { +			return ret; +		} +	} + +	/* Configure HSIDIV */ +	if (priv->osc[_HSI] != 0U) { +		ret = stm32mp1_hsidiv(rcc, priv->osc[_HSI]); +		if (ret != 0) { +			return ret; +		} +		stm32mp1_stgen_config(priv); +	} + +	/* Select DIV */ +	/* No ready bit when MPUSRC != CLK_MPU_PLL1P_DIV, MPUDIV is disabled */ +	mmio_write_32(rcc + RCC_MPCKDIVR, +		      clkdiv[CLKDIV_MPU] & RCC_DIVR_DIV_MASK); +	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_AXI], rcc + RCC_AXIDIVR); +	if (ret != 0) { +		return ret; +	} +	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB4], rcc + RCC_APB4DIVR); +	if (ret != 0) { +		return ret; +	} +	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB5], rcc + RCC_APB5DIVR); +	if (ret != 0) { +		return ret; +	} +	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB1], rcc + RCC_APB1DIVR); +	if (ret != 0) { +		return ret; +	} +	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB2], rcc + RCC_APB2DIVR); +	if (ret != 0) { +		return ret; +	} +	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB3], rcc + RCC_APB3DIVR); +	if (ret != 0) { +		return ret; +	} + +	/* No ready bit for RTC */ +	mmio_write_32(rcc + RCC_RTCDIVR, +		      clkdiv[CLKDIV_RTC] & RCC_DIVR_DIV_MASK); + +	/* Configure PLLs source */ +	ret = stm32mp1_set_clksrc(priv, clksrc[CLKSRC_PLL12]); +	if (ret != 0) { +		return ret; +	} +	ret = stm32mp1_set_clksrc(priv, clksrc[CLKSRC_PLL3]); +	if (ret != 0) { +		return ret; +	} + +	ret = stm32mp1_set_clksrc(priv, clksrc[CLKSRC_PLL4]); +	if (ret != 0) { +		return ret; +	} + +	/* Configure and start PLLs */ +	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { +		uint32_t fracv; +		uint32_t csg[PLLCSG_NB]; + +		if (!fdt_check_node(plloff[i])) { +			continue; +		} + +		fracv = fdt_read_uint32_default(plloff[i], "frac", 0); + +		ret = stm32mp1_pll_config(priv, i, pllcfg[i], fracv); +		if (ret != 0) { +			return ret; +		} +		ret = fdt_read_uint32_array(plloff[i], "csg", csg, +					    (uint32_t)PLLCSG_NB); +		if (ret == 0) { +			stm32mp1_pll_csg(priv, i, csg); +		} else if (ret != -FDT_ERR_NOTFOUND) { +			return ret; +		} + +		stm32mp1_pll_start(priv, i); +	} +	/* Wait and start PLLs ouptut when ready */ +	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { +		if (!fdt_check_node(plloff[i])) { +			continue; +		} + +		ret = stm32mp1_pll_output(priv, i, pllcfg[i][PLLCFG_O]); +		if (ret != 0) { +			return ret; +		} +	} +	/* Wait LSE ready before to use it */ +	if (priv->osc[_LSE] != 0U) { +		stm32mp1_lse_wait(rcc); +	} + +	/* Configure with expected clock source */ +	ret = stm32mp1_set_clksrc(priv, clksrc[CLKSRC_MPU]); +	if (ret != 0) { +		return ret; +	} +	ret = stm32mp1_set_clksrc(priv, clksrc[CLKSRC_AXI]); +	if (ret != 0) { +		return ret; +	} +	stm32mp1_set_rtcsrc(priv, clksrc[CLKSRC_RTC], lse_css); + +	/* Configure PKCK */ +	pkcs_cell = fdt_rcc_read_prop("st,pkcs", &len); +	if (pkcs_cell != NULL) { +		bool ckper_disabled = false; +		uint32_t j; + +		priv->pkcs_usb_value = 0; + +		for (j = 0; j < ((uint32_t)len / sizeof(uint32_t)); j++) { +			uint32_t pkcs = (uint32_t)fdt32_to_cpu(pkcs_cell[j]); + +			if (pkcs == (uint32_t)CLK_CKPER_DISABLED) { +				ckper_disabled = true; +				continue; +			} +			stm32mp1_pkcs_config(priv, pkcs); +		} + +		/* +		 * CKPER is source for some peripheral clocks +		 * (FMC-NAND / QPSI-NOR) and switching source is allowed +		 * only if previous clock is still ON +		 * => deactivated CKPER only after switching clock +		 */ +		if (ckper_disabled) { +			stm32mp1_pkcs_config(priv, CLK_CKPER_DISABLED); +		} +	} + +	/* Switch OFF HSI if not found in device-tree */ +	if (priv->osc[_HSI] == 0U) { +		stm32mp1_hsi_set(rcc, 0); +	} +	stm32mp1_stgen_config(priv); + +	/* Software Self-Refresh mode (SSR) during DDR initilialization */ +	mmio_clrsetbits_32(priv->base + RCC_DDRITFCR, +			   RCC_DDRITFCR_DDRCKMOD_MASK, +			   RCC_DDRITFCR_DDRCKMOD_SSR << +			   RCC_DDRITFCR_DDRCKMOD_SHIFT); + +	return 0; +} + +static void stm32mp1_osc_clk_init(const char *name, +				  struct stm32mp1_clk_priv *priv, +				  enum stm32mp_osc_id index) +{ +	uint32_t frequency; + +	priv->osc[index] = 0; + +	if (fdt_osc_read_freq(name, &frequency) != 0) { +		ERROR("%s frequency request failed\n", name); +		panic(); +	} else { +		priv->osc[index] = frequency; +	} +} + +static void stm32mp1_osc_init(void) +{ +	struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data; +	enum stm32mp_osc_id i; + +	for (i = (enum stm32mp_osc_id)0 ; i < NB_OSC; i++) { +		stm32mp1_osc_clk_init(stm32mp_osc_node_label[i], priv, i); +	} +} + +int stm32mp1_clk_probe(void) +{ +	struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data; + +	priv->base = fdt_rcc_read_addr(); +	if (priv->base == 0U) { +		return -EINVAL; +	} + +	priv->data = &stm32mp1_data; + +	if ((priv->data->gate == NULL) || (priv->data->sel == NULL) || +	    (priv->data->pll == NULL)) { +		return -EINVAL; +	} + +	stm32mp1_osc_init(); + +	return 0; +} diff --git a/drivers/st/clk/stm32mp1_clkfunc.c b/drivers/st/clk/stm32mp1_clkfunc.c new file mode 100644 index 00000000..d4c69cb4 --- /dev/null +++ b/drivers/st/clk/stm32mp1_clkfunc.c @@ -0,0 +1,365 @@ +/* + * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <dt-bindings/clock/stm32mp1-clksrc.h> +#include <errno.h> +#include <libfdt.h> +#include <stm32mp1_clk.h> +#include <stm32mp1_clkfunc.h> +#include <stm32mp1_dt.h> + +#define DT_RCC_NODE_NAME	"rcc@50000000" +#define DT_RCC_CLK_COMPAT	"st,stm32mp1-rcc" +#define DT_RCC_COMPAT		"syscon" +#define DT_STGEN_COMPAT		"st,stm32-stgen" +#define DT_UART_COMPAT		"st,stm32h7-uart" +#define DT_USART_COMPAT		"st,stm32h7-usart" + +const char *stm32mp_osc_node_label[NB_OSC] = { +	[_LSI] = "clk-lsi", +	[_LSE] = "clk-lse", +	[_HSI] = "clk-hsi", +	[_HSE] = "clk-hse", +	[_CSI] = "clk-csi", +	[_I2S_CKIN] = "i2s_ckin", +	[_USB_PHY_48] = "ck_usbo_48m" +}; + +/******************************************************************************* + * This function reads the frequency of an oscillator from its name. + * It reads the value indicated inside the device tree. + * Returns 0 if success, and a negative value else. + * If success, value is stored in the second parameter. + ******************************************************************************/ +int fdt_osc_read_freq(const char *name, uint32_t *freq) +{ +	int node, subnode; +	void *fdt; + +	if (fdt_get_address(&fdt) == 0) { +		return -ENOENT; +	} + +	node = fdt_path_offset(fdt, "/clocks"); +	if (node < 0) { +		return -FDT_ERR_NOTFOUND; +	} + +	fdt_for_each_subnode(subnode, fdt, node) { +		const char *cchar; +		int ret; + +		cchar = fdt_get_name(fdt, subnode, &ret); +		if (cchar == NULL) { +			return ret; +		} + +		if (strncmp(cchar, name, (size_t)ret) == 0) { +			const fdt32_t *cuint; + +			cuint = fdt_getprop(fdt, subnode, "clock-frequency", +					    &ret); +			if (cuint == NULL) { +				return ret; +			} + +			*freq = fdt32_to_cpu(*cuint); + +			return 0; +		} +	} + +	/* Oscillator not found, freq=0 */ +	*freq = 0; +	return 0; +} + +/******************************************************************************* + * This function checks the presence of an oscillator property from its id. + * The search is done inside the device tree. + * Returns true/false regarding search result. + ******************************************************************************/ +bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name) +{ +	int node, subnode; +	void *fdt; + +	if (fdt_get_address(&fdt) == 0) { +		return false; +	} + +	if (osc_id >= NB_OSC) { +		return false; +	} + +	node = fdt_path_offset(fdt, "/clocks"); +	if (node < 0) { +		return false; +	} + +	fdt_for_each_subnode(subnode, fdt, node) { +		const char *cchar; +		int ret; + +		cchar = fdt_get_name(fdt, subnode, &ret); +		if (cchar == NULL) { +			return false; +		} + +		if (strncmp(cchar, stm32mp_osc_node_label[osc_id], +			    (size_t)ret) != 0) { +			continue; +		} + +		if (fdt_getprop(fdt, subnode, prop_name, NULL) != NULL) { +			return true; +		} +	} + +	return false; +} + +/******************************************************************************* + * This function reads a value of a oscillator property from its id. + * Returns value if success, and a default value if property not found. + * Default value is passed as parameter. + ******************************************************************************/ +uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id, +				     const char *prop_name, uint32_t dflt_value) +{ +	int node, subnode; +	void *fdt; + +	if (fdt_get_address(&fdt) == 0) { +		return dflt_value; +	} + +	if (osc_id >= NB_OSC) { +		return dflt_value; +	} + +	node = fdt_path_offset(fdt, "/clocks"); +	if (node < 0) { +		return dflt_value; +	} + +	fdt_for_each_subnode(subnode, fdt, node) { +		const char *cchar; +		int ret; + +		cchar = fdt_get_name(fdt, subnode, &ret); +		if (cchar == NULL) { +			return dflt_value; +		} + +		if (strncmp(cchar, stm32mp_osc_node_label[osc_id], +			    (size_t)ret) != 0) { +			continue; +		} + +		return fdt_read_uint32_default(subnode, prop_name, dflt_value); +	} + +	return dflt_value; +} + +/******************************************************************************* + * This function reads the rcc base address. + * It reads the value indicated inside the device tree. + * Returns address if success, and 0 value else. + ******************************************************************************/ +uint32_t fdt_rcc_read_addr(void) +{ +	int node, subnode; +	void *fdt; + +	if (fdt_get_address(&fdt) == 0) { +		return 0; +	} + +	node = fdt_path_offset(fdt, "/soc"); +	if (node < 0) { +		return 0; +	} + +	fdt_for_each_subnode(subnode, fdt, node) { +		const char *cchar; +		int ret; + +		cchar = fdt_get_name(fdt, subnode, &ret); +		if (cchar == NULL) { +			return 0; +		} + +		if (strncmp(cchar, DT_RCC_NODE_NAME, (size_t)ret) == 0) { +			const fdt32_t *cuint; + +			cuint = fdt_getprop(fdt, subnode, "reg", NULL); +			if (cuint == NULL) { +				return 0; +			} + +			return fdt32_to_cpu(*cuint); +		} +	} + +	return 0; +} + +/******************************************************************************* + * This function reads a series of parameters in rcc-clk section. + * It reads the values indicated inside the device tree, from property name. + * The number of parameters is also indicated as entry parameter. + * Returns 0 if success, and a negative value else. + * If success, values are stored at the second parameter address. + ******************************************************************************/ +int fdt_rcc_read_uint32_array(const char *prop_name, +			      uint32_t *array, uint32_t count) +{ +	int node; +	void *fdt; + +	if (fdt_get_address(&fdt) == 0) { +		return -ENOENT; +	} + +	node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT); +	if (node < 0) { +		return -FDT_ERR_NOTFOUND; +	} + +	return fdt_read_uint32_array(node, prop_name, array, count); +} + +/******************************************************************************* + * This function gets the subnode offset in rcc-clk section from its name. + * It reads the values indicated inside the device tree. + * Returns offset if success, and a negative value else. + ******************************************************************************/ +int fdt_rcc_subnode_offset(const char *name) +{ +	int node, subnode; +	void *fdt; + +	if (fdt_get_address(&fdt) == 0) { +		return -ENOENT; +	} + +	node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT); +	if (node < 0) { +		return -FDT_ERR_NOTFOUND; +	} + +	subnode = fdt_subnode_offset(fdt, node, name); +	if (subnode <= 0) { +		return -FDT_ERR_NOTFOUND; +	} + +	return subnode; +} + +/******************************************************************************* + * This function gets the pointer to a rcc-clk property from its name. + * It reads the values indicated inside the device tree. + * Length of the property is stored in the second parameter. + * Returns pointer if success, and NULL value else. + ******************************************************************************/ +const uint32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp) +{ +	const uint32_t *cuint; +	int node, len; +	void *fdt; + +	if (fdt_get_address(&fdt) == 0) { +		return NULL; +	} + +	node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT); +	if (node < 0) { +		return NULL; +	} + +	cuint = fdt_getprop(fdt, node, prop_name, &len); +	if (cuint == NULL) { +		return NULL; +	} + +	*lenp = len; +	return cuint; +} + +/******************************************************************************* + * This function gets the secure status for rcc node. + * It reads secure-status in device tree. + * Returns 1 if rcc is available from secure world, 0 else. + ******************************************************************************/ +bool fdt_get_rcc_secure_status(void) +{ +	int node; +	void *fdt; + +	if (fdt_get_address(&fdt) == 0) { +		return false; +	} + +	node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_COMPAT); +	if (node < 0) { +		return false; +	} + +	return fdt_check_secure_status(node); +} + +/******************************************************************************* + * This function reads the stgen base address. + * It reads the value indicated inside the device tree. + * Returns address if success, and NULL value else. + ******************************************************************************/ +uintptr_t fdt_get_stgen_base(void) +{ +	int node; +	const fdt32_t *cuint; +	void *fdt; + +	if (fdt_get_address(&fdt) == 0) { +		return 0; +	} + +	node = fdt_node_offset_by_compatible(fdt, -1, DT_STGEN_COMPAT); +	if (node < 0) { +		return 0; +	} + +	cuint = fdt_getprop(fdt, node, "reg", NULL); +	if (cuint == NULL) { +		return 0; +	} + +	return fdt32_to_cpu(*cuint); +} + +/******************************************************************************* + * This function gets the clock ID of the given node. + * It reads the value indicated inside the device tree. + * Returns ID if success, and a negative value else. + ******************************************************************************/ +int fdt_get_clock_id(int node) +{ +	const fdt32_t *cuint; +	void *fdt; + +	if (fdt_get_address(&fdt) == 0) { +		return -ENOENT; +	} + +	cuint = fdt_getprop(fdt, node, "clocks", NULL); +	if (cuint == NULL) { +		return -FDT_ERR_NOTFOUND; +	} + +	cuint++; +	return (int)fdt32_to_cpu(*cuint); +} diff --git a/drivers/st/ddr/stm32mp1_ddr.c b/drivers/st/ddr/stm32mp1_ddr.c new file mode 100644 index 00000000..eed1d761 --- /dev/null +++ b/drivers/st/ddr/stm32mp1_ddr.c @@ -0,0 +1,895 @@ +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause + */ + +#include <arch.h> +#include <arch_helpers.h> +#include <debug.h> +#include <delay_timer.h> +#include <dt-bindings/clock/stm32mp1-clks.h> +#include <mmio.h> +#include <platform.h> +#include <stddef.h> +#include <stm32mp1_clk.h> +#include <stm32mp1_ddr.h> +#include <stm32mp1_ddr_regs.h> +#include <stm32mp1_dt.h> +#include <stm32mp1_pmic.h> +#include <stm32mp1_pwr.h> +#include <stm32mp1_ram.h> +#include <stm32mp1_rcc.h> + +struct reg_desc { +	const char *name; +	uint16_t offset;	/* Offset for base address */ +	uint8_t par_offset;	/* Offset for parameter array */ +}; + +#define INVALID_OFFSET	0xFFU + +#define TIMESLOT_1US	(plat_get_syscnt_freq2() / 1000000U) + +#define DDRCTL_REG(x, y)					\ +	{							\ +		.name = #x,					\ +		.offset = offsetof(struct stm32mp1_ddrctl, x),	\ +		.par_offset = offsetof(struct y, x)		\ +	} + +#define DDRPHY_REG(x, y)					\ +	{							\ +		.name = #x,					\ +		.offset = offsetof(struct stm32mp1_ddrphy, x),	\ +		.par_offset = 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), +}; + +#define DDR_REG_DYN(x)						\ +	{							\ +		.name = #x,					\ +		.offset = offsetof(struct stm32mp1_ddrctl, x),	\ +		.par_offset = INVALID_OFFSET \ +	} + +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 DDRPHY_REG_DYN(x)					\ +	{							\ +		.name = #x,					\ +		.offset = offsetof(struct stm32mp1_ddrphy, x),	\ +		.par_offset = INVALID_OFFSET			\ +	} + +static const struct reg_desc ddrphy_dyn[] = { +	DDRPHY_REG_DYN(pir), +	DDRPHY_REG_DYN(pgsr), +}; + +enum reg_type { +	REG_REG, +	REG_TIMING, +	REG_PERF, +	REG_MAP, +	REGPHY_REG, +	REGPHY_TIMING, +	REGPHY_CAL, +/* + * Dynamic registers => managed in driver or not changed, + * can be dumped in interactive mode. + */ +	REG_DYN, +	REGPHY_DYN, +	REG_TYPE_NB +}; + +enum base_type { +	DDR_BASE, +	DDRPHY_BASE, +	NONE_BASE +}; + +struct ddr_reg_info { +	const char *name; +	const struct reg_desc *desc; +	uint8_t size; +	enum base_type base; +}; + +static 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 +	}, +	[REG_DYN] = { +		"dyn", ddr_dyn, ARRAY_SIZE(ddr_dyn), DDR_BASE +	}, +	[REGPHY_DYN] = { +		"dyn", ddrphy_dyn, ARRAY_SIZE(ddrphy_dyn), DDRPHY_BASE +	}, +}; + +static uint32_t get_base_addr(const struct ddr_info *priv, enum base_type base) +{ +	if (base == DDRPHY_BASE) { +		return (uint32_t)priv->phy; +	} else { +		return (uint32_t)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; +	uint32_t base_addr = get_base_addr(priv, base); +	const struct reg_desc *desc = ddr_registers[type].desc; + +	VERBOSE("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) { +			ERROR("invalid parameter offset for %s", desc[i].name); +			panic(); +		} else { +			value = *((uint32_t *)((uint32_t)param + +					       desc[i].par_offset)); +			mmio_write_32((uint32_t)ptr, value); +		} +	} +} + +static void stm32mp1_ddrphy_idone_wait(struct stm32mp1_ddrphy *phy) +{ +	uint32_t pgsr; +	int error = 0; +	unsigned long start; +	unsigned long time0, time; + +	start = get_timer(0); +	time0 = start; + +	do { +		pgsr = mmio_read_32((uint32_t)&phy->pgsr); +		time = get_timer(start); +		if (time != time0) { +			VERBOSE("  > [0x%x] pgsr = 0x%x &\n", +				(uint32_t)&phy->pgsr, pgsr); +			VERBOSE("    [0x%x] pir = 0x%x (time=%x)\n", +				(uint32_t)&phy->pir, +				mmio_read_32((uint32_t)&phy->pir), +				(uint32_t)time); +		} + +		time0 = time; +		if (time > plat_get_syscnt_freq2()) { +			panic(); +		} +		if ((pgsr & DDRPHYC_PGSR_DTERR) != 0U) { +			VERBOSE("DQS Gate Trainig Error\n"); +			error++; +		} +		if ((pgsr & DDRPHYC_PGSR_DTIERR) != 0U) { +			VERBOSE("DQS Gate Trainig Intermittent Error\n"); +			error++; +		} +		if ((pgsr & DDRPHYC_PGSR_DFTERR) != 0U) { +			VERBOSE("DQS Drift Error\n"); +			error++; +		} +		if ((pgsr & DDRPHYC_PGSR_RVERR) != 0U) { +			VERBOSE("Read Valid Training Error\n"); +			error++; +		} +		if ((pgsr & DDRPHYC_PGSR_RVEIRR) != 0U) { +			VERBOSE("Read Valid Training Intermittent Error\n"); +			error++; +		} +	} while ((pgsr & DDRPHYC_PGSR_IDONE) == 0U && error == 0); +	VERBOSE("\n[0x%x] pgsr = 0x%x\n", +		(uint32_t)&phy->pgsr, pgsr); +} + +static void stm32mp1_ddrphy_init(struct stm32mp1_ddrphy *phy, uint32_t pir) +{ +	uint32_t pir_init = pir | DDRPHYC_PIR_INIT; + +	mmio_write_32((uint32_t)&phy->pir, pir_init); +	VERBOSE("[0x%x] pir = 0x%x -> 0x%x\n", +		(uint32_t)&phy->pir, pir_init, +		mmio_read_32((uint32_t)&phy->pir)); + +	/* Need to wait 10 configuration clock before start polling */ +	udelay(10); + +	/* Wait DRAM initialization and Gate Training Evaluation complete */ +	stm32mp1_ddrphy_idone_wait(phy); +} + +/* Start quasi dynamic register update */ +static void stm32mp1_start_sw_done(struct stm32mp1_ddrctl *ctl) +{ +	mmio_clrbits_32((uint32_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE); +	VERBOSE("[0x%x] swctl = 0x%x\n", +		(uint32_t)&ctl->swctl,  mmio_read_32((uint32_t)&ctl->swctl)); +} + +/* Wait quasi dynamic register update */ +static void stm32mp1_wait_sw_done_ack(struct stm32mp1_ddrctl *ctl) +{ +	unsigned long start; +	uint32_t swstat; + +	mmio_setbits_32((uint32_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE); +	VERBOSE("[0x%x] swctl = 0x%x\n", +		(uint32_t)&ctl->swctl, mmio_read_32((uint32_t)&ctl->swctl)); + +	start = get_timer(0); +	do { +		swstat = mmio_read_32((uint32_t)&ctl->swstat); +		VERBOSE("[0x%x] swstat = 0x%x ", +			(uint32_t)&ctl->swstat, swstat); +		VERBOSE("timer in ms 0x%x = start 0x%lx\r", +			get_timer(0), start); +		if (get_timer(start) > plat_get_syscnt_freq2()) { +			panic(); +		} +	} while ((swstat & DDRCTRL_SWSTAT_SW_DONE_ACK) == 0U); + +	VERBOSE("[0x%x] swstat = 0x%x\n", +		(uint32_t)&ctl->swstat, swstat); +} + +/* Wait quasi dynamic register update */ +static void stm32mp1_wait_operating_mode(struct ddr_info *priv, uint32_t mode) +{ +	unsigned long start; +	uint32_t stat; +	uint32_t operating_mode; +	uint32_t selref_type; +	int break_loop = 0; + +	start = get_timer(0); +	for ( ; ; ) { +		stat = mmio_read_32((uint32_t)&priv->ctl->stat); +		operating_mode = stat & DDRCTRL_STAT_OPERATING_MODE_MASK; +		selref_type = stat & DDRCTRL_STAT_SELFREF_TYPE_MASK; +		VERBOSE("[0x%x] stat = 0x%x\n", +			(uint32_t)&priv->ctl->stat, stat); +		VERBOSE("timer in ms 0x%x = start 0x%lx\r", +			get_timer(0), start); +		if (get_timer(start) > plat_get_syscnt_freq2()) { +			panic(); +		} + +		if (mode == DDRCTRL_STAT_OPERATING_MODE_SR) { +			/* +			 * Self-refresh due to software +			 * => checking also STAT.selfref_type. +			 */ +			if ((operating_mode == +			     DDRCTRL_STAT_OPERATING_MODE_SR) && +			    (selref_type == DDRCTRL_STAT_SELFREF_TYPE_SR)) { +				break_loop = 1; +			} +		} else if (operating_mode == mode) { +			break_loop = 1; +		} else if ((mode == DDRCTRL_STAT_OPERATING_MODE_NORMAL) && +			   (operating_mode == DDRCTRL_STAT_OPERATING_MODE_SR) && +			   (selref_type == DDRCTRL_STAT_SELFREF_TYPE_ASR)) { +			/* Normal mode: handle also automatic self refresh */ +			break_loop = 1; +		} + +		if (break_loop == 1) { +			break; +		} +	} + +	VERBOSE("[0x%x] stat = 0x%x\n", +		(uint32_t)&priv->ctl->stat, stat); +} + +/* Mode Register Writes (MRW or MRS) */ +static void stm32mp1_mode_register_write(struct ddr_info *priv, uint8_t addr, +					 uint32_t data) +{ +	uint32_t mrctrl0; + +	VERBOSE("MRS: %d = %x\n", addr, data); + +	/* +	 * 1. Poll MRSTAT.mr_wr_busy until it is '0'. +	 *    This checks that there is no outstanding MR transaction. +	 *    No write should be performed to MRCTRL0 and MRCTRL1 +	 *    if MRSTAT.mr_wr_busy = 1. +	 */ +	while ((mmio_read_32((uint32_t)&priv->ctl->mrstat) & +		DDRCTRL_MRSTAT_MR_WR_BUSY) != 0U) { +		; +	} + +	/* +	 * 2. Write the MRCTRL0.mr_type, MRCTRL0.mr_addr, MRCTRL0.mr_rank +	 *    and (for MRWs) MRCTRL1.mr_data to define the MR transaction. +	 */ +	mrctrl0 = DDRCTRL_MRCTRL0_MR_TYPE_WRITE | +		  DDRCTRL_MRCTRL0_MR_RANK_ALL | +		  (((uint32_t)addr << DDRCTRL_MRCTRL0_MR_ADDR_SHIFT) & +		   DDRCTRL_MRCTRL0_MR_ADDR_MASK); +	mmio_write_32((uint32_t)&priv->ctl->mrctrl0, mrctrl0); +	VERBOSE("[0x%x] mrctrl0 = 0x%x (0x%x)\n", +		(uint32_t)&priv->ctl->mrctrl0, +		mmio_read_32((uint32_t)&priv->ctl->mrctrl0), mrctrl0); +	mmio_write_32((uint32_t)&priv->ctl->mrctrl1, data); +	VERBOSE("[0x%x] mrctrl1 = 0x%x\n", +		(uint32_t)&priv->ctl->mrctrl1, +		mmio_read_32((uint32_t)&priv->ctl->mrctrl1)); + +	/* +	 * 3. In a separate APB transaction, write the MRCTRL0.mr_wr to 1. This +	 *    bit is self-clearing, and triggers the MR transaction. +	 *    The uMCTL2 then asserts the MRSTAT.mr_wr_busy while it performs +	 *    the MR transaction to SDRAM, and no further access can be +	 *    initiated until it is deasserted. +	 */ +	mrctrl0 |= DDRCTRL_MRCTRL0_MR_WR; +	mmio_write_32((uint32_t)&priv->ctl->mrctrl0, mrctrl0); + +	while ((mmio_read_32((uint32_t)&priv->ctl->mrstat) & +	       DDRCTRL_MRSTAT_MR_WR_BUSY) != 0U) { +		; +	} + +	VERBOSE("[0x%x] mrctrl0 = 0x%x\n", +		(uint32_t)&priv->ctl->mrctrl0, mrctrl0); +} + +/* Switch DDR3 from DLL-on to DLL-off */ +static void stm32mp1_ddr3_dll_off(struct ddr_info *priv) +{ +	uint32_t mr1 = mmio_read_32((uint32_t)&priv->phy->mr1); +	uint32_t mr2 = mmio_read_32((uint32_t)&priv->phy->mr2); +	uint32_t dbgcam; + +	VERBOSE("mr1: 0x%x\n", mr1); +	VERBOSE("mr2: 0x%x\n", mr2); + +	/* +	 * 1. Set the DBG1.dis_hif = 1. +	 *    This prevents further reads/writes being received on the HIF. +	 */ +	mmio_setbits_32((uint32_t)&priv->ctl->dbg1, DDRCTRL_DBG1_DIS_HIF); +	VERBOSE("[0x%x] dbg1 = 0x%x\n", +		(uint32_t)&priv->ctl->dbg1, +		mmio_read_32((uint32_t)&priv->ctl->dbg1)); + +	/* +	 * 2. Ensure all commands have been flushed from the uMCTL2 by polling +	 *    DBGCAM.wr_data_pipeline_empty = 1, +	 *    DBGCAM.rd_data_pipeline_empty = 1, +	 *    DBGCAM.dbg_wr_q_depth = 0 , +	 *    DBGCAM.dbg_lpr_q_depth = 0, and +	 *    DBGCAM.dbg_hpr_q_depth = 0. +	 */ +	do { +		dbgcam = mmio_read_32((uint32_t)&priv->ctl->dbgcam); +		VERBOSE("[0x%x] dbgcam = 0x%x\n", +			(uint32_t)&priv->ctl->dbgcam, dbgcam); +	} while ((((dbgcam & DDRCTRL_DBGCAM_DATA_PIPELINE_EMPTY) == +		   DDRCTRL_DBGCAM_DATA_PIPELINE_EMPTY)) && +		 ((dbgcam & DDRCTRL_DBGCAM_DBG_Q_DEPTH) == 0U)); + +	/* +	 * 3. Perform an MRS command (using MRCTRL0 and MRCTRL1 registers) +	 *    to disable RTT_NOM: +	 *    a. DDR3: Write to MR1[9], MR1[6] and MR1[2] +	 *    b. DDR4: Write to MR1[10:8] +	 */ +	mr1 &= ~(BIT(9) | BIT(6) | BIT(2)); +	stm32mp1_mode_register_write(priv, 1, mr1); + +	/* +	 * 4. For DDR4 only: Perform an MRS command +	 *    (using MRCTRL0 and MRCTRL1 registers) to write to MR5[8:6] +	 *    to disable RTT_PARK +	 */ + +	/* +	 * 5. Perform an MRS command (using MRCTRL0 and MRCTRL1 registers) +	 *    to write to MR2[10:9], to disable RTT_WR +	 *    (and therefore disable dynamic ODT). +	 *    This applies for both DDR3 and DDR4. +	 */ +	mr2 &= ~GENMASK(10, 9); +	stm32mp1_mode_register_write(priv, 2, mr2); + +	/* +	 * 6. Perform an MRS command (using MRCTRL0 and MRCTRL1 registers) +	 *    to disable the DLL. The timing of this MRS is automatically +	 *    handled by the uMCTL2. +	 *    a. DDR3: Write to MR1[0] +	 *    b. DDR4: Write to MR1[0] +	 */ +	mr1 |= BIT(0); +	stm32mp1_mode_register_write(priv, 1, mr1); + +	/* +	 * 7. Put the SDRAM into self-refresh mode by setting +	 *    PWRCTL.selfref_sw = 1, and polling STAT.operating_mode to ensure +	 *    the DDRC has entered self-refresh. +	 */ +	mmio_setbits_32((uint32_t)&priv->ctl->pwrctl, +			DDRCTRL_PWRCTL_SELFREF_SW); +	VERBOSE("[0x%x] pwrctl = 0x%x\n", +		(uint32_t)&priv->ctl->pwrctl, +		mmio_read_32((uint32_t)&priv->ctl->pwrctl)); + +	/* +	 * 8. Wait until STAT.operating_mode[1:0]==11 indicating that the +	 *    DWC_ddr_umctl2 core is in self-refresh mode. +	 *    Ensure transition to self-refresh was due to software +	 *    by checking that STAT.selfref_type[1:0]=2. +	 */ +	stm32mp1_wait_operating_mode(priv, DDRCTRL_STAT_OPERATING_MODE_SR); + +	/* +	 * 9. Set the MSTR.dll_off_mode = 1. +	 *    warning: MSTR.dll_off_mode is a quasi-dynamic type 2 field +	 */ +	stm32mp1_start_sw_done(priv->ctl); + +	mmio_setbits_32((uint32_t)&priv->ctl->mstr, DDRCTRL_MSTR_DLL_OFF_MODE); +	VERBOSE("[0x%x] mstr = 0x%x\n", +		(uint32_t)&priv->ctl->mstr, +		mmio_read_32((uint32_t)&priv->ctl->mstr)); + +	stm32mp1_wait_sw_done_ack(priv->ctl); + +	/* 10. Change the clock frequency to the desired value. */ + +	/* +	 * 11. Update any registers which may be required to change for the new +	 *     frequency. This includes static and dynamic registers. +	 *     This includes both uMCTL2 registers and PHY registers. +	 */ + +	/* Change Bypass Mode Frequency Range */ +	if (stm32mp1_clk_get_rate(DDRPHYC) < 100000000U) { +		mmio_clrbits_32((uint32_t)&priv->phy->dllgcr, +				DDRPHYC_DLLGCR_BPS200); +	} else { +		mmio_setbits_32((uint32_t)&priv->phy->dllgcr, +				DDRPHYC_DLLGCR_BPS200); +	} + +	mmio_setbits_32((uint32_t)&priv->phy->acdllcr, DDRPHYC_ACDLLCR_DLLDIS); + +	mmio_setbits_32((uint32_t)&priv->phy->dx0dllcr, +			DDRPHYC_DXNDLLCR_DLLDIS); +	mmio_setbits_32((uint32_t)&priv->phy->dx1dllcr, +			DDRPHYC_DXNDLLCR_DLLDIS); +	mmio_setbits_32((uint32_t)&priv->phy->dx2dllcr, +			DDRPHYC_DXNDLLCR_DLLDIS); +	mmio_setbits_32((uint32_t)&priv->phy->dx3dllcr, +			DDRPHYC_DXNDLLCR_DLLDIS); + +	/* 12. Exit the self-refresh state by setting PWRCTL.selfref_sw = 0. */ +	mmio_clrbits_32((uint32_t)&priv->ctl->pwrctl, +			DDRCTRL_PWRCTL_SELFREF_SW); +	stm32mp1_wait_operating_mode(priv, DDRCTRL_STAT_OPERATING_MODE_NORMAL); + +	/* +	 * 13. If ZQCTL0.dis_srx_zqcl = 0, the uMCTL2 performs a ZQCL command +	 *     at this point. +	 */ + +	/* +	 * 14. Perform MRS commands as required to re-program timing registers +	 *     in the SDRAM for the new frequency +	 *     (in particular, CL, CWL and WR may need to be changed). +	 */ + +	/* 15. Write DBG1.dis_hif = 0 to re-enable reads and writes. */ +	mmio_clrbits_32((uint32_t)&priv->ctl->dbg1, DDRCTRL_DBG1_DIS_HIF); +	VERBOSE("[0x%x] dbg1 = 0x%x\n", +		(uint32_t)&priv->ctl->dbg1, +		mmio_read_32((uint32_t)&priv->ctl->dbg1)); +} + +static void stm32mp1_refresh_disable(struct stm32mp1_ddrctl *ctl) +{ +	stm32mp1_start_sw_done(ctl); +	/* Quasi-dynamic register update*/ +	mmio_setbits_32((uint32_t)&ctl->rfshctl3, +			DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH); +	mmio_clrbits_32((uint32_t)&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN); +	mmio_clrbits_32((uint32_t)&ctl->dfimisc, +			DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); +	stm32mp1_wait_sw_done_ack(ctl); +} + +static void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl, +				     uint32_t rfshctl3, uint32_t pwrctl) +{ +	stm32mp1_start_sw_done(ctl); +	if ((rfshctl3 & DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH) == 0U) { +		mmio_clrbits_32((uint32_t)&ctl->rfshctl3, +				DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH); +	} +	if ((pwrctl & DDRCTRL_PWRCTL_POWERDOWN_EN) != 0U) { +		mmio_setbits_32((uint32_t)&ctl->pwrctl, +				DDRCTRL_PWRCTL_POWERDOWN_EN); +	} +	mmio_setbits_32((uint32_t)&ctl->dfimisc, +			DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); +	stm32mp1_wait_sw_done_ack(ctl); +} + +static int board_ddr_power_init(enum ddr_type ddr_type) +{ +	if (dt_check_pmic()) { +		return pmic_ddr_power_init(ddr_type); +	} + +	return 0; +} + +void stm32mp1_ddr_init(struct ddr_info *priv, +		       struct stm32mp1_ddr_config *config) +{ +	uint32_t pir; +	int ret; + +	if ((config->c_reg.mstr & DDRCTRL_MSTR_DDR3) != 0U) { +		ret = board_ddr_power_init(STM32MP_DDR3); +	} else { +		ret = board_ddr_power_init(STM32MP_LPDDR2); +	} + +	if (ret != 0) { +		panic(); +	} + +	VERBOSE("name = %s\n", config->info.name); +	VERBOSE("speed = %d MHz\n", config->info.speed); +	VERBOSE("size  = 0x%x\n", config->info.size); + +	/* DDR INIT SEQUENCE */ + +	/* +	 * 1. Program the DWC_ddr_umctl2 registers +	 *     nota: check DFIMISC.dfi_init_complete = 0 +	 */ + +	/* 1.1 RESETS: presetn, core_ddrc_rstn, aresetn */ +	mmio_setbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAPBRST); +	mmio_setbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAXIRST); +	mmio_setbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCORERST); +	mmio_setbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYAPBRST); +	mmio_setbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYRST); +	mmio_setbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYCTLRST); + +	/* 1.2. start CLOCK */ +	if (stm32mp1_ddr_clk_enable(priv, config->info.speed) != 0) { +		panic(); +	} + +	/* 1.3. deassert reset */ +	/* De-assert PHY rstn and ctl_rstn via DPHYRST and DPHYCTLRST. */ +	mmio_clrbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYRST); +	mmio_clrbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYCTLRST); +	/* +	 * De-assert presetn once the clocks are active +	 * and stable via DDRCAPBRST bit. +	 */ +	mmio_clrbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAPBRST); + +	/* 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 */ + +	/* 1.5. initialize registers ddr_umctl2 */ +	/* Stop uMCTL2 before PHY is ready */ +	mmio_clrbits_32((uint32_t)&priv->ctl->dfimisc, +			DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); +	VERBOSE("[0x%x] dfimisc = 0x%x\n", +		(uint32_t)&priv->ctl->dfimisc, +		mmio_read_32((uint32_t)&priv->ctl->dfimisc)); + +	set_reg(priv, REG_REG, &config->c_reg); + +	/* DDR3 = don't set DLLOFF for init mode */ +	if ((config->c_reg.mstr & +	     (DDRCTRL_MSTR_DDR3 | DDRCTRL_MSTR_DLL_OFF_MODE)) +	    == (DDRCTRL_MSTR_DDR3 | DDRCTRL_MSTR_DLL_OFF_MODE)) { +		VERBOSE("deactivate DLL OFF in mstr\n"); +		mmio_clrbits_32((uint32_t)&priv->ctl->mstr, +				DDRCTRL_MSTR_DLL_OFF_MODE); +		VERBOSE("[0x%x] mstr = 0x%x\n", +			(uint32_t)&priv->ctl->mstr, +			mmio_read_32((uint32_t)&priv->ctl->mstr)); +	} + +	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 */ +	mmio_clrsetbits_32((uint32_t)&priv->ctl->init0, +			   DDRCTRL_INIT0_SKIP_DRAM_INIT_MASK, +			   DDRCTRL_INIT0_SKIP_DRAM_INIT_NORMAL); +	VERBOSE("[0x%x] init0 = 0x%x\n", +		(uint32_t)&priv->ctl->init0, +		mmio_read_32((uint32_t)&priv->ctl->init0)); + +	set_reg(priv, REG_PERF, &config->c_perf); + +	/*  2. deassert reset signal core_ddrc_rstn, aresetn and presetn */ +	mmio_clrbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCORERST); +	mmio_clrbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAXIRST); +	mmio_clrbits_32(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); + +	/* DDR3 = don't set DLLOFF for init mode */ +	if ((config->c_reg.mstr & +	     (DDRCTRL_MSTR_DDR3 | DDRCTRL_MSTR_DLL_OFF_MODE)) +	    == (DDRCTRL_MSTR_DDR3 | DDRCTRL_MSTR_DLL_OFF_MODE)) { +		VERBOSE("deactivate DLL OFF in mr1\n"); +		mmio_clrbits_32((uint32_t)&priv->phy->mr1, BIT(0)); +		VERBOSE("[0x%x] mr1 = 0x%x\n", +			(uint32_t)&priv->phy->mr1, +			mmio_read_32((uint32_t)&priv->phy->mr1)); +	} + +	/* +	 *  4. Monitor PHY init status by polling PUBL register PGSR.IDONE +	 *     Perform DDR PHY DRAM initialization and Gate Training Evaluation +	 */ +	stm32mp1_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) != 0U) { +		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. +	 */ +	stm32mp1_start_sw_done(priv->ctl); + +	mmio_setbits_32((uint32_t)&priv->ctl->dfimisc, +			DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); +	VERBOSE("[0x%x] dfimisc = 0x%x\n", +		(uint32_t)&priv->ctl->dfimisc, +		mmio_read_32((uint32_t)&priv->ctl->dfimisc)); + +	stm32mp1_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 */ +	stm32mp1_wait_operating_mode(priv, DDRCTRL_STAT_OPERATING_MODE_NORMAL); + +	/* Switch to DLL OFF mode */ +	if ((config->c_reg.mstr & DDRCTRL_MSTR_DLL_OFF_MODE) != 0U) { +		stm32mp1_ddr3_dll_off(priv); +	} + +	VERBOSE("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 */ +	stm32mp1_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 */ +	mmio_setbits_32((uint32_t)&priv->ctl->pctrl_0, DDRCTRL_PCTRL_N_PORT_EN); +	VERBOSE("[0x%x] pctrl_0 = 0x%x\n", +		(uint32_t)&priv->ctl->pctrl_0, +		mmio_read_32((uint32_t)&priv->ctl->pctrl_0)); + +	/* Enable uMCTL2 AXI port 1 */ +	mmio_setbits_32((uint32_t)&priv->ctl->pctrl_1, DDRCTRL_PCTRL_N_PORT_EN); +	VERBOSE("[0x%x] pctrl_1 = 0x%x\n", +		(uint32_t)&priv->ctl->pctrl_1, +		mmio_read_32((uint32_t)&priv->ctl->pctrl_1)); +} diff --git a/drivers/st/ddr/stm32mp1_ddr_helpers.c b/drivers/st/ddr/stm32mp1_ddr_helpers.c new file mode 100644 index 00000000..325c0b89 --- /dev/null +++ b/drivers/st/ddr/stm32mp1_ddr_helpers.c @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <mmio.h> +#include <platform_def.h> +#include <stm32mp1_ddr_helpers.h> +#include <stm32mp1_rcc.h> + +void ddr_enable_clock(void) +{ +	mmio_setbits_32(RCC_BASE + RCC_DDRITFCR, +			RCC_DDRITFCR_DDRC1EN | +			RCC_DDRITFCR_DDRC2EN | +			RCC_DDRITFCR_DDRPHYCEN | +			RCC_DDRITFCR_DDRPHYCAPBEN | +			RCC_DDRITFCR_DDRCAPBEN); +} diff --git a/drivers/st/ddr/stm32mp1_ram.c b/drivers/st/ddr/stm32mp1_ram.c new file mode 100644 index 00000000..6d515ec7 --- /dev/null +++ b/drivers/st/ddr/stm32mp1_ram.c @@ -0,0 +1,308 @@ +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause + */ + +#include <arch_helpers.h> +#include <boot_api.h> +#include <debug.h> +#include <dt-bindings/clock/stm32mp1-clks.h> +#include <errno.h> +#include <libfdt.h> +#include <mmio.h> +#include <platform_def.h> +#include <stm32mp1_clk.h> +#include <stm32mp1_ddr.h> +#include <stm32mp1_ddr_helpers.h> +#include <stm32mp1_dt.h> +#include <stm32mp1_private.h> +#include <stm32mp1_ram.h> +#include <stm32mp1_rcc.h> + +#define DDR_PATTERN	0xAAAAAAAAU +#define DDR_ANTIPATTERN	0x55555555U + +static struct ddr_info ddr_priv_data; + +int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint16_t mem_speed) +{ +	unsigned long ddrphy_clk, ddr_clk, mem_speed_hz; + +	ddr_enable_clock(); + +	ddrphy_clk = stm32mp1_clk_get_rate(DDRPHYC); + +	VERBOSE("DDR: mem_speed (%d MHz), RCC %ld MHz\n", +		mem_speed, ddrphy_clk / 1000U / 1000U); + +	mem_speed_hz = (uint32_t)mem_speed * 1000U * 1000U; + +	/* Max 10% frequency delta */ +	if (ddrphy_clk > mem_speed_hz) { +		ddr_clk = ddrphy_clk - mem_speed_hz; +	} else { +		ddr_clk = mem_speed_hz - ddrphy_clk; +	} +	if (ddr_clk > mem_speed_hz) { +		ERROR("DDR expected freq %d MHz, current is %ld MHz\n", +		      mem_speed, ddrphy_clk / 1000U / 1000U); +		return -1; +	} +	return 0; +} + +/******************************************************************************* + * This function tests the DDR data bus wiring. + * This is inspired from the Data Bus Test algorithm written by Michael Barr + * in "Programming Embedded Systems in C and C++" book. + * resources.oreilly.com/examples/9781565923546/blob/master/Chapter6/ + * File: memtest.c - This source code belongs to Public Domain. + * Returns 0 if success, and address value else. + ******************************************************************************/ +static uint32_t ddr_test_data_bus(void) +{ +	uint32_t pattern; + +	for (pattern = 1U; pattern != 0U; pattern <<= 1) { +		mmio_write_32(STM32MP1_DDR_BASE, pattern); + +		if (mmio_read_32(STM32MP1_DDR_BASE) != pattern) { +			return (uint32_t)STM32MP1_DDR_BASE; +		} +	} + +	return 0; +} + +/******************************************************************************* + * This function tests the DDR address bus wiring. + * This is inspired from the Data Bus Test algorithm written by Michael Barr + * in "Programming Embedded Systems in C and C++" book. + * resources.oreilly.com/examples/9781565923546/blob/master/Chapter6/ + * File: memtest.c - This source code belongs to Public Domain. + * Returns 0 if success, and address value else. + ******************************************************************************/ +static uint32_t ddr_test_addr_bus(void) +{ +	uint64_t addressmask = (ddr_priv_data.info.size - 1U); +	uint64_t offset; +	uint64_t testoffset = 0; + +	/* Write the default pattern at each of the power-of-two offsets. */ +	for (offset = sizeof(uint32_t); (offset & addressmask) != 0U; +	     offset <<= 1) { +		mmio_write_32(STM32MP1_DDR_BASE + (uint32_t)offset, +			      DDR_PATTERN); +	} + +	/* Check for address bits stuck high. */ +	mmio_write_32(STM32MP1_DDR_BASE + (uint32_t)testoffset, +		      DDR_ANTIPATTERN); + +	for (offset = sizeof(uint32_t); (offset & addressmask) != 0U; +	     offset <<= 1) { +		if (mmio_read_32(STM32MP1_DDR_BASE + (uint32_t)offset) != +		    DDR_PATTERN) { +			return (uint32_t)(STM32MP1_DDR_BASE + offset); +		} +	} + +	mmio_write_32(STM32MP1_DDR_BASE + (uint32_t)testoffset, DDR_PATTERN); + +	/* Check for address bits stuck low or shorted. */ +	for (testoffset = sizeof(uint32_t); (testoffset & addressmask) != 0U; +	     testoffset <<= 1) { +		mmio_write_32(STM32MP1_DDR_BASE + (uint32_t)testoffset, +			      DDR_ANTIPATTERN); + +		if (mmio_read_32(STM32MP1_DDR_BASE) != DDR_PATTERN) { +			return STM32MP1_DDR_BASE; +		} + +		for (offset = sizeof(uint32_t); (offset & addressmask) != 0U; +		     offset <<= 1) { +			if ((mmio_read_32(STM32MP1_DDR_BASE + +					  (uint32_t)offset) != DDR_PATTERN) && +			    (offset != testoffset)) { +				return (uint32_t)(STM32MP1_DDR_BASE + offset); +			} +		} + +		mmio_write_32(STM32MP1_DDR_BASE + (uint32_t)testoffset, +			      DDR_PATTERN); +	} + +	return 0; +} + +/******************************************************************************* + * This function checks the DDR size. It has to be run with Data Cache off. + * This test is run before data have been put in DDR, and is only done for + * cold boot. The DDR data can then be overwritten, and it is not useful to + * restore its content. + * Returns DDR computed size. + ******************************************************************************/ +static uint32_t ddr_check_size(void) +{ +	uint32_t offset = sizeof(uint32_t); + +	mmio_write_32(STM32MP1_DDR_BASE, DDR_PATTERN); + +	while (offset < STM32MP1_DDR_MAX_SIZE) { +		mmio_write_32(STM32MP1_DDR_BASE + offset, DDR_ANTIPATTERN); +		dsb(); + +		if (mmio_read_32(STM32MP1_DDR_BASE) != DDR_PATTERN) { +			break; +		} + +		offset <<= 1; +	} + +	INFO("Memory size = 0x%x (%d MB)\n", offset, offset / (1024U * 1024U)); + +	return offset; +} + +static int stm32mp1_ddr_setup(void) +{ +	struct ddr_info *priv = &ddr_priv_data; +	int ret; +	struct stm32mp1_ddr_config config; +	int node, len; +	uint32_t tamp_clk_off = 0, uret, idx; +	void *fdt; + +#define PARAM(x, y)							\ +	{								\ +		.name = x,						\ +		.offset = offsetof(struct stm32mp1_ddr_config, y),	\ +		.size = sizeof(config.y) / sizeof(uint32_t)		\ +	} + +#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 uint32_t offset; /* Offset in config struct */ +		const uint32_t 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) +	}; + +	if (fdt_get_address(&fdt) == 0) { +		return -ENOENT; +	} + +	node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT); +	if (node < 0) { +		ERROR("%s: Cannot read DDR node in DT\n", __func__); +		return -EINVAL; +	} + +	config.info.speed = +		(uint16_t)fdt_read_uint32_default(node, "st,mem-speed", +						  STM32MP1_DDR_SPEED_DFLT); +	config.info.size = fdt_read_uint32_default(node, "st,mem-size", +						   STM32MP1_DDR_SIZE_DFLT); +	config.info.name = fdt_getprop(fdt, node, "st,mem-name", &len); +	if (config.info.name == NULL) { +		VERBOSE("%s: no st,mem-name\n", __func__); +		return -EINVAL; +	} +	INFO("RAM: %s\n", config.info.name); + +	for (idx = 0; idx < ARRAY_SIZE(param); idx++) { +		ret = fdt_read_uint32_array(node, param[idx].name, +					    (void *)((uint32_t)&config + +						     param[idx].offset), +					    param[idx].size); + +		VERBOSE("%s: %s[0x%x] = %d\n", __func__, +			param[idx].name, param[idx].size, ret); +		if (ret != 0) { +			ERROR("%s: Cannot read %s\n", +			      __func__, param[idx].name); +			return -EINVAL; +		} +	} + +	if (!stm32mp1_clk_is_enabled(RTCAPB)) { +		tamp_clk_off = 1; +		if (stm32mp1_clk_enable(RTCAPB) != 0) { +			return -EINVAL; +		} +	} + +	if (tamp_clk_off != 0U) { +		if (stm32mp1_clk_disable(RTCAPB) != 0) { +			return -EINVAL; +		} +	} + +	/* Disable axidcg clock gating during init */ +	mmio_clrbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_AXIDCGEN); + +	stm32mp1_ddr_init(priv, &config); + +	/* Enable axidcg clock gating */ +	mmio_setbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_AXIDCGEN); + +	priv->info.size = config.info.size; + +	VERBOSE("%s : ram size(%x, %x)\n", __func__, +		(uint32_t)priv->info.base, (uint32_t)priv->info.size); + +	dcsw_op_all(DC_OP_CISW); +	write_sctlr(read_sctlr() & ~SCTLR_C_BIT); + +	uret = ddr_test_data_bus(); +	if (uret != 0U) { +		ERROR("DDR data bus test: can't access memory @ 0x%x\n", +		      uret); +		panic(); +	} + +	uret = ddr_test_addr_bus(); +	if (uret != 0U) { +		ERROR("DDR addr bus test: can't access memory @ 0x%x\n", +		      uret); +		panic(); +	} + +	uret = ddr_check_size(); +	if (uret < config.info.size) { +		ERROR("DDR size: 0x%x does not match DT config: 0x%x\n", +		      uret, config.info.size); +		panic(); +	} + +	write_sctlr(read_sctlr() | SCTLR_C_BIT); + +	return 0; +} + +int stm32mp1_ddr_probe(void) +{ +	struct ddr_info *priv = &ddr_priv_data; + +	VERBOSE("STM32MP DDR probe\n"); + +	priv->ctl = (struct stm32mp1_ddrctl *)DDRCTRL_BASE; +	priv->phy = (struct stm32mp1_ddrphy *)DDRPHYC_BASE; +	priv->pwr = PWR_BASE; +	priv->rcc = RCC_BASE; + +	priv->info.base = STM32MP1_DDR_BASE; +	priv->info.size = 0; + +	return stm32mp1_ddr_setup(); +} diff --git a/drivers/st/gpio/stm32_gpio.c b/drivers/st/gpio/stm32_gpio.c new file mode 100644 index 00000000..200b4734 --- /dev/null +++ b/drivers/st/gpio/stm32_gpio.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <bl_common.h> +#include <debug.h> +#include <mmio.h> +#include <stdbool.h> +#include <stm32_gpio.h> + +static bool check_gpio(uint32_t bank, uint32_t pin) +{ +	if (pin > GPIO_PIN_MAX) { +		ERROR("%s: wrong pin number (%d)\n", __func__, pin); +		return false; +	} + +	if ((bank > GPIO_BANK_K) && (bank != GPIO_BANK_Z)) { +		ERROR("%s: wrong GPIO bank number (%d)\n", __func__, bank); +		return false; +	} + +	return true; +} + +void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t speed, +	      uint32_t pull, uint32_t alternate) +{ +	volatile uint32_t bank_address; + +	if (!check_gpio(bank, pin)) { +		return; +	} + +	if (bank == GPIO_BANK_Z) { +		bank_address = STM32_GPIOZ_BANK; +	} else { +		bank_address = STM32_GPIOA_BANK + +			(bank * STM32_GPIO_BANK_OFFSET); +	} + +	mmio_clrbits_32(bank_address + GPIO_MODE_OFFSET, +			((uint32_t)GPIO_MODE_MASK << (pin << 1))); +	mmio_setbits_32(bank_address + GPIO_MODE_OFFSET, +			(mode & ~GPIO_OPEN_DRAIN) << (pin << 1)); + +	if ((mode & GPIO_OPEN_DRAIN) != 0U) { +		mmio_setbits_32(bank_address + GPIO_TYPE_OFFSET, +				BIT(pin)); +	} + +	mmio_clrbits_32(bank_address + GPIO_SPEED_OFFSET, +			((uint32_t)GPIO_SPEED_MASK << (pin << 1))); +	mmio_setbits_32(bank_address + GPIO_SPEED_OFFSET, speed << (pin << 1)); + +	mmio_clrbits_32(bank_address + GPIO_PUPD_OFFSET, +			((uint32_t)GPIO_PULL_MASK << (pin << 1))); +	mmio_setbits_32(bank_address + GPIO_PUPD_OFFSET, pull << (pin << 1)); + +	if (pin < GPIO_ALT_LOWER_LIMIT) { +		mmio_clrbits_32(bank_address + GPIO_AFRL_OFFSET, +				((uint32_t)GPIO_ALTERNATE_MASK << (pin << 2))); +		mmio_setbits_32(bank_address + GPIO_AFRL_OFFSET, +				alternate << (pin << 2)); +	} else { +		mmio_clrbits_32(bank_address + GPIO_AFRH_OFFSET, +				((uint32_t)GPIO_ALTERNATE_MASK << +				 ((pin - GPIO_ALT_LOWER_LIMIT) << 2))); +		mmio_setbits_32(bank_address + GPIO_AFRH_OFFSET, +				alternate << ((pin - GPIO_ALT_LOWER_LIMIT) << +					      2)); +	} + +	VERBOSE("GPIO %u mode set to 0x%x\n", bank, +		mmio_read_32(bank_address + GPIO_MODE_OFFSET)); +	VERBOSE("GPIO %u speed set to 0x%x\n", bank, +		mmio_read_32(bank_address + GPIO_SPEED_OFFSET)); +	VERBOSE("GPIO %u mode pull to 0x%x\n", bank, +		mmio_read_32(bank_address + GPIO_PUPD_OFFSET)); +	VERBOSE("GPIO %u mode alternate low to 0x%x\n", bank, +		mmio_read_32(bank_address + GPIO_AFRL_OFFSET)); +	VERBOSE("GPIO %u mode alternate high to 0x%x\n", bank, +		mmio_read_32(bank_address + GPIO_AFRH_OFFSET)); +} diff --git a/drivers/st/pmic/stm32_i2c.c b/drivers/st/pmic/stm32_i2c.c new file mode 100644 index 00000000..09801394 --- /dev/null +++ b/drivers/st/pmic/stm32_i2c.c @@ -0,0 +1,851 @@ +/* + * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch_helpers.h> +#include <delay_timer.h> +#include <errno.h> +#include <mmio.h> +#include <stdbool.h> +#include <stdlib.h> +#include <stm32_i2c.h> + +/* STM32 I2C registers offsets */ +#define I2C_CR1			0x00U +#define I2C_CR2			0x04U +#define I2C_OAR1		0x08U +#define I2C_OAR2		0x0CU +#define I2C_TIMINGR		0x10U +#define I2C_TIMEOUTR		0x14U +#define I2C_ISR			0x18U +#define I2C_ICR			0x1CU +#define I2C_PECR		0x20U +#define I2C_RXDR		0x24U +#define I2C_TXDR		0x28U + +#define MAX_DELAY		0xFFFFFFFFU + +/* I2C TIMING clear register Mask */ +#define TIMING_CLEAR_MASK	0xF0FFFFFFU +/* Timeout 25 ms */ +#define I2C_TIMEOUT_BUSY	25U + +#define MAX_NBYTE_SIZE		255U + +static int i2c_request_memory_write(struct i2c_handle_s *hi2c, +				    uint16_t dev_addr, uint16_t mem_addr, +				    uint16_t mem_add_size, uint32_t timeout, +				    uint32_t tick_start); +static int i2c_request_memory_read(struct i2c_handle_s *hi2c, uint16_t dev_addr, +				   uint16_t mem_addr, uint16_t mem_add_size, +				   uint32_t timeout, uint32_t tick_start); + +/* Private functions to handle flags during polling transfer */ +static int i2c_wait_flag(struct i2c_handle_s *hi2c, uint32_t flag, +			 uint8_t awaited_value, uint32_t timeout, +			 uint32_t tick_start); +static int i2c_wait_txis(struct i2c_handle_s *hi2c, uint32_t timeout, +			 uint32_t tick_start); +static int i2c_wait_stop(struct i2c_handle_s *hi2c, uint32_t timeout, +			 uint32_t tick_start); +static int i2c_ack_failed(struct i2c_handle_s *hi2c, uint32_t timeout, +			  uint32_t tick_start); + +/* Private function to flush TXDR register */ +static void i2c_flush_txdr(struct i2c_handle_s *hi2c); + +/* Private function to start, restart or stop a transfer */ +static void i2c_transfer_config(struct i2c_handle_s *hi2c, uint16_t dev_addr, +				uint16_t size, uint32_t i2c_mode, +				uint32_t request); + +/* + * @brief  Initialize the I2C device. + * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains + *               the configuration information for the specified I2C. + * @retval 0 if OK, negative value else + */ +int stm32_i2c_init(struct i2c_handle_s *hi2c) +{ +	if (hi2c == NULL) { +		return -ENOENT; +	} + +	if (hi2c->i2c_state == I2C_STATE_RESET) { +		hi2c->lock = 0; +	} + +	hi2c->i2c_state = I2C_STATE_BUSY; + +	/* Disable the selected I2C peripheral */ +	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE); + +	/* Configure I2Cx: Frequency range */ +	mmio_write_32(hi2c->i2c_base_addr + I2C_TIMINGR, +		      hi2c->i2c_init.timing & TIMING_CLEAR_MASK); + +	/* Disable Own Address1 before set the Own Address1 configuration */ +	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_OAR1, I2C_OAR1_OA1EN); + +	/* Configure I2Cx: Own Address1 and ack own address1 mode */ +	if (hi2c->i2c_init.addressing_mode == I2C_ADDRESSINGMODE_7BIT) { +		mmio_write_32(hi2c->i2c_base_addr + I2C_OAR1, +			      I2C_OAR1_OA1EN | hi2c->i2c_init.own_address1); +	} else { /* I2C_ADDRESSINGMODE_10BIT */ +		mmio_write_32(hi2c->i2c_base_addr + I2C_OAR1, +			      I2C_OAR1_OA1EN | I2C_OAR1_OA1MODE | +			      hi2c->i2c_init.own_address1); +	} + +	/* Configure I2Cx: Addressing Master mode */ +	if (hi2c->i2c_init.addressing_mode == I2C_ADDRESSINGMODE_10BIT) { +		mmio_write_32(hi2c->i2c_base_addr + I2C_CR2, I2C_CR2_ADD10); +	} + +	/* +	 * Enable the AUTOEND by default, and enable NACK +	 * (should be disable only during Slave process) +	 */ +	mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2, +			I2C_CR2_AUTOEND | I2C_CR2_NACK); + +	/* Disable Own Address2 before set the Own Address2 configuration */ +	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_OAR2, I2C_DUALADDRESS_ENABLE); + +	/* Configure I2Cx: Dual mode and Own Address2 */ +	mmio_write_32(hi2c->i2c_base_addr + I2C_OAR2, +		      hi2c->i2c_init.dual_address_mode | +		      hi2c->i2c_init.own_address2 | +		      (hi2c->i2c_init.own_address2_masks << 8)); + +	/* Configure I2Cx: Generalcall and NoStretch mode */ +	mmio_write_32(hi2c->i2c_base_addr + I2C_CR1, +		      hi2c->i2c_init.general_call_mode | +		      hi2c->i2c_init.no_stretch_mode); + +	/* Enable the selected I2C peripheral */ +	mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE); + +	hi2c->i2c_err = I2C_ERROR_NONE; +	hi2c->i2c_state = I2C_STATE_READY; +	hi2c->i2c_mode = I2C_MODE_NONE; + +	return 0; +} + +/* + * @brief  Write an amount of data in blocking mode to a specific memory address + * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains + *               the configuration information for the specified I2C. + * @param  dev_addr: Target device address + * @param  mem_addr: Internal memory address + * @param  mem_add_size: size of internal memory address + * @param  p_data: Pointer to data buffer + * @param  size: Amount of data to be sent + * @param  timeout: timeout duration + * @retval 0 if OK, negative value else + */ +int stm32_i2c_mem_write(struct i2c_handle_s *hi2c, uint16_t dev_addr, +			uint16_t mem_addr, uint16_t mem_add_size, +			uint8_t *p_data, uint16_t size, uint32_t timeout) +{ +	uint32_t tickstart; + +	if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) { +		return -EBUSY; +	} + +	if ((p_data == NULL) || (size == 0U)) { +		return -EINVAL; +	} + +	hi2c->lock = 1; + +	tickstart = (uint32_t)read_cntpct_el0(); + +	if (i2c_wait_flag(hi2c, I2C_FLAG_BUSY, 1, I2C_TIMEOUT_BUSY, +			  tickstart) != 0) { +		return -EIO; +	} + +	hi2c->i2c_state     = I2C_STATE_BUSY_TX; +	hi2c->i2c_mode      = I2C_MODE_MEM; +	hi2c->i2c_err = I2C_ERROR_NONE; + +	hi2c->p_buff  = p_data; +	hi2c->xfer_count = size; + +	/* Send Slave Address and Memory Address */ +	if (i2c_request_memory_write(hi2c, dev_addr, mem_addr, mem_add_size, +				     timeout, tickstart) != 0) { +		hi2c->lock = 0; +		return -EIO; +	} + +	/* +	 * Set NBYTES to write and reload +	 * if hi2c->xfer_count > MAX_NBYTE_SIZE +	 */ +	if (hi2c->xfer_count > MAX_NBYTE_SIZE) { +		hi2c->xfer_size = MAX_NBYTE_SIZE; +		i2c_transfer_config(hi2c, dev_addr, hi2c->xfer_size, +				    I2C_RELOAD_MODE, I2C_NO_STARTSTOP); +	} else { +		hi2c->xfer_size = hi2c->xfer_count; +		i2c_transfer_config(hi2c, dev_addr, hi2c->xfer_size, +				    I2C_AUTOEND_MODE, I2C_NO_STARTSTOP); +	} + +	do { +		if (i2c_wait_txis(hi2c, timeout, tickstart) != 0) { +			return -EIO; +		} + +		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, *hi2c->p_buff); +		hi2c->p_buff++; +		hi2c->xfer_count--; +		hi2c->xfer_size--; + +		if ((hi2c->xfer_count != 0U) && (hi2c->xfer_size == 0U)) { +			/* Wait until TCR flag is set */ +			if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, timeout, +					  tickstart) != 0) { +				return -EIO; +		} + +			if (hi2c->xfer_count > MAX_NBYTE_SIZE) { +				hi2c->xfer_size = MAX_NBYTE_SIZE; +				i2c_transfer_config(hi2c, dev_addr, +						    hi2c->xfer_size, +						    I2C_RELOAD_MODE, +						    I2C_NO_STARTSTOP); +			} else { +				hi2c->xfer_size = hi2c->xfer_count; +				i2c_transfer_config(hi2c, dev_addr, +						    hi2c->xfer_size, +						    I2C_AUTOEND_MODE, +						    I2C_NO_STARTSTOP); +			} +		} + +	} while (hi2c->xfer_count > 0U); + +	/* +	 * No need to Check TC flag, with AUTOEND mode the stop +	 * is automatically generated. +	 * Wait until STOPF flag is reset. +	 */ +	if (i2c_wait_stop(hi2c, timeout, tickstart) != 0) { +		return -EIO; +	} + +	mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF); + +	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2); + +	hi2c->i2c_state = I2C_STATE_READY; +	hi2c->i2c_mode  = I2C_MODE_NONE; + +	hi2c->lock = 0; + +	return 0; +} + +/* + * @brief  Read an amount of data in blocking mode from a specific memory + *	   address + * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains + *               the configuration information for the specified I2C. + * @param  dev_addr: Target device address + * @param  mem_addr: Internal memory address + * @param  mem_add_size: size of internal memory address + * @param  p_data: Pointer to data buffer + * @param  size: Amount of data to be sent + * @param  timeout: timeout duration + * @retval 0 if OK, negative value else + */ +int stm32_i2c_mem_read(struct i2c_handle_s *hi2c, uint16_t dev_addr, +		       uint16_t mem_addr, uint16_t mem_add_size, +		       uint8_t *p_data, uint16_t size, uint32_t timeout) +{ +	uint32_t tickstart; + +	if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) { +		return -EBUSY; +	} + +	if ((p_data == NULL) || (size == 0U)) { +		return  -EINVAL; +	} + +	hi2c->lock = 1; + +	tickstart = (uint32_t)read_cntpct_el0(); + +	if (i2c_wait_flag(hi2c, I2C_FLAG_BUSY, 1, I2C_TIMEOUT_BUSY, +			  tickstart) != 0) { +		return -EIO; +	} + +	hi2c->i2c_state     = I2C_STATE_BUSY_RX; +	hi2c->i2c_mode      = I2C_MODE_MEM; +	hi2c->i2c_err = I2C_ERROR_NONE; + +	hi2c->p_buff  = p_data; +	hi2c->xfer_count = size; + +	/* Send Slave Address and Memory Address */ +	if (i2c_request_memory_read(hi2c, dev_addr, mem_addr, mem_add_size, +				    timeout, tickstart) != 0) { +		hi2c->lock = 0; +		return -EIO; +	} + +	/* +	 * Send Slave Address. +	 * Set NBYTES to write and reload if hi2c->xfer_count > MAX_NBYTE_SIZE +	 * and generate RESTART. +	 */ +	if (hi2c->xfer_count > MAX_NBYTE_SIZE) { +		hi2c->xfer_size = MAX_NBYTE_SIZE; +		i2c_transfer_config(hi2c, dev_addr, hi2c->xfer_size, +				    I2C_RELOAD_MODE, I2C_GENERATE_START_READ); +	} else { +		hi2c->xfer_size = hi2c->xfer_count; +		i2c_transfer_config(hi2c, dev_addr, hi2c->xfer_size, +				    I2C_AUTOEND_MODE, I2C_GENERATE_START_READ); +	} + +	do { +		if (i2c_wait_flag(hi2c, I2C_FLAG_RXNE, 0, timeout, +				  tickstart) != 0) { +			return -EIO; +		} + +		*hi2c->p_buff = mmio_read_8(hi2c->i2c_base_addr + I2C_RXDR); +		hi2c->p_buff++; +		hi2c->xfer_size--; +		hi2c->xfer_count--; + +		if ((hi2c->xfer_count != 0U) && (hi2c->xfer_size == 0U)) { +			if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, timeout, +					  tickstart) != 0) { +				return -EIO; +			} + +			if (hi2c->xfer_count > MAX_NBYTE_SIZE) { +				hi2c->xfer_size = MAX_NBYTE_SIZE; +				i2c_transfer_config(hi2c, dev_addr, +						    hi2c->xfer_size, +						    I2C_RELOAD_MODE, +						    I2C_NO_STARTSTOP); +			} else { +				hi2c->xfer_size = hi2c->xfer_count; +				i2c_transfer_config(hi2c, dev_addr, +						    hi2c->xfer_size, +						    I2C_AUTOEND_MODE, +						    I2C_NO_STARTSTOP); +			} +		} +	} while (hi2c->xfer_count > 0U); + +	/* +	 * No need to Check TC flag, with AUTOEND mode the stop +	 * is automatically generated +	 * Wait until STOPF flag is reset +	 */ +	if (i2c_wait_stop(hi2c, timeout, tickstart) != 0) { +		return -EIO; +	} + +	mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF); + +	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2); + +	hi2c->i2c_state = I2C_STATE_READY; +	hi2c->i2c_mode  = I2C_MODE_NONE; + +	hi2c->lock = 0; + +	return 0; +} + +/* + * @brief  Checks if target device is ready for communication. + * @note   This function is used with Memory devices + * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains + *               the configuration information for the specified I2C. + * @param  dev_addr: Target device address + * @param  trials: Number of trials + * @param  timeout: timeout duration + * @retval 0 if OK, negative value else + */ +int stm32_i2c_is_device_ready(struct i2c_handle_s *hi2c, +			      uint16_t dev_addr, uint32_t trials, +			      uint32_t timeout) +{ +	uint32_t i2c_trials = 0U; + +	if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) { +		return -EBUSY; +	} + +	if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_BUSY) != +	    0U) { +		return -EBUSY; +	} + +	hi2c->lock = 1; + +	hi2c->i2c_state = I2C_STATE_BUSY; +	hi2c->i2c_err = I2C_ERROR_NONE; + +	do { +		uint32_t tickstart; + +		/* Generate Start */ +		if (hi2c->i2c_init.addressing_mode == I2C_ADDRESSINGMODE_7BIT) { +			mmio_write_32(hi2c->i2c_base_addr + I2C_CR2, +				      (((uint32_t)dev_addr & I2C_CR2_SADD) | +				       I2C_CR2_START | I2C_CR2_AUTOEND) & +				       ~I2C_CR2_RD_WRN); +		} else { +			mmio_write_32(hi2c->i2c_base_addr + I2C_CR2, +				      (((uint32_t)dev_addr & I2C_CR2_SADD) | +				       I2C_CR2_START | I2C_CR2_ADD10) & +				      ~I2C_CR2_RD_WRN); +		} + +		/* +		 * No need to Check TC flag, with AUTOEND mode the stop +		 * is automatically generated +		 * Wait until STOPF flag is set or a NACK flag is set +		 */ +		tickstart = (uint32_t)read_cntpct_el0(); +		while (((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & +			 (I2C_FLAG_STOPF | I2C_FLAG_AF)) == 0U) && +		       (hi2c->i2c_state != I2C_STATE_TIMEOUT)) { +			if (timeout != MAX_DELAY) { +				if ((((uint32_t)read_cntpct_el0() - tickstart) > +				     timeout) || (timeout == 0U)) { +					hi2c->i2c_state = I2C_STATE_READY; + +					hi2c->i2c_err |= +						I2C_ERROR_TIMEOUT; + +					hi2c->lock = 0; + +					return -EIO; +				} +			} +		} + +		/* Check if the NACKF flag has not been set */ +		if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & +		     I2C_FLAG_AF) == 0U) { +			if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, timeout, +					  tickstart) != 0) { +				return -EIO; +			} + +			mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, +				      I2C_FLAG_STOPF); + +			hi2c->i2c_state = I2C_STATE_READY; + +			hi2c->lock = 0; + +			return 0; +		} + +		if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, timeout, +				  tickstart) != 0) { +			return -EIO; +		} + +		mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_AF); + +		mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF); + +		if (i2c_trials == trials) { +			mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2, +					I2C_CR2_STOP); + +			if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, timeout, +					  tickstart) != 0) { +				return -EIO; +			} + +			mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, +				      I2C_FLAG_STOPF); +		} + +		i2c_trials++; +	} while (i2c_trials < trials); + +	hi2c->i2c_state = I2C_STATE_READY; + +	hi2c->i2c_err |= I2C_ERROR_TIMEOUT; + +	hi2c->lock = 0; + +	return -EIO; +} + +/* + * @brief  Master sends target device address followed by internal memory + *	   address for write request. + * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains + *               the configuration information for the specified I2C. + * @param  dev_addr: Target device address + * @param  mem_addr: Internal memory address + * @param  mem_add_size: size of internal memory address + * @param  timeout: timeout duration + * @param  tick_start Tick start value + * @retval 0 if OK, negative value else + */ +static int i2c_request_memory_write(struct i2c_handle_s *hi2c, +				    uint16_t dev_addr, uint16_t mem_addr, +				    uint16_t mem_add_size, uint32_t timeout, +				    uint32_t tick_start) +{ +	i2c_transfer_config(hi2c, dev_addr, mem_add_size, I2C_RELOAD_MODE, +			    I2C_GENERATE_START_WRITE); + +	if (i2c_wait_txis(hi2c, timeout, tick_start) != 0) { +		return -EIO; +	} + +	if (mem_add_size == I2C_MEMADD_SIZE_8BIT) { +		/* Send Memory Address */ +		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, +			     (uint8_t)(mem_addr & 0x00FFU)); +	} else { +		/* Send MSB of Memory Address */ +		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, +			     (uint8_t)((mem_addr & 0xFF00U) >> 8)); + +		/* Wait until TXIS flag is set */ +		if (i2c_wait_txis(hi2c, timeout, tick_start) != 0) { +			return -EIO; +		} + +		/* Send LSB of Memory Address */ +		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, +			     (uint8_t)(mem_addr & 0x00FFU)); +	} + +	if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, timeout, tick_start) != +	    0) { +		return -EIO; +	} + +	return 0; +} + +/* + * @brief  Master sends target device address followed by internal memory + *	   address for read request. + * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains + *               the configuration information for the specified I2C. + * @param  dev_addr: Target device address + * @param  mem_addr: Internal memory address + * @param  mem_add_size: size of internal memory address + * @param  timeout: timeout duration + * @param  tick_start Tick start value + * @retval 0 if OK, negative value else + */ +static int i2c_request_memory_read(struct i2c_handle_s *hi2c, uint16_t dev_addr, +				   uint16_t mem_addr, uint16_t mem_add_size, +				   uint32_t timeout, uint32_t tick_start) +{ +	i2c_transfer_config(hi2c, dev_addr, mem_add_size, I2C_SOFTEND_MODE, +			    I2C_GENERATE_START_WRITE); + +	if (i2c_wait_txis(hi2c, timeout, tick_start) != 0) { +		return -EIO; +	} + +	if (mem_add_size == I2C_MEMADD_SIZE_8BIT) { +		/* Send Memory Address */ +		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, +			     (uint8_t)(mem_addr & 0x00FFU)); +	} else { +		/* Send MSB of Memory Address */ +		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, +			     (uint8_t)((mem_addr & 0xFF00U) >> 8)); + +		/* Wait until TXIS flag is set */ +		if (i2c_wait_txis(hi2c, timeout, tick_start) != 0) { +			return -EIO; +		} + +		/* Send LSB of Memory Address */ +		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, +			     (uint8_t)(mem_addr & 0x00FFU)); +	} + +	if (i2c_wait_flag(hi2c, I2C_FLAG_TC, 0, timeout, tick_start) != 0) { +		return -EIO; +	} + +	return 0; +} + +/* + * @brief  I2C Tx data register flush process. + * @param  hi2c: I2C handle. + * @retval None + */ +static void i2c_flush_txdr(struct i2c_handle_s *hi2c) +{ +	/* +	 * If a pending TXIS flag is set, +	 * write a dummy data in TXDR to clear it. +	 */ +	if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_TXIS) != +	    0U) { +		mmio_write_32(hi2c->i2c_base_addr + I2C_TXDR, 0); +	} + +	/* Flush TX register if not empty */ +	if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_TXE) == +	    0U) { +		mmio_setbits_32(hi2c->i2c_base_addr + I2C_ISR, +				I2C_FLAG_TXE); +	} +} + +/* + * @brief  This function handles I2C Communication timeout. + * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains + *               the configuration information for the specified I2C. + * @param  flag: Specifies the I2C flag to check. + * @param  awaited_value: The awaited bit value for the flag (0 or 1). + * @param  timeout: timeout duration + * @param  tick_start: Tick start value + * @retval 0 if OK, negative value else + */ +static int i2c_wait_flag(struct i2c_handle_s *hi2c, uint32_t flag, +			 uint8_t awaited_value, uint32_t timeout, +			 uint32_t tick_start) +{ +	uint8_t flag_check; + +	do { +		flag_check = ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & +			       flag) == flag) ? 1U : 0U; + +		if (timeout != MAX_DELAY) { +			if ((((uint32_t)read_cntpct_el0() - tick_start) > +			     timeout) || (timeout == 0U)) { +				hi2c->i2c_err |= I2C_ERROR_TIMEOUT; +				hi2c->i2c_state = I2C_STATE_READY; +				hi2c->i2c_mode = I2C_MODE_NONE; + +				hi2c->lock = 0; +				return -EIO; +			} +		} +	} while (flag_check == awaited_value); + +	return 0; +} + +/* + * @brief  This function handles I2C Communication timeout for specific usage + *	   of TXIS flag. + * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains + *               the configuration information for the specified I2C. + * @param  timeout: timeout duration + * @param  tick_start: Tick start value + * @retval 0 if OK, negative value else + */ +static int i2c_wait_txis(struct i2c_handle_s *hi2c, uint32_t timeout, +			 uint32_t tick_start) +{ +	while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & +		I2C_FLAG_TXIS) == 0U) { +		if (i2c_ack_failed(hi2c, timeout, tick_start) != 0) { +			return -EIO; +		} + +		if (timeout != MAX_DELAY) { +			if ((((uint32_t)read_cntpct_el0() - tick_start) > +			     timeout) || (timeout == 0U)) { +				hi2c->i2c_err |= I2C_ERROR_TIMEOUT; +				hi2c->i2c_state = I2C_STATE_READY; +				hi2c->i2c_mode = I2C_MODE_NONE; + +				hi2c->lock = 0; + +				return -EIO; +			} +		} +	} + +	return 0; +} + +/* + * @brief  This function handles I2C Communication timeout for specific + *	   usage of STOP flag. + * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains + *               the configuration information for the specified I2C. + * @param  timeout: timeout duration + * @param  tick_start: Tick start value + * @retval 0 if OK, negative value else + */ +static int i2c_wait_stop(struct i2c_handle_s *hi2c, uint32_t timeout, +			 uint32_t tick_start) +{ +	while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & +		 I2C_FLAG_STOPF) == 0U) { +		if (i2c_ack_failed(hi2c, timeout, tick_start) != 0) { +			return -EIO; +		} + +		if ((((uint32_t)read_cntpct_el0() - tick_start) > timeout) || +		    (timeout == 0U)) { +			hi2c->i2c_err |= I2C_ERROR_TIMEOUT; +			hi2c->i2c_state = I2C_STATE_READY; +			hi2c->i2c_mode = I2C_MODE_NONE; + +			hi2c->lock = 0; + +			return -EIO; +		} +	} + +	return 0; +} + +/* + * @brief  This function handles Acknowledge failed detection during + *	   an I2C Communication. + * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains + *               the configuration information for the specified I2C. + * @param  timeout: timeout duration + * @param  tick_start: Tick start value + * @retval 0 if OK, negative value else + */ +static int i2c_ack_failed(struct i2c_handle_s *hi2c, uint32_t timeout, +			  uint32_t tick_start) +{ +	if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_AF) == 0U) { +		return 0; +	} + +	/* +	 * Wait until STOP Flag is reset. +	 * AutoEnd should be initiate after AF. +	 */ +	while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & +		I2C_FLAG_STOPF) == 0U) { +		if (timeout != MAX_DELAY) { +			if ((((uint32_t)read_cntpct_el0() - tick_start) > +			     timeout) || (timeout == 0U)) { +				hi2c->i2c_err |= I2C_ERROR_TIMEOUT; +				hi2c->i2c_state = I2C_STATE_READY; +				hi2c->i2c_mode = I2C_MODE_NONE; + +				hi2c->lock = 0; + +				return -EIO; +			} +		} +	} + +	mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_AF); + +	mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF); + +	i2c_flush_txdr(hi2c); + +	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2); + +	hi2c->i2c_err |= I2C_ERROR_AF; +	hi2c->i2c_state = I2C_STATE_READY; +	hi2c->i2c_mode = I2C_MODE_NONE; + +	hi2c->lock = 0; + +	return -EIO; +} + +/* + * @brief  Handles I2Cx communication when starting transfer or during transfer + *	   (TC or TCR flag are set). + * @param  hi2c: I2C handle. + * @param  dev_addr: Specifies the slave address to be programmed. + * @param  size: Specifies the number of bytes to be programmed. + *   This parameter must be a value between 0 and 255. + * @param  i2c_mode: New state of the I2C START condition generation. + *   This parameter can be one of the following values: + *     @arg @ref I2C_RELOAD_MODE: Enable Reload mode . + *     @arg @ref I2C_AUTOEND_MODE: Enable Automatic end mode. + *     @arg @ref I2C_SOFTEND_MODE: Enable Software end mode. + * @param  request: New state of the I2C START condition generation. + *   This parameter can be one of the following values: + *     @arg @ref I2C_NO_STARTSTOP: Don't Generate stop and start condition. + *     @arg @ref I2C_GENERATE_STOP: Generate stop condition + *                                  (size should be set to 0). + *     @arg @ref I2C_GENERATE_START_READ: Generate Restart for read request. + *     @arg @ref I2C_GENERATE_START_WRITE: Generate Restart for write request. + * @retval None + */ +static void i2c_transfer_config(struct i2c_handle_s *hi2c, uint16_t dev_addr, +				uint16_t size, uint32_t i2c_mode, +				uint32_t request) +{ +	uint32_t clr_value, set_value; + +	clr_value = (I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RELOAD | +		     I2C_CR2_AUTOEND | I2C_CR2_START | I2C_CR2_STOP) | +		(I2C_CR2_RD_WRN & (request >> (31U - I2C_CR2_RD_WRN_OFFSET))); + +	set_value = ((uint32_t)dev_addr & I2C_CR2_SADD) | +		(((uint32_t)size << I2C_CR2_NBYTES_OFFSET) & I2C_CR2_NBYTES) | +		i2c_mode | request; + +	mmio_clrsetbits_32(hi2c->i2c_base_addr + I2C_CR2, clr_value, set_value); +} + +/* + * @brief  Configure I2C Analog noise filter. + * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains + *               the configuration information for the specified I2Cx peripheral + * @param  analog_filter: New state of the Analog filter. + * @retval 0 if OK, negative value else + */ +int stm32_i2c_config_analog_filter(struct i2c_handle_s *hi2c, +				   uint32_t analog_filter) +{ +	if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) { +		return -EBUSY; +	} + +	hi2c->lock = 1; + +	hi2c->i2c_state = I2C_STATE_BUSY; + +	/* Disable the selected I2C peripheral */ +	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE); + +	/* Reset I2Cx ANOFF bit */ +	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_ANFOFF); + +	/* Set analog filter bit*/ +	mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, analog_filter); + +	/* Enable the selected I2C peripheral */ +	mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE); + +	hi2c->i2c_state = I2C_STATE_READY; + +	hi2c->lock = 0; + +	return 0; +} diff --git a/drivers/st/pmic/stm32mp1_pmic.c b/drivers/st/pmic/stm32mp1_pmic.c new file mode 100644 index 00000000..958de08d --- /dev/null +++ b/drivers/st/pmic/stm32mp1_pmic.c @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <debug.h> +#include <delay_timer.h> +#include <errno.h> +#include <libfdt.h> +#include <mmio.h> +#include <mmio.h> +#include <platform_def.h> +#include <stdbool.h> +#include <stm32_gpio.h> +#include <stm32mp1_clk.h> +#include <stm32mp1_dt.h> +#include <stm32mp1_pmic.h> +#include <stpmu1.h> +#include <utils_def.h> + +/* I2C Timing hard-coded value, for I2C clock source is HSI at 64MHz */ +#define I2C_TIMING			0x10D07DB5 + +#define I2C_TIMEOUT			0xFFFFF + +#define MASK_RESET_BUCK3		BIT(2) + +#define STPMU1_LDO12356_OUTPUT_MASK	(uint8_t)(GENMASK(6, 2)) +#define STPMU1_LDO12356_OUTPUT_SHIFT	2 +#define STPMU1_LDO3_MODE		(uint8_t)(BIT(7)) +#define STPMU1_LDO3_DDR_SEL		31U +#define STPMU1_LDO3_1800000		(9U << STPMU1_LDO12356_OUTPUT_SHIFT) + +#define STPMU1_BUCK_OUTPUT_SHIFT	2 +#define STPMU1_BUCK3_1V8		(39U << STPMU1_BUCK_OUTPUT_SHIFT) + +#define STPMU1_DEFAULT_START_UP_DELAY_MS	1 + +static struct i2c_handle_s i2c_handle; +static uint32_t pmic_i2c_addr; + +static int dt_get_pmic_node(void *fdt) +{ +	return fdt_node_offset_by_compatible(fdt, -1, "st,stpmu1"); +} + +bool dt_check_pmic(void) +{ +	int node; +	void *fdt; + +	if (fdt_get_address(&fdt) == 0) { +		return false; +	} + +	node = dt_get_pmic_node(fdt); +	if (node < 0) { +		VERBOSE("%s: No PMIC node found in DT\n", __func__); +		return false; +	} + +	return fdt_check_status(node); +} + +static int dt_pmic_i2c_config(struct dt_node_info *i2c_info) +{ +	int pmic_node, i2c_node; +	void *fdt; +	const fdt32_t *cuint; + +	if (fdt_get_address(&fdt) == 0) { +		return -ENOENT; +	} + +	pmic_node = dt_get_pmic_node(fdt); +	if (pmic_node < 0) { +		return -FDT_ERR_NOTFOUND; +	} + +	cuint = fdt_getprop(fdt, pmic_node, "reg", NULL); +	if (cuint == NULL) { +		return -FDT_ERR_NOTFOUND; +	} + +	pmic_i2c_addr = fdt32_to_cpu(*cuint) << 1; +	if (pmic_i2c_addr > UINT16_MAX) { +		return -EINVAL; +	} + +	i2c_node = fdt_parent_offset(fdt, pmic_node); +	if (i2c_node < 0) { +		return -FDT_ERR_NOTFOUND; +	} + +	dt_fill_device_info(i2c_info, i2c_node); +	if (i2c_info->base == 0U) { +		return -FDT_ERR_NOTFOUND; +	} + +	return dt_set_pinctrl_config(i2c_node); +} + +int dt_pmic_enable_boot_on_regulators(void) +{ +	int pmic_node, regulators_node, regulator_node; +	void *fdt; + +	if (fdt_get_address(&fdt) == 0) { +		return -ENOENT; +	} + +	pmic_node = dt_get_pmic_node(fdt); +	if (pmic_node < 0) { +		return -FDT_ERR_NOTFOUND; +	} + +	regulators_node = fdt_subnode_offset(fdt, pmic_node, "regulators"); + +	fdt_for_each_subnode(regulator_node, fdt, regulators_node) { +		const fdt32_t *cuint; +		const char *node_name; +		uint16_t voltage; + +		if (fdt_getprop(fdt, regulator_node, "regulator-boot-on", +				NULL) == NULL) { +			continue; +		} + +		cuint = fdt_getprop(fdt, regulator_node, +				    "regulator-min-microvolt", NULL); +		if (cuint == NULL) { +			continue; +		} + +		/* DT uses microvolts, whereas driver awaits millivolts */ +		voltage = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U); +		node_name = fdt_get_name(fdt, regulator_node, NULL); + +		if (stpmu1_is_regulator_enabled(node_name) == 0U) { +			int status; + +			status = stpmu1_regulator_voltage_set(node_name, +							      voltage); +			if (status != 0) { +				return status; +			} + +			status = stpmu1_regulator_enable(node_name); +			if (status != 0) { +				return status; +			} +		} +	} + +	return 0; +} + +void initialize_pmic_i2c(void) +{ +	int ret; +	struct dt_node_info i2c_info; + +	if (dt_pmic_i2c_config(&i2c_info) != 0) { +		ERROR("I2C configuration failed\n"); +		panic(); +	} + +	if (stm32mp1_clk_enable((uint32_t)i2c_info.clock) < 0) { +		ERROR("I2C clock enable failed\n"); +		panic(); +	} + +	/* Initialize PMIC I2C */ +	i2c_handle.i2c_base_addr		= i2c_info.base; +	i2c_handle.i2c_init.timing		= I2C_TIMING; +	i2c_handle.i2c_init.own_address1	= pmic_i2c_addr; +	i2c_handle.i2c_init.addressing_mode	= I2C_ADDRESSINGMODE_7BIT; +	i2c_handle.i2c_init.dual_address_mode	= I2C_DUALADDRESS_DISABLE; +	i2c_handle.i2c_init.own_address2	= 0; +	i2c_handle.i2c_init.own_address2_masks	= I2C_OAR2_OA2NOMASK; +	i2c_handle.i2c_init.general_call_mode	= I2C_GENERALCALL_DISABLE; +	i2c_handle.i2c_init.no_stretch_mode	= I2C_NOSTRETCH_DISABLE; + +	ret = stm32_i2c_init(&i2c_handle); +	if (ret != 0) { +		ERROR("Cannot initialize I2C %x (%d)\n", +		      i2c_handle.i2c_base_addr, ret); +		panic(); +	} + +	ret = stm32_i2c_config_analog_filter(&i2c_handle, +					     I2C_ANALOGFILTER_ENABLE); +	if (ret != 0) { +		ERROR("Cannot initialize I2C analog filter (%d)\n", ret); +		panic(); +	} + +	ret = stm32_i2c_is_device_ready(&i2c_handle, (uint16_t)pmic_i2c_addr, 1, +					I2C_TIMEOUT); +	if (ret != 0) { +		ERROR("I2C device not ready (%d)\n", ret); +		panic(); +	} + +	stpmu1_bind_i2c(&i2c_handle, (uint16_t)pmic_i2c_addr); +} + +void initialize_pmic(void) +{ +	int status; +	uint8_t read_val; + +	initialize_pmic_i2c(); + +	status = stpmu1_register_read(VERSION_STATUS_REG, &read_val); +	if (status != 0) { +		panic(); +	} + +	INFO("PMIC version = 0x%x\n", read_val); + +	/* Keep VDD on during the reset cycle */ +	status = stpmu1_register_update(MASK_RESET_BUCK_REG, +					MASK_RESET_BUCK3, +					MASK_RESET_BUCK3); +	if (status != 0) { +		panic(); +	} +} + +int pmic_ddr_power_init(enum ddr_type ddr_type) +{ +	bool buck3_at_1v8 = false; +	uint8_t read_val; +	int status; + +	switch (ddr_type) { +	case STM32MP_DDR3: +		/* Set LDO3 to sync mode */ +		status = stpmu1_register_read(LDO3_CONTROL_REG, &read_val); +		if (status != 0) { +			return status; +		} + +		read_val &= ~STPMU1_LDO3_MODE; +		read_val &= ~STPMU1_LDO12356_OUTPUT_MASK; +		read_val |= STPMU1_LDO3_DDR_SEL << STPMU1_LDO12356_OUTPUT_SHIFT; + +		status = stpmu1_register_write(LDO3_CONTROL_REG, read_val); +		if (status != 0) { +			return status; +		} + +		status = stpmu1_regulator_voltage_set("buck2", 1350); +		if (status != 0) { +			return status; +		} + +		status = stpmu1_regulator_enable("buck2"); +		if (status != 0) { +			return status; +		} + +		mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); + +		status = stpmu1_regulator_enable("vref_ddr"); +		if (status != 0) { +			return status; +		} + +		mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); + +		status = stpmu1_regulator_enable("ldo3"); +		if (status != 0) { +			return status; +		} + +		mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); +		break; + +	case STM32MP_LPDDR2: +		/* +		 * Set LDO3 to 1.8V +		 * Set LDO3 to bypass mode if BUCK3 = 1.8V +		 * Set LDO3 to normal mode if BUCK3 != 1.8V +		 */ +		status = stpmu1_register_read(BUCK3_CONTROL_REG, &read_val); +		if (status != 0) { +			return status; +		} + +		if ((read_val & STPMU1_BUCK3_1V8) == STPMU1_BUCK3_1V8) { +			buck3_at_1v8 = true; +		} + +		status = stpmu1_register_read(LDO3_CONTROL_REG, &read_val); +		if (status != 0) { +			return status; +		} + +		read_val &= ~STPMU1_LDO3_MODE; +		read_val &= ~STPMU1_LDO12356_OUTPUT_MASK; +		read_val |= STPMU1_LDO3_1800000; +		if (buck3_at_1v8) { +			read_val |= STPMU1_LDO3_MODE; +		} + +		status = stpmu1_register_write(LDO3_CONTROL_REG, read_val); +		if (status != 0) { +			return status; +		} + +		status = stpmu1_regulator_voltage_set("buck2", 1200); +		if (status != 0) { +			return status; +		} + +		status = stpmu1_regulator_enable("ldo3"); +		if (status != 0) { +			return status; +		} + +		mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); + +		status = stpmu1_regulator_enable("buck2"); +		if (status != 0) { +			return status; +		} + +		mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); + +		status = stpmu1_regulator_enable("vref_ddr"); +		if (status != 0) { +			return status; +		} + +		mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); +		break; + +	default: +		break; +	}; + +	return 0; +} diff --git a/drivers/st/pmic/stpmu1.c b/drivers/st/pmic/stpmu1.c new file mode 100644 index 00000000..5951899a --- /dev/null +++ b/drivers/st/pmic/stpmu1.c @@ -0,0 +1,600 @@ +/* + * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <debug.h> +#include <platform.h> +#include <stpmu1.h> +#include <string.h> + +struct regul_struct { +	const char *dt_node_name; +	const uint16_t *voltage_table; +	uint8_t voltage_table_size; +	uint8_t control_reg; +	uint8_t low_power_reg; +}; + +static struct i2c_handle_s *stpmu_i2c_handle; +static uint16_t stpmu_i2c_addr; + +/* Voltage tables in mV */ +static const uint16_t buck1_voltage_table[] = { +	600, +	625, +	650, +	675, +	700, +	725, +	750, +	775, +	800, +	825, +	850, +	875, +	900, +	925, +	950, +	975, +	1000, +	1025, +	1050, +	1075, +	1100, +	1125, +	1150, +	1175, +	1200, +	1225, +	1250, +	1275, +	1300, +	1325, +	1350, +	1350, +}; + +static const uint16_t buck2_voltage_table[] = { +	1000, +	1000, +	1000, +	1000, +	1000, +	1000, +	1000, +	1000, +	1000, +	1000, +	1000, +	1000, +	1000, +	1000, +	1000, +	1000, +	1000, +	1000, +	1050, +	1050, +	1100, +	1100, +	1150, +	1150, +	1200, +	1200, +	1250, +	1250, +	1300, +	1300, +	1350, +	1350, +	1400, +	1400, +	1450, +	1450, +	1500, +}; + +static const uint16_t buck3_voltage_table[] = { +	1000, +	1000, +	1000, +	1000, +	1000, +	1000, +	1000, +	1000, +	1000, +	1000, +	1000, +	1000, +	1000, +	1000, +	1000, +	1000, +	1000, +	1000, +	1000, +	1000, +	1100, +	1100, +	1100, +	1100, +	1200, +	1200, +	1200, +	1200, +	1300, +	1300, +	1300, +	1300, +	1400, +	1400, +	1400, +	1400, +	1500, +	1600, +	1700, +	1800, +	1900, +	2000, +	2100, +	2200, +	2300, +	2400, +	2500, +	2600, +	2700, +	2800, +	2900, +	3000, +	3100, +	3200, +	3300, +	3400, +}; + +static const uint16_t buck4_voltage_table[] = { +	600, +	625, +	650, +	675, +	700, +	725, +	750, +	775, +	800, +	825, +	850, +	875, +	900, +	925, +	950, +	975, +	1000, +	1025, +	1050, +	1075, +	1100, +	1125, +	1150, +	1175, +	1200, +	1225, +	1250, +	1275, +	1300, +	1300, +	1350, +	1350, +	1400, +	1400, +	1450, +	1450, +	1500, +	1600, +	1700, +	1800, +	1900, +	2000, +	2100, +	2200, +	2300, +	2400, +	2500, +	2600, +	2700, +	2800, +	2900, +	3000, +	3100, +	3200, +	3300, +	3400, +	3500, +	3600, +	3700, +	3800, +	3900, +}; + +static const uint16_t ldo1_voltage_table[] = { +	1700, +	1700, +	1700, +	1700, +	1700, +	1700, +	1700, +	1700, +	1700, +	1800, +	1900, +	2000, +	2100, +	2200, +	2300, +	2400, +	2500, +	2600, +	2700, +	2800, +	2900, +	3000, +	3100, +	3200, +	3300, +}; + +static const uint16_t ldo2_voltage_table[] = { +	1700, +	1700, +	1700, +	1700, +	1700, +	1700, +	1700, +	1700, +	1700, +	1800, +	1900, +	2000, +	2100, +	2200, +	2300, +	2400, +	2500, +	2600, +	2700, +	2800, +	2900, +	3000, +	3100, +	3200, +	3300, +}; + +static const uint16_t ldo3_voltage_table[] = { +	1700, +	1700, +	1700, +	1700, +	1700, +	1700, +	1700, +	1700, +	1700, +	1800, +	1900, +	2000, +	2100, +	2200, +	2300, +	2400, +	2500, +	2600, +	2700, +	2800, +	2900, +	3000, +	3100, +	3200, +	3300, +	3300, +	3300, +	3300, +	3300, +	3300, +	3300, +	0xFFFF, /* VREFDDR */ +}; + +static const uint16_t ldo5_voltage_table[] = { +	1700, +	1700, +	1700, +	1700, +	1700, +	1700, +	1700, +	1700, +	1700, +	1800, +	1900, +	2000, +	2100, +	2200, +	2300, +	2400, +	2500, +	2600, +	2700, +	2800, +	2900, +	3000, +	3100, +	3200, +	3300, +	3400, +	3500, +	3600, +	3700, +	3800, +	3900, +}; + +static const uint16_t ldo6_voltage_table[] = { +	900, +	1000, +	1100, +	1200, +	1300, +	1400, +	1500, +	1600, +	1700, +	1800, +	1900, +	2000, +	2100, +	2200, +	2300, +	2400, +	2500, +	2600, +	2700, +	2800, +	2900, +	3000, +	3100, +	3200, +	3300, +}; + +static const uint16_t ldo4_voltage_table[] = { +	3300, +}; + +static const uint16_t vref_ddr_voltage_table[] = { +	3300, +}; + +/* Table of Regulators in PMIC SoC */ +static const struct regul_struct regulators_table[] = { +	{ +		.dt_node_name	= "buck1", +		.voltage_table	= buck1_voltage_table, +		.voltage_table_size = ARRAY_SIZE(buck1_voltage_table), +		.control_reg	= BUCK1_CONTROL_REG, +		.low_power_reg	= BUCK1_PWRCTRL_REG, +	}, +	{ +		.dt_node_name	= "buck2", +		.voltage_table	= buck2_voltage_table, +		.voltage_table_size = ARRAY_SIZE(buck2_voltage_table), +		.control_reg	= BUCK2_CONTROL_REG, +		.low_power_reg	= BUCK2_PWRCTRL_REG, +	}, +	{ +		.dt_node_name	= "buck3", +		.voltage_table	= buck3_voltage_table, +		.voltage_table_size = ARRAY_SIZE(buck3_voltage_table), +		.control_reg	= BUCK3_CONTROL_REG, +		.low_power_reg	= BUCK3_PWRCTRL_REG, +	}, +	{ +		.dt_node_name	= "buck4", +		.voltage_table	= buck4_voltage_table, +		.voltage_table_size = ARRAY_SIZE(buck4_voltage_table), +		.control_reg	= BUCK4_CONTROL_REG, +		.low_power_reg	= BUCK4_PWRCTRL_REG, +	}, +	{ +		.dt_node_name	= "ldo1", +		.voltage_table	= ldo1_voltage_table, +		.voltage_table_size = ARRAY_SIZE(ldo1_voltage_table), +		.control_reg	= LDO1_CONTROL_REG, +		.low_power_reg	= LDO1_PWRCTRL_REG, +	}, +	{ +		.dt_node_name	= "ldo2", +		.voltage_table	= ldo2_voltage_table, +		.voltage_table_size = ARRAY_SIZE(ldo2_voltage_table), +		.control_reg	= LDO2_CONTROL_REG, +		.low_power_reg	= LDO2_PWRCTRL_REG, +	}, +	{ +		.dt_node_name	= "ldo3", +		.voltage_table	= ldo3_voltage_table, +		.voltage_table_size = ARRAY_SIZE(ldo3_voltage_table), +		.control_reg	= LDO3_CONTROL_REG, +		.low_power_reg	= LDO3_PWRCTRL_REG, +	}, +	{ +		.dt_node_name	= "ldo4", +		.voltage_table	= ldo4_voltage_table, +		.voltage_table_size = ARRAY_SIZE(ldo4_voltage_table), +		.control_reg	= LDO4_CONTROL_REG, +		.low_power_reg	= LDO4_PWRCTRL_REG, +	}, +	{ +		.dt_node_name	= "ldo5", +		.voltage_table	= ldo5_voltage_table, +		.voltage_table_size = ARRAY_SIZE(ldo5_voltage_table), +		.control_reg	= LDO5_CONTROL_REG, +		.low_power_reg	= LDO5_PWRCTRL_REG, +	}, +	{ +		.dt_node_name	= "ldo6", +		.voltage_table	= ldo6_voltage_table, +		.voltage_table_size = ARRAY_SIZE(ldo6_voltage_table), +		.control_reg	= LDO6_CONTROL_REG, +		.low_power_reg	= LDO6_PWRCTRL_REG, +	}, +	{ +		.dt_node_name	= "vref_ddr", +		.voltage_table	= vref_ddr_voltage_table, +		.voltage_table_size = ARRAY_SIZE(vref_ddr_voltage_table), +		.control_reg	= VREF_DDR_CONTROL_REG, +		.low_power_reg	= VREF_DDR_PWRCTRL_REG, +	}, +}; + +#define MAX_REGUL  ARRAY_SIZE(regulators_table) + +static const struct regul_struct *stpmu1_get_regulator_data(const char *name) +{ +	uint8_t i; + +	for (i = 0 ; i < MAX_REGUL ; i++) { +		if (strncmp(name, regulators_table[i].dt_node_name, +			    strlen(regulators_table[i].dt_node_name)) == 0) { +			return ®ulators_table[i]; +		} +	} + +	/* Regulator not found */ +	panic(); +	return NULL; +} + +static uint8_t stpmu1_voltage_find_index(const char *name, +					 uint16_t millivolts) +{ +	const struct regul_struct *regul = stpmu1_get_regulator_data(name); +	uint8_t i; + +	for (i = 0 ; i < regul->voltage_table_size ; i++) { +		if (regul->voltage_table[i] == millivolts) { +			return i; +		} +	} + +	/* Voltage not found */ +	panic(); + +	return 0; +} + +int stpmu1_switch_off(void) +{ +	return stpmu1_register_update(MAIN_CONTROL_REG, 1, +				      SOFTWARE_SWITCH_OFF_ENABLED); +} + +int stpmu1_regulator_enable(const char *name) +{ +	const struct regul_struct *regul = stpmu1_get_regulator_data(name); + +	return stpmu1_register_update(regul->control_reg, BIT(0), BIT(0)); +} + +int stpmu1_regulator_disable(const char *name) +{ +	const struct regul_struct *regul = stpmu1_get_regulator_data(name); + +	return stpmu1_register_update(regul->control_reg, 0, BIT(0)); +} + +uint8_t stpmu1_is_regulator_enabled(const char *name) +{ +	uint8_t val; +	const struct regul_struct *regul = stpmu1_get_regulator_data(name); + +	if (stpmu1_register_read(regul->control_reg, &val) != 0) { +		panic(); +	} + +	return (val & 0x1U); +} + +int stpmu1_regulator_voltage_set(const char *name, uint16_t millivolts) +{ +	uint8_t voltage_index = stpmu1_voltage_find_index(name, millivolts); +	const struct regul_struct *regul = stpmu1_get_regulator_data(name); + +	return stpmu1_register_update(regul->control_reg, voltage_index << 2, +				      0xFC); +} + +int stpmu1_register_read(uint8_t register_id,  uint8_t *value) +{ +	return stm32_i2c_mem_read(stpmu_i2c_handle, stpmu_i2c_addr, +				    (uint16_t)register_id, I2C_MEMADD_SIZE_8BIT, +				    value, 1, 100000); +} + +int stpmu1_register_write(uint8_t register_id, uint8_t value) +{ +	int status; + +	status = stm32_i2c_mem_write(stpmu_i2c_handle, stpmu_i2c_addr, +				     (uint16_t)register_id, +				     I2C_MEMADD_SIZE_8BIT, &value, 1, 100000); + +	if (status != 0) { +		return status; +	} + +	if ((register_id != WATCHDOG_CONTROL_REG) && (register_id <= 0x40U)) { +		uint8_t readval; + +		status = stpmu1_register_read(register_id, &readval); +		if (status != 0) { +			return status; +		} + +		if (readval != value) { +			return -1; +		} +	} + +	return 0; +} + +int stpmu1_register_update(uint8_t register_id, uint8_t value, uint8_t mask) +{ +	int status; +	uint8_t val; + +	status = stpmu1_register_read(register_id, &val); +	if (status != 0) { +		return status; +	} + +	/* Clear bits to update */ +	val &= ~mask; + +	/* Update appropriate bits*/ +	val |= (value & mask); + +	/* Send new value on I2C Bus */ +	return stpmu1_register_write(register_id, val); +} + +void stpmu1_bind_i2c(struct i2c_handle_s *i2c_handle, uint16_t i2c_addr) +{ +	stpmu_i2c_handle = i2c_handle; +	stpmu_i2c_addr = i2c_addr; +} diff --git a/drivers/st/reset/stm32mp1_reset.c b/drivers/st/reset/stm32mp1_reset.c new file mode 100644 index 00000000..106bbfe6 --- /dev/null +++ b/drivers/st/reset/stm32mp1_reset.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <bl_common.h> +#include <debug.h> +#include <limits.h> +#include <mmio.h> +#include <platform_def.h> +#include <stm32mp1_rcc.h> +#include <stm32mp1_reset.h> +#include <utils_def.h> + +#define RST_CLR_OFFSET	4U + +void stm32mp1_reset_assert(uint32_t id) +{ +	uint32_t offset = (id / (uint32_t)__LONG_BIT) * sizeof(uintptr_t); +	uint32_t bit = id % (uint32_t)__LONG_BIT; + +	mmio_write_32(RCC_BASE + offset, BIT(bit)); +	while ((mmio_read_32(RCC_BASE + offset) & BIT(bit)) == 0U) { +		; +	} +} + +void stm32mp1_reset_deassert(uint32_t id) +{ +	uint32_t offset = ((id / (uint32_t)__LONG_BIT) * sizeof(uintptr_t)) + +			  RST_CLR_OFFSET; +	uint32_t bit = id % (uint32_t)__LONG_BIT; + +	mmio_write_32(RCC_BASE + offset, BIT(bit)); +	while ((mmio_read_32(RCC_BASE + offset) & BIT(bit)) != 0U) { +		; +	} +} diff --git a/drivers/st/uart/aarch32/stm32_console.S b/drivers/st/uart/aarch32/stm32_console.S new file mode 100644 index 00000000..792703a9 --- /dev/null +++ b/drivers/st/uart/aarch32/stm32_console.S @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include <asm_macros.S> + +#define USART_TIMEOUT		0x1000 + +#define USART_CR1		0x00 +#define USART_CR1_UE		0x00000001 +#define USART_CR1_TE		0x00000008 +#define USART_CR1_FIFOEN	0x20000000 + +#define USART_CR2		0x04 +#define USART_CR2_STOP		0x00003000 + +#define USART_BRR		0x0C + +#define USART_ISR		0x1C +#define USART_ISR_TC		0x00000040 +#define USART_ISR_TXE		0x00000080 +#define USART_ISR_TEACK		0x00200000 + +#define USART_TDR		0x28 + +	.globl	console_core_init +	.globl	console_core_putc +	.globl	console_core_getc +	.globl	console_core_flush + +	/* ----------------------------------------------------------------- +	 * int console_core_init(uintptr_t base_addr, +	 *			 unsigned int uart_clk, +	 *			 unsigned int baud_rate) +	 * +	 * Function to initialize the console without a C Runtime to print +	 * debug information. This function will be accessed by console_init +	 * and crash reporting. +	 * +	 * In: r0 - console base address +	 *     r1 - Uart clock in Hz +	 *     r2 - Baud rate +	 * Out: return 1 on success else 0 on error +	 * Clobber list : r1, r2, r3 +	 * ----------------------------------------------------------------- +	 */ +func console_core_init +	/* Check the input base address */ +	cmp	r0, #0 +	beq	core_init_fail +#if defined(IMAGE_BL2) +	/* Check baud rate and uart clock for sanity */ +	cmp	r1, #0 +	beq	core_init_fail +	cmp	r2, #0 +	beq	core_init_fail +	/* Disable UART */ +	ldr	r3, [r0, #USART_CR1] +	bic	r3, r3, #USART_CR1_UE +	str	r3, [r0, #USART_CR1] +	/* Configure UART */ +	orr	r3, r3, #(USART_CR1_TE | USART_CR1_FIFOEN) +	str	r3, [r0, #USART_CR1] +	ldr	r3, [r0, #USART_CR2] +	bic	r3, r3, #USART_CR2_STOP +	str	r3, [r0, #USART_CR2] +	/* Divisor =  (Uart clock + (baudrate / 2)) / baudrate */ +	lsl	r3, r2, #1 +	add	r3, r1, r3 +	udiv	r3, r3, r2 +	str	r3, [r0, #USART_BRR] +	/* Enable UART */ +	ldr	r3, [r0, #USART_CR1] +	orr	r3, r3, #USART_CR1_UE +	str	r3, [r0, #USART_CR1] +	/* Check TEACK bit */ +	mov	r2, #USART_TIMEOUT +teack_loop: +	subs	r2, r2, #1 +	beq	core_init_fail +	ldr	r3, [r0, #USART_ISR] +	tst	r3, #USART_ISR_TEACK +	beq	teack_loop +#endif /* IMAGE_BL2 */ +	mov	r0, #1 +	bx	lr +core_init_fail: +	mov	r0, #0 +	bx	lr +endfunc console_core_init + +	/* --------------------------------------------------------------- +	 * int console_core_putc(int c, uintptr_t base_addr) +	 * +	 * Function to output a character over the console. It returns the +	 * character printed on success or -1 on error. +	 * +	 * In : r0 - character to be printed +	 *      r1 - console base address +	 * Out : return -1 on error else return character. +	 * Clobber list : r2 +	 * --------------------------------------------------------------- +	 */ +func console_core_putc +	/* Check the input parameter */ +	cmp	r1, #0 +	beq	putc_error +	/* Prepend '\r' to '\n' */ +	cmp	r0, #0xA +	bne	2f +1: +	/* Check Transmit Data Register Empty */ +txe_loop_1: +	ldr	r2, [r1, #USART_ISR] +	tst	r2, #USART_ISR_TXE +	beq	txe_loop_1 +	mov	r2, #0xD +	str	r2, [r1, #USART_TDR] +	/* Check transmit complete flag */ +tc_loop_1: +	ldr	r2, [r1, #USART_ISR] +	tst	r2, #USART_ISR_TC +	beq	tc_loop_1 +2: +	/* Check Transmit Data Register Empty */ +txe_loop_2: +	ldr	r2, [r1, #USART_ISR] +	tst	r2, #USART_ISR_TXE +	beq	txe_loop_2 +	str	r0, [r1, #USART_TDR] +	/* Check transmit complete flag */ +tc_loop_2: +	ldr	r2, [r1, #USART_ISR] +	tst	r2, #USART_ISR_TC +	beq	tc_loop_2 +	bx	lr +putc_error: +	mov	r0, #-1 +	bx	lr +endfunc console_core_putc + +	/* ----------------------------------------------------------- +	 * int console_core_getc(uintptr_t base_addr) +	 * +	 * Function to get a character from the console. +	 * It returns the character grabbed on success or -1 on error. +	 * +	 * In : r0 - console base address +	 * Out : return -1. +	 * Clobber list : r0, r1 +	 * ----------------------------------------------------------- +	 */ +func console_core_getc +	/* Not supported */ +	mov	r0, #-1 +	bx	lr +endfunc console_core_getc + +	/* --------------------------------------------------------------- +	 * int console_core_flush(uintptr_t base_addr) +	 * +	 * Function to force a write of all buffered data that hasn't been +	 * output. +	 * +	 * In : r0 - console base address +	 * Out : return -1 on error else return 0. +	 * Clobber list : r0, r1 +	 * --------------------------------------------------------------- +	 */ +func console_core_flush +	cmp	r0, #0 +	beq	flush_error +	/* Check Transmit Data Register Empty */ +txe_loop_3: +	ldr	r1, [r0, #USART_ISR] +	tst	r1, #USART_ISR_TXE +	beq	txe_loop_3 +	mov	r0, #0 +	bx	lr +flush_error: +	mov	r0, #-1 +	bx	lr +endfunc console_core_flush diff --git a/fdts/stm32mp15-ddr.dtsi b/fdts/stm32mp15-ddr.dtsi new file mode 100644 index 00000000..be4e2c37 --- /dev/null +++ b/fdts/stm32mp15-ddr.dtsi @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +/ { +	soc { +		ddr: ddr@0x5A003000{ + +			compatible = "st,stm32mp1-ddr"; + +			reg = <0x5A003000 0x550 +			       0x5A004000 0x234>; + +			clocks = <&rcc AXIDCG>, +				 <&rcc DDRC1>, +				 <&rcc DDRC2>, +				 <&rcc DDRPHYC>, +				 <&rcc DDRCAPB>, +				 <&rcc DDRPHYCAPB>; + +			clock-names = "axidcg", +				      "ddrc1", +				      "ddrc2", +				      "ddrphyc", +				      "ddrcapb", +				      "ddrphycapb"; + +			st,mem-name = DDR_MEM_NAME; +			st,mem-speed = <DDR_MEM_SPEED>; +			st,mem-size = <DDR_MEM_SIZE>; + +			st,ctl-reg = < +				DDR_MSTR +				DDR_MRCTRL0 +				DDR_MRCTRL1 +				DDR_DERATEEN +				DDR_DERATEINT +				DDR_PWRCTL +				DDR_PWRTMG +				DDR_HWLPCTL +				DDR_RFSHCTL0 +				DDR_RFSHCTL3 +				DDR_CRCPARCTL0 +				DDR_ZQCTL0 +				DDR_DFITMG0 +				DDR_DFITMG1 +				DDR_DFILPCFG0 +				DDR_DFIUPD0 +				DDR_DFIUPD1 +				DDR_DFIUPD2 +				DDR_DFIPHYMSTR +				DDR_ODTMAP +				DDR_DBG0 +				DDR_DBG1 +				DDR_DBGCMD +				DDR_POISONCFG +				DDR_PCCFG +			>; + +			st,ctl-timing = < +				DDR_RFSHTMG +				DDR_DRAMTMG0 +				DDR_DRAMTMG1 +				DDR_DRAMTMG2 +				DDR_DRAMTMG3 +				DDR_DRAMTMG4 +				DDR_DRAMTMG5 +				DDR_DRAMTMG6 +				DDR_DRAMTMG7 +				DDR_DRAMTMG8 +				DDR_DRAMTMG14 +				DDR_ODTCFG +			>; + +			st,ctl-map = < +				DDR_ADDRMAP1 +				DDR_ADDRMAP2 +				DDR_ADDRMAP3 +				DDR_ADDRMAP4 +				DDR_ADDRMAP5 +				DDR_ADDRMAP6 +				DDR_ADDRMAP9 +				DDR_ADDRMAP10 +				DDR_ADDRMAP11 +			>; + +			st,ctl-perf = < +				DDR_SCHED +				DDR_SCHED1 +				DDR_PERFHPR1 +				DDR_PERFLPR1 +				DDR_PERFWR1 +				DDR_PCFGR_0 +				DDR_PCFGW_0 +				DDR_PCFGQOS0_0 +				DDR_PCFGQOS1_0 +				DDR_PCFGWQOS0_0 +				DDR_PCFGWQOS1_0 +				DDR_PCFGR_1 +				DDR_PCFGW_1 +				DDR_PCFGQOS0_1 +				DDR_PCFGQOS1_1 +				DDR_PCFGWQOS0_1 +				DDR_PCFGWQOS1_1 +			>; + +			st,phy-reg = < +				DDR_PGCR +				DDR_ACIOCR +				DDR_DXCCR +				DDR_DSGCR +				DDR_DCR +				DDR_ODTCR +				DDR_ZQ0CR1 +				DDR_DX0GCR +				DDR_DX1GCR +				DDR_DX2GCR +				DDR_DX3GCR +			>; + +			st,phy-timing = < +				DDR_PTR0 +				DDR_PTR1 +				DDR_PTR2 +				DDR_DTPR0 +				DDR_DTPR1 +				DDR_DTPR2 +				DDR_MR0 +				DDR_MR1 +				DDR_MR2 +				DDR_MR3 +			>; + +			st,phy-cal = < +				DDR_DX0DLLCR +				DDR_DX0DQTR +				DDR_DX0DQSTR +				DDR_DX1DLLCR +				DDR_DX1DQTR +				DDR_DX1DQSTR +				DDR_DX2DLLCR +				DDR_DX2DQTR +				DDR_DX2DQSTR +				DDR_DX3DLLCR +				DDR_DX3DQTR +				DDR_DX3DQSTR +			>; + +			status = "okay"; +		}; +	}; +}; diff --git a/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi b/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi new file mode 100644 index 00000000..58a4cdc8 --- /dev/null +++ b/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +/* STM32MP157C ED1 and ED2 BOARD configuration + * 2x DDR3L 4Gb each, 16-bit, 533MHz, Single Die Package in flyby topology. + * Reference used NT5CC256M16DP-DI from NANYA + * + * DDR type / Platform	DDR3/3L + * freq		533MHz + * width	32 + * datasheet	0  = MT41J256M16-187 / DDR3-1066 bin G + * DDR density	8 + * timing mode	optimized + * Scheduling/QoS options : type = 2 + * address mapping : RBC + */ + +#define DDR_MEM_NAME "DDR3-1066 bin G 2x4Gb 533MHz v1.39" +#define DDR_MEM_SPEED 533 +#define DDR_MEM_SIZE 0x40000000 + +#define DDR_MSTR 0x00040401 +#define DDR_MRCTRL0 0x00000010 +#define DDR_MRCTRL1 0x00000000 +#define DDR_DERATEEN 0x00000000 +#define DDR_DERATEINT 0x00800000 +#define DDR_PWRCTL 0x00000000 +#define DDR_PWRTMG 0x00400010 +#define DDR_HWLPCTL 0x00000000 +#define DDR_RFSHCTL0 0x00210000 +#define DDR_RFSHCTL3 0x00000000 +#define DDR_RFSHTMG 0x0081008B +#define DDR_CRCPARCTL0 0x00000000 +#define DDR_DRAMTMG0 0x121B2414 +#define DDR_DRAMTMG1 0x000A041C +#define DDR_DRAMTMG2 0x0608090F +#define DDR_DRAMTMG3 0x0050400C +#define DDR_DRAMTMG4 0x08040608 +#define DDR_DRAMTMG5 0x06060403 +#define DDR_DRAMTMG6 0x02020002 +#define DDR_DRAMTMG7 0x00000202 +#define DDR_DRAMTMG8 0x00001005 +#define DDR_DRAMTMG14 0x000000A0 +#define DDR_ZQCTL0 0xC2000040 +#define DDR_DFITMG0 0x02060105 +#define DDR_DFITMG1 0x00000202 +#define DDR_DFILPCFG0 0x07000000 +#define DDR_DFIUPD0 0xC0400003 +#define DDR_DFIUPD1 0x00000000 +#define DDR_DFIUPD2 0x00000000 +#define DDR_DFIPHYMSTR 0x00000000 +#define DDR_ADDRMAP1 0x00080808 +#define DDR_ADDRMAP2 0x00000000 +#define DDR_ADDRMAP3 0x00000000 +#define DDR_ADDRMAP4 0x00001F1F +#define DDR_ADDRMAP5 0x07070707 +#define DDR_ADDRMAP6 0x0F070707 +#define DDR_ADDRMAP9 0x00000000 +#define DDR_ADDRMAP10 0x00000000 +#define DDR_ADDRMAP11 0x00000000 +#define DDR_ODTCFG 0x06000600 +#define DDR_ODTMAP 0x00000001 +#define DDR_SCHED 0x00001201 +#define DDR_SCHED1 0x00000000 +#define DDR_PERFHPR1 0x01000001 +#define DDR_PERFLPR1 0x08000200 +#define DDR_PERFWR1 0x08000400 +#define DDR_DBG0 0x00000000 +#define DDR_DBG1 0x00000000 +#define DDR_DBGCMD 0x00000000 +#define DDR_POISONCFG 0x00000000 +#define DDR_PCCFG 0x00000010 +#define DDR_PCFGR_0 0x00010000 +#define DDR_PCFGW_0 0x00000000 +#define DDR_PCFGQOS0_0 0x02100B03 +#define DDR_PCFGQOS1_0 0x00800100 +#define DDR_PCFGWQOS0_0 0x01100B03 +#define DDR_PCFGWQOS1_0 0x01000200 +#define DDR_PCFGR_1 0x00010000 +#define DDR_PCFGW_1 0x00000000 +#define DDR_PCFGQOS0_1 0x02100B03 +#define DDR_PCFGQOS1_1 0x00800000 +#define DDR_PCFGWQOS0_1 0x01100B03 +#define DDR_PCFGWQOS1_1 0x01000200 +#define DDR_PGCR 0x01442E02 +#define DDR_PTR0 0x0022AA5B +#define DDR_PTR1 0x04841104 +#define DDR_PTR2 0x042DA068 +#define DDR_ACIOCR 0x10400812 +#define DDR_DXCCR 0x00000C40 +#define DDR_DSGCR 0xF200001F +#define DDR_DCR 0x0000000B +#define DDR_DTPR0 0x38D488D0 +#define DDR_DTPR1 0x098B00D8 +#define DDR_DTPR2 0x10023600 +#define DDR_MR0 0x00000840 +#define DDR_MR1 0x00000000 +#define DDR_MR2 0x00000208 +#define DDR_MR3 0x00000000 +#define DDR_ODTCR 0x00010000 +#define DDR_ZQ0CR1 0x00000038 +#define DDR_DX0GCR 0x0000CE81 +#define DDR_DX0DLLCR 0x40000000 +#define DDR_DX0DQTR 0xFFFFFFFF +#define DDR_DX0DQSTR 0x3DB02000 +#define DDR_DX1GCR 0x0000CE81 +#define DDR_DX1DLLCR 0x40000000 +#define DDR_DX1DQTR 0xFFFFFFFF +#define DDR_DX1DQSTR 0x3DB02000 +#define DDR_DX2GCR 0x0000CE81 +#define DDR_DX2DLLCR 0x40000000 +#define DDR_DX2DQTR 0xFFFFFFFF +#define DDR_DX2DQSTR 0x3DB02000 +#define DDR_DX3GCR 0x0000CE81 +#define DDR_DX3DLLCR 0x40000000 +#define DDR_DX3DQTR 0xFFFFFFFF +#define DDR_DX3DQSTR 0x3DB02000 + +#include "stm32mp15-ddr.dtsi" diff --git a/fdts/stm32mp157-pinctrl.dtsi b/fdts/stm32mp157-pinctrl.dtsi new file mode 100644 index 00000000..21bd34e0 --- /dev/null +++ b/fdts/stm32mp157-pinctrl.dtsi @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2017 - All Rights Reserved + * Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics. + */ + +#include <dt-bindings/pinctrl/stm32-pinfunc.h> +/ { +	soc { +		pinctrl: pin-controller { +			#address-cells = <1>; +			#size-cells = <1>; +			ranges = <0 0x50002000 0xa400>; +			pins-are-numbered; + +			gpioa: gpio@50002000 { +				gpio-controller; +				#gpio-cells = <2>; +				interrupt-controller; +				#interrupt-cells = <2>; +				reg = <0x0 0x400>; +				clocks = <&rcc GPIOA>; +				st,bank-name = "GPIOA"; +				status = "disabled"; +			}; + +			gpiob: gpio@50003000 { +				gpio-controller; +				#gpio-cells = <2>; +				interrupt-controller; +				#interrupt-cells = <2>; +				reg = <0x1000 0x400>; +				clocks = <&rcc GPIOB>; +				st,bank-name = "GPIOB"; +				status = "disabled"; +			}; + +			gpioc: gpio@50004000 { +				gpio-controller; +				#gpio-cells = <2>; +				interrupt-controller; +				#interrupt-cells = <2>; +				reg = <0x2000 0x400>; +				clocks = <&rcc GPIOC>; +				st,bank-name = "GPIOC"; +				status = "disabled"; +			}; + +			gpiod: gpio@50005000 { +				gpio-controller; +				#gpio-cells = <2>; +				interrupt-controller; +				#interrupt-cells = <2>; +				reg = <0x3000 0x400>; +				clocks = <&rcc GPIOD>; +				st,bank-name = "GPIOD"; +				status = "disabled"; +			}; + +			gpioe: gpio@50006000 { +				gpio-controller; +				#gpio-cells = <2>; +				interrupt-controller; +				#interrupt-cells = <2>; +				reg = <0x4000 0x400>; +				clocks = <&rcc GPIOE>; +				st,bank-name = "GPIOE"; +				status = "disabled"; +			}; + +			gpiof: gpio@50007000 { +				gpio-controller; +				#gpio-cells = <2>; +				interrupt-controller; +				#interrupt-cells = <2>; +				reg = <0x5000 0x400>; +				clocks = <&rcc GPIOF>; +				st,bank-name = "GPIOF"; +				status = "disabled"; +			}; + +			gpiog: gpio@50008000 { +				gpio-controller; +				#gpio-cells = <2>; +				interrupt-controller; +				#interrupt-cells = <2>; +				reg = <0x6000 0x400>; +				clocks = <&rcc GPIOG>; +				st,bank-name = "GPIOG"; +				status = "disabled"; +			}; + +			gpioh: gpio@50009000 { +				gpio-controller; +				#gpio-cells = <2>; +				interrupt-controller; +				#interrupt-cells = <2>; +				reg = <0x7000 0x400>; +				clocks = <&rcc GPIOH>; +				st,bank-name = "GPIOH"; +				status = "disabled"; +			}; + +			gpioi: gpio@5000a000 { +				gpio-controller; +				#gpio-cells = <2>; +				interrupt-controller; +				#interrupt-cells = <2>; +				reg = <0x8000 0x400>; +				clocks = <&rcc GPIOI>; +				st,bank-name = "GPIOI"; +				status = "disabled"; +			}; + +			gpioj: gpio@5000b000 { +				gpio-controller; +				#gpio-cells = <2>; +				interrupt-controller; +				#interrupt-cells = <2>; +				reg = <0x9000 0x400>; +				clocks = <&rcc GPIOJ>; +				st,bank-name = "GPIOJ"; +				status = "disabled"; +			}; + +			gpiok: gpio@5000c000 { +				gpio-controller; +				#gpio-cells = <2>; +				interrupt-controller; +				#interrupt-cells = <2>; +				reg = <0xa000 0x400>; +				clocks = <&rcc GPIOK>; +				st,bank-name = "GPIOK"; +				status = "disabled"; +			}; + +			uart4_pins_a: uart4@0 { +				pins1 { +					pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */ +					bias-disable; +					drive-push-pull; +					slew-rate = <0>; +				}; +				pins2 { +					pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */ +					bias-disable; +				}; +			}; + +			usart3_pins_a: usart3@0 { +				pins1 { +					pinmux = <STM32_PINMUX('B', 10, AF7)>, /* USART3_TX */ +						 <STM32_PINMUX('G', 8, AF8)>; /* USART3_RTS */ +					bias-disable; +					drive-push-pull; +					slew-rate = <0>; +				}; +				pins2 { +					pinmux = <STM32_PINMUX('B', 12, AF8)>, /* USART3_RX */ +						 <STM32_PINMUX('I', 10, AF8)>; /* USART3_CTS_NSS */ +					bias-disable; +				}; +			}; + +			sdmmc1_b4_pins_a: sdmmc1-b4@0 { +				pins { +					pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */ +						 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */ +						 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */ +						 <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */ +						 <STM32_PINMUX('C', 12, AF12)>, /* SDMMC1_CK */ +						 <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */ +					slew-rate = <3>; +					drive-push-pull; +					bias-disable; +				}; +			}; + +			sdmmc1_dir_pins_a: sdmmc1-dir@0 { +				pins1 { +					pinmux = <STM32_PINMUX('F', 2, AF11)>, /* SDMMC1_D0DIR */ +						 <STM32_PINMUX('C', 7, AF8)>, /* SDMMC1_D123DIR */ +						 <STM32_PINMUX('B', 9, AF11)>; /* SDMMC1_CDIR */ +					slew-rate = <3>; +					drive-push-pull; +					bias-pull-up; +				}; +				pins2{ +					pinmux = <STM32_PINMUX('E', 4, AF8)>; /* SDMMC1_CKIN */ +					bias-pull-up; +				}; +			}; + +			sdmmc2_b4_pins_a: sdmmc2-b4@0 { +				pins { +					pinmux = <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */ +						 <STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */ +						 <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */ +						 <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */ +						 <STM32_PINMUX('E', 3, AF9)>, /* SDMMC2_CK */ +						 <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */ +					slew-rate = <3>; +					drive-push-pull; +					bias-pull-up; +				}; +			}; + +			sdmmc2_d47_pins_a: sdmmc2-d47@0 { +				pins { +					pinmux = <STM32_PINMUX('A', 8, AF9)>, /* SDMMC2_D4 */ +						 <STM32_PINMUX('A', 9, AF10)>, /* SDMMC2_D5 */ +						 <STM32_PINMUX('E', 5, AF9)>, /* SDMMC2_D6 */ +						 <STM32_PINMUX('D', 3, AF9)>; /* SDMMC2_D7 */ +					slew-rate = <3>; +					drive-push-pull; +					bias-pull-up; +				}; +			}; +		}; + +		pinctrl_z: pin-controller-z { +			#address-cells = <1>; +			#size-cells = <1>; +			ranges = <0 0x54004000 0x400>; +			pins-are-numbered; + +			gpioz: gpio@54004000 { +				gpio-controller; +				#gpio-cells = <2>; +				interrupt-controller; +				#interrupt-cells = <2>; +				reg = <0 0x400>; +				clocks = <&rcc GPIOZ>; +				st,bank-name = "GPIOZ"; +				st,bank-ioport = <11>; +				status = "disabled"; +			}; + +			i2c4_pins_a: i2c4@0 { +				pins { +					pinmux = <STM32_PINMUX('Z', 4, AF6)>, /* I2C4_SCL */ +						 <STM32_PINMUX('Z', 5, AF6)>; /* I2C4_SDA */ +					bias-disable; +					drive-open-drain; +					slew-rate = <0>; +				}; +			}; +		}; +	}; +}; diff --git a/fdts/stm32mp157c-ed1.dts b/fdts/stm32mp157c-ed1.dts new file mode 100644 index 00000000..e3dabe8b --- /dev/null +++ b/fdts/stm32mp157c-ed1.dts @@ -0,0 +1,246 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2017 - All Rights Reserved + * Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics. + */ + +/dts-v1/; + +#include "stm32mp157c.dtsi" +#include "stm32mp157caa-pinctrl.dtsi" + +/ { +	model = "STMicroelectronics STM32MP157C-ED1 pmic eval daughter"; +	compatible = "st,stm32mp157c-ed1", "st,stm32mp157"; + +	chosen { +		bootargs = "earlyprintk console=ttyS3,115200 root=/dev/ram"; +		stdout-path = "serial3:115200n8"; +	}; +}; + +&i2c4 { +	pinctrl-names = "default"; +	pinctrl-0 = <&i2c4_pins_a>; +	i2c-scl-rising-time-ns = <185>; +	i2c-scl-falling-time-ns = <20>; +	status = "okay"; + +	pmic: stpmu1@33 { +		compatible = "st,stpmu1"; +		reg = <0x33>; +		status = "okay"; + +		st,main_control_register = <0x04>; +		st,vin_control_register = <0xc0>; +		st,usb_control_register = <0x30>; + +		regulators { +			compatible = "st,stpmu1-regulators"; + +			v3v3: buck4 { +				regulator-name = "v3v3"; +				regulator-min-microvolt = <3300000>; +				regulator-max-microvolt = <3300000>; +				regulator-boot-on; +				regulator-over-current-protection; +				regulator-initial-mode = <8>; + +				regulator-state-standby { +					regulator-suspend-microvolt = <3300000>; +					regulator-unchanged-in-suspend; +					regulator-mode = <8>; +				}; +				regulator-state-mem { +					regulator-off-in-suspend; +				}; +				regulator-state-disk { +					regulator-off-in-suspend; +				}; +			}; + +			vdd_sd: ldo5 { +				regulator-name = "vdd_sd"; +				regulator-min-microvolt = <2900000>; +				regulator-max-microvolt = <2900000>; +				regulator-boot-on; + +				regulator-state-standby { +					regulator-suspend-microvolt = <2900000>; +					regulator-unchanged-in-suspend; +				}; +				regulator-state-mem { +					regulator-off-in-suspend; +				}; +				regulator-state-disk { +					regulator-off-in-suspend; +				}; +			}; +		}; +	}; +}; + +&iwdg2 { +	instance = <2>; +	timeout-sec = <32>; +	status = "okay"; +}; + +&rng1 { +	status = "okay"; +}; + +&sdmmc1 { +	pinctrl-names = "default"; +	pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_a>; +	broken-cd; +	st,dirpol; +	st,negedge; +	st,pin-ckin; +	bus-width = <4>; +	sd-uhs-sdr12; +	sd-uhs-sdr25; +	sd-uhs-sdr50; +	sd-uhs-ddr50; +	sd-uhs-sdr104; +	status = "okay"; +}; + +&sdmmc2 { +	pinctrl-names = "default"; +	pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_d47_pins_a>; +	non-removable; +	no-sd; +	no-sdio; +	st,dirpol; +	st,negedge; +	bus-width = <8>; +	status = "okay"; +}; + +&uart4 { +	pinctrl-names = "default"; +	pinctrl-0 = <&uart4_pins_a>; +	resets = <&rcc UART4_R>; +	status = "okay"; +}; + +/* ATF Specific */ +#include <dt-bindings/clock/stm32mp1-clksrc.h> +#include "stm32mp15-ddr3-2x4Gb-1066-binG.dtsi" + +/ { +	aliases { +		gpio0 = &gpioa; +		gpio1 = &gpiob; +		gpio2 = &gpioc; +		gpio3 = &gpiod; +		gpio4 = &gpioe; +		gpio5 = &gpiof; +		gpio6 = &gpiog; +		gpio7 = &gpioh; +		gpio8 = &gpioi; +		gpio9 = &gpioj; +		gpio10 = &gpiok; +		gpio25 = &gpioz; +		i2c3 = &i2c4; +	}; + +	soc { +		stgen: stgen@5C008000 { +			compatible = "st,stm32-stgen"; +			reg = <0x5C008000 0x1000>; +			status = "okay"; +		}; +	}; +}; + +/* CLOCK init */ +&rcc { +	st,clksrc = < +		CLK_MPU_PLL1P +		CLK_AXI_PLL2P +		CLK_PLL12_HSE +		CLK_PLL3_HSE +		CLK_PLL4_HSE +		CLK_RTC_LSE +		CLK_MCO1_DISABLED +		CLK_MCO2_DISABLED +	>; + +	st,clkdiv = < +		1 /*MPU*/ +		0 /*AXI*/ +		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_PLL3R +		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_PLL3R +		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_PLL3Q +		CLK_FDCAN_PLL4Q +		CLK_SAI1_PLL3Q +		CLK_SAI2_PLL3Q +		CLK_SAI3_PLL3Q +		CLK_SAI4_PLL3Q +		CLK_RNG1_CSI +		CLK_RNG2_CSI +		CLK_LPTIM1_PCLK1 +		CLK_LPTIM23_PCLK3 +		CLK_LPTIM45_PCLK3 +	>; + +	/* VCO = 1300.0 MHz => P = 650 (CPU) */ +	pll1: st,pll@0 { +		cfg = < 2 80 0 0 0 PQR(1,0,0) >; +		frac = < 0x800 >; +	}; + +	/* 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 >; +	}; + +	/* VCO = 786.4 MHz => P = 197, Q = 49, R = 98 */ +	pll3: st,pll@2 { +		cfg = < 2 97 3 15 7 PQR(1,1,1) >; +		frac = < 0x9ba >; +	}; + +	/* VCO = 508.0 MHz => P = 56, Q = 56, R = 56 */ +	pll4: st,pll@3 { +		cfg = < 5 126 8 8 8 PQR(1,1,1) >; +	}; +}; + +/delete-node/ &clk_csi; diff --git a/fdts/stm32mp157c-ev1.dts b/fdts/stm32mp157c-ev1.dts new file mode 100644 index 00000000..98a9d350 --- /dev/null +++ b/fdts/stm32mp157c-ev1.dts @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2017 - All Rights Reserved + * Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics. + */ + +/dts-v1/; +#include "stm32mp157c-ed1.dts" + +/ { +	model = "STMicroelectronics STM32MP157C-EV1 pmic eval daughter on eval mother"; +	compatible = "st,stm32mp157c-ev1", "st,stm32mp157c-ed1", "st,stm32mp157"; + +	chosen { +		bootargs = "earlyprintk console=ttyS3,115200 root=/dev/ram"; +		stdout-path = "serial3:115200n8"; +	}; +}; + +&usart3 { +	pinctrl-names = "default"; +	pinctrl-0 = <&usart3_pins_a>; +	resets = <&rcc USART3_R>; +	status = "disabled"; +}; diff --git a/fdts/stm32mp157c.dtsi b/fdts/stm32mp157c.dtsi new file mode 100644 index 00000000..8b13c0e3 --- /dev/null +++ b/fdts/stm32mp157c.dtsi @@ -0,0 +1,240 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2017 - All Rights Reserved + * Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics. + */ + +#include <dt-bindings/clock/stm32mp1-clks.h> +#include <dt-bindings/reset/stm32mp1-resets.h> + +/ { +	#address-cells = <1>; +	#size-cells = <1>; + +	aliases { +		serial0 = &usart1; +		serial1 = &usart2; +		serial2 = &usart3; +		serial3 = &uart4; +		serial4 = &uart5; +		serial5 = &usart6; +		serial6 = &uart7; +		serial7 = &uart8; +	}; + +	clocks { +		clk_hse: clk-hse { +			#clock-cells = <0>; +			compatible = "fixed-clock"; +			clock-frequency = <24000000>; +		}; + +		clk_hsi: clk-hsi { +			#clock-cells = <0>; +			compatible = "fixed-clock"; +			clock-frequency = <64000000>; +		}; + +		clk_lse: clk-lse { +			#clock-cells = <0>; +			compatible = "fixed-clock"; +			clock-frequency = <32768>; +		}; + +		clk_lsi: clk-lsi { +			#clock-cells = <0>; +			compatible = "fixed-clock"; +			clock-frequency = <32000>; +		}; + +		clk_csi: clk-csi { +			#clock-cells = <0>; +			compatible = "fixed-clock"; +			clock-frequency = <4000000>; +		}; + +		clk_i2s_ckin: i2s_ckin { +			#clock-cells = <0>; +			compatible = "fixed-clock"; +			clock-frequency = <64000000>; +		}; + +		clk_dsi_phy: ck_dsi_phy { +			#clock-cells = <0>; +			compatible = "fixed-clock"; +			clock-frequency = <0>; +		}; + +		clk_usbo_48m: ck_usbo_48m { +			#clock-cells = <0>; +			compatible = "fixed-clock"; +			clock-frequency = <48000000>; +		}; +	}; + +	soc { +		compatible = "simple-bus"; +		#address-cells = <1>; +		#size-cells = <1>; +		ranges; + +		usart2: serial@4000e000 { +			compatible = "st,stm32h7-usart"; +			reg = <0x4000e000 0x400>; +			clocks = <&rcc USART2_K>; +			status = "disabled"; +		}; + +		usart3: serial@4000f000 { +			compatible = "st,stm32h7-usart"; +			reg = <0x4000f000 0x400>; +			clocks = <&rcc USART3_K>; +			status = "disabled"; +		}; + +		uart4: serial@40010000 { +			compatible = "st,stm32h7-uart"; +			reg = <0x40010000 0x400>; +			clocks = <&rcc UART4_K>; +			status = "disabled"; +		}; + +		uart5: serial@40011000 { +			compatible = "st,stm32h7-uart"; +			reg = <0x40011000 0x400>; +			clocks = <&rcc UART5_K>; +			status = "disabled"; +		}; + + +		uart7: serial@40018000 { +			compatible = "st,stm32h7-uart"; +			reg = <0x40018000 0x400>; +			clocks = <&rcc UART7_K>; +			status = "disabled"; +		}; + +		uart8: serial@40019000 { +			compatible = "st,stm32h7-uart"; +			reg = <0x40019000 0x400>; +			clocks = <&rcc UART8_K>; +			status = "disabled"; +		}; + +		usart6: serial@44003000 { +			compatible = "st,stm32h7-usart"; +			reg = <0x44003000 0x400>; +			clocks = <&rcc USART6_K>; +			status = "disabled"; +		}; + +		sdmmc3: sdmmc@48004000 { +			compatible = "st,stm32-sdmmc2"; +			reg = <0x48004000 0x400>, <0x48005000 0x400>; +			reg-names = "sdmmc", "delay"; +			clocks = <&rcc SDMMC3_K>; +			resets = <&rcc SDMMC3_R>; +			cap-sd-highspeed; +			cap-mmc-highspeed; +			max-frequency = <120000000>; +			status = "disabled"; +		}; + +		rcc: rcc@50000000 { +			compatible = "syscon", "st,stm32mp1-rcc"; +			#clock-cells = <1>; +			#reset-cells = <1>; +			reg = <0x50000000 0x1000>; +		}; + +		rcc_reboot: rcc-reboot@50000000 { +				compatible = "syscon-reboot"; +				regmap = <&rcc>; +				offset = <0x404>; +				mask = <0x1>; +		}; + +		rng1: rng@54003000 { +			compatible = "st,stm32-rng"; +			reg = <0x54003000 0x400>; +			clocks = <&rcc RNG1_K>; +			resets = <&rcc RNG1_R>; +			status = "disabled"; +		}; + +		fmc_nand: fmc_nand@58002000 { +			compatible = "st,stm32mp1-fmc"; +			reg = <0x58002000 0x1000>, +			      <0x80000000 0x40000>, +			      <0x81000000 0x40000>, +			      <0x88000000 0x40000>, +			      <0x89000000 0x40000>; +			clocks = <&rcc FMC_K>; +			resets = <&rcc FMC_R>; +			status = "disabled"; +		}; + +		qspi: qspi@58003000 { +			compatible = "st,stm32f469-qspi"; +			reg = <0x58003000 0x1000>, <0x70000000 0x10000000>; +			clocks = <&rcc QSPI_K>; +			status = "disabled"; +		}; + +		sdmmc1: sdmmc@58005000 { +			compatible = "st,stm32-sdmmc2"; +			reg = <0x58005000 0x1000>, <0x58006000 0x1000>; +			reg-names = "sdmmc", "delay"; +			clocks = <&rcc SDMMC1_K>; +			resets = <&rcc SDMMC1_R>; +			cap-sd-highspeed; +			cap-mmc-highspeed; +			max-frequency = <120000000>; +			status = "disabled"; +		}; + +		sdmmc2: sdmmc@58007000 { +			compatible = "st,stm32-sdmmc2"; +			reg = <0x58007000 0x1000>, <0x58008000 0x1000>; +			reg-names = "sdmmc", "delay"; +			clocks = <&rcc SDMMC2_K>; +			resets = <&rcc SDMMC2_R>; +			cap-sd-highspeed; +			cap-mmc-highspeed; +			max-frequency = <120000000>; +			status = "disabled"; +		}; + +		iwdg2: iwdg@5a002000 { +			compatible = "st,stm32mp1-iwdg"; +			reg = <0x5a002000 0x400>; +			clocks = <&rcc IWDG2>, <&rcc CK_LSI>; +			clock-names = "pclk", "lsi"; +			status = "disabled"; +		}; + +		usart1: serial@5c000000 { +			compatible = "st,stm32h7-usart"; +			reg = <0x5c000000 0x400>; +			clocks = <&rcc USART1_K>; +			status = "disabled"; +		}; + +		i2c4: i2c@5c002000 { +			compatible = "st,stm32f7-i2c"; +			reg = <0x5c002000 0x400>; +			clocks = <&rcc I2C4_K>; +			resets = <&rcc I2C4_R>; +			#address-cells = <1>; +			#size-cells = <0>; +			status = "disabled"; +		}; + +		rtc: rtc@5c004000 { +			compatible = "st,stm32mp1-rtc"; +			reg = <0x5c004000 0x400>; +			clocks = <&rcc RTCAPB>, <&rcc RTC>; +			clock-names = "pclk", "rtc_ck"; +		}; +	}; +}; diff --git a/fdts/stm32mp157caa-pinctrl.dtsi b/fdts/stm32mp157caa-pinctrl.dtsi new file mode 100644 index 00000000..774561ae --- /dev/null +++ b/fdts/stm32mp157caa-pinctrl.dtsi @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + * Author: Alexandre Torgue <alexandre.torgue@st.com> + */ + +#include "stm32mp157-pinctrl.dtsi" +/ { +	soc { +		pinctrl: pin-controller { +			compatible = "st,stm32mp157caa-pinctrl"; + +			gpioa: gpio@50002000 { +				status = "okay"; +				ngpios = <16>; +				gpio-ranges = <&pinctrl 0 0 16>; +			}; + +			gpiob: gpio@50003000 { +				status = "okay"; +				ngpios = <16>; +				gpio-ranges = <&pinctrl 0 16 16>; +			}; + +			gpioc: gpio@50004000 { +				status = "okay"; +				ngpios = <16>; +				gpio-ranges = <&pinctrl 0 32 16>; +			}; + +			gpiod: gpio@50005000 { +				status = "okay"; +				ngpios = <16>; +				gpio-ranges = <&pinctrl 0 48 16>; +			}; + +			gpioe: gpio@50006000 { +				status = "okay"; +				ngpios = <16>; +				gpio-ranges = <&pinctrl 0 64 16>; +			}; + +			gpiof: gpio@50007000 { +				status = "okay"; +				ngpios = <16>; +				gpio-ranges = <&pinctrl 0 80 16>; +			}; + +			gpiog: gpio@50008000 { +				status = "okay"; +				ngpios = <16>; +				gpio-ranges = <&pinctrl 0 96 16>; +			}; + +			gpioh: gpio@50009000 { +				status = "okay"; +				ngpios = <16>; +				gpio-ranges = <&pinctrl 0 112 16>; +			}; + +			gpioi: gpio@5000a000 { +				status = "okay"; +				ngpios = <16>; +				gpio-ranges = <&pinctrl 0 128 16>; +			}; + +			gpioj: gpio@5000b000 { +				status = "okay"; +				ngpios = <16>; +				gpio-ranges = <&pinctrl 0 144 16>; +			}; + +			gpiok: gpio@5000c000 { +				status = "okay"; +				ngpios = <8>; +				gpio-ranges = <&pinctrl 0 160 8>; +			}; +		}; + +		pinctrl_z: pin-controller-z { +			compatible = "st,stm32mp157caa-z-pinctrl"; + +			gpioz: gpio@54004000 { +				status = "okay"; +				ngpios = <8>; +				gpio-ranges = <&pinctrl_z 0 400 8>; +			}; +		}; +	}; +}; diff --git a/include/drivers/st/stm32_gpio.h b/include/drivers/st/stm32_gpio.h new file mode 100644 index 00000000..7a5ccd37 --- /dev/null +++ b/include/drivers/st/stm32_gpio.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2015-2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __PLAT_GPIO_H__ +#define __PLAT_GPIO_H__ + +#include <utils_def.h> + +#define STM32_GPIOA_BANK	U(0x50002000) +#define STM32_GPIOZ_BANK	U(0x54004000) +#define STM32_GPIO_BANK_OFFSET	U(0x1000) + +#define GPIO_MODE_OFFSET	U(0x00) +#define GPIO_TYPE_OFFSET	U(0x04) +#define GPIO_SPEED_OFFSET	U(0x08) +#define GPIO_PUPD_OFFSET	U(0x0C) +#define GPIO_BSRR_OFFSET	U(0x18) +#define GPIO_AFRL_OFFSET	U(0x20) +#define GPIO_AFRH_OFFSET	U(0x24) + +#define GPIO_ALT_LOWER_LIMIT	U(0x08) + +#define GPIO_BANK_A		U(0x00) +#define GPIO_BANK_B		U(0x01) +#define GPIO_BANK_C		U(0x02) +#define GPIO_BANK_D		U(0x03) +#define GPIO_BANK_E		U(0x04) +#define GPIO_BANK_F		U(0x05) +#define GPIO_BANK_G		U(0x06) +#define GPIO_BANK_H		U(0x07) +#define GPIO_BANK_I		U(0x08) +#define GPIO_BANK_J		U(0x09) +#define GPIO_BANK_K		U(0x0A) +#define GPIO_BANK_Z		U(0x19) + +#define GPIO_PIN_0		U(0x00) +#define GPIO_PIN_1		U(0x01) +#define GPIO_PIN_2		U(0x02) +#define GPIO_PIN_3		U(0x03) +#define GPIO_PIN_4		U(0x04) +#define GPIO_PIN_5		U(0x05) +#define GPIO_PIN_6		U(0x06) +#define GPIO_PIN_7		U(0x07) +#define GPIO_PIN_8		U(0x08) +#define GPIO_PIN_9		U(0x09) +#define GPIO_PIN_10		U(0x0A) +#define GPIO_PIN_11		U(0x0B) +#define GPIO_PIN_12		U(0x0C) +#define GPIO_PIN_13		U(0x0D) +#define GPIO_PIN_14		U(0x0E) +#define GPIO_PIN_15		U(0x0F) +#define GPIO_PIN_MAX		GPIO_PIN_15 + +#define GPIO_ALTERNATE_0	0x00 +#define GPIO_ALTERNATE_1	0x01 +#define GPIO_ALTERNATE_2	0x02 +#define GPIO_ALTERNATE_3	0x03 +#define GPIO_ALTERNATE_4	0x04 +#define GPIO_ALTERNATE_5	0x05 +#define GPIO_ALTERNATE_6	0x06 +#define GPIO_ALTERNATE_7	0x07 +#define GPIO_ALTERNATE_8	0x08 +#define GPIO_ALTERNATE_9	0x09 +#define GPIO_ALTERNATE_10	0x0A +#define GPIO_ALTERNATE_11	0x0B +#define GPIO_ALTERNATE_12	0x0C +#define GPIO_ALTERNATE_13	0x0D +#define GPIO_ALTERNATE_14	0x0E +#define GPIO_ALTERNATE_15	0x0F +#define GPIO_ALTERNATE_MASK	U(0x0F) + +#define GPIO_MODE_INPUT		0x00 +#define GPIO_MODE_OUTPUT	0x01 +#define GPIO_MODE_ALTERNATE	0x02 +#define GPIO_MODE_ANALOG	0x03 +#define GPIO_MODE_MASK		U(0x03) + +#define GPIO_OPEN_DRAIN		U(0x10) + +#define GPIO_SPEED_LOW		0x00 +#define GPIO_SPEED_MEDIUM	0x01 +#define GPIO_SPEED_FAST		0x02 +#define GPIO_SPEED_HIGH		0x03 +#define GPIO_SPEED_MASK		U(0x03) + +#define GPIO_NO_PULL		0x00 +#define GPIO_PULL_UP		0x01 +#define GPIO_PULL_DOWN		0x02 +#define GPIO_PULL_MASK		U(0x03) + +#ifndef __ASSEMBLY__ +#include <stdint.h> + +void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t speed, +	      uint32_t pull, uint32_t alternate); +#endif /*__ASSEMBLY__*/ + +#endif /*__PLAT_GPIO_H__*/ diff --git a/include/drivers/st/stm32_i2c.h b/include/drivers/st/stm32_i2c.h new file mode 100644 index 00000000..29b9d344 --- /dev/null +++ b/include/drivers/st/stm32_i2c.h @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __STM32MP1_I2C_H +#define __STM32MP1_I2C_H + +#include <stdint.h> +#include <utils_def.h> + +/* Bit definition for I2C_CR1 register */ +#define I2C_CR1_PE			BIT(0) +#define I2C_CR1_TXIE			BIT(1) +#define I2C_CR1_RXIE			BIT(2) +#define I2C_CR1_ADDRIE			BIT(3) +#define I2C_CR1_NACKIE			BIT(4) +#define I2C_CR1_STOPIE			BIT(5) +#define I2C_CR1_TCIE			BIT(6) +#define I2C_CR1_ERRIE			BIT(7) +#define I2C_CR1_DNF			GENMASK(11, 8) +#define I2C_CR1_ANFOFF			BIT(12) +#define I2C_CR1_SWRST			BIT(13) +#define I2C_CR1_TXDMAEN			BIT(14) +#define I2C_CR1_RXDMAEN			BIT(15) +#define I2C_CR1_SBC			BIT(16) +#define I2C_CR1_NOSTRETCH		BIT(17) +#define I2C_CR1_WUPEN			BIT(18) +#define I2C_CR1_GCEN			BIT(19) +#define I2C_CR1_SMBHEN			BIT(22) +#define I2C_CR1_SMBDEN			BIT(21) +#define I2C_CR1_ALERTEN			BIT(22) +#define I2C_CR1_PECEN			BIT(23) + +/* Bit definition for I2C_CR2 register */ +#define I2C_CR2_SADD			GENMASK(9, 0) +#define I2C_CR2_RD_WRN			BIT(10) +#define I2C_CR2_RD_WRN_OFFSET		10U +#define I2C_CR2_ADD10			BIT(11) +#define I2C_CR2_HEAD10R			BIT(12) +#define I2C_CR2_START			BIT(13) +#define I2C_CR2_STOP			BIT(14) +#define I2C_CR2_NACK			BIT(15) +#define I2C_CR2_NBYTES			GENMASK(23, 16) +#define I2C_CR2_NBYTES_OFFSET		16U +#define I2C_CR2_RELOAD			BIT(24) +#define I2C_CR2_AUTOEND			BIT(25) +#define I2C_CR2_PECBYTE			BIT(26) + +/* Bit definition for I2C_OAR1 register */ +#define I2C_OAR1_OA1			GENMASK(9, 0) +#define I2C_OAR1_OA1MODE		BIT(10) +#define I2C_OAR1_OA1EN			BIT(15) + +/* Bit definition for I2C_OAR2 register */ +#define I2C_OAR2_OA2			GENMASK(7, 1) +#define I2C_OAR2_OA2MSK			GENMASK(10, 8) +#define I2C_OAR2_OA2NOMASK		0 +#define I2C_OAR2_OA2MASK01		BIT(8) +#define I2C_OAR2_OA2MASK02		BIT(9) +#define I2C_OAR2_OA2MASK03		GENMASK(9, 8) +#define I2C_OAR2_OA2MASK04		BIT(10) +#define I2C_OAR2_OA2MASK05		(BIT(8) | BIT(10)) +#define I2C_OAR2_OA2MASK06		(BIT(9) | BIT(10)) +#define I2C_OAR2_OA2MASK07		GENMASK(10, 8) +#define I2C_OAR2_OA2EN			BIT(15) + +/* Bit definition for I2C_TIMINGR register */ +#define I2C_TIMINGR_SCLL		GENMASK(7, 0) +#define I2C_TIMINGR_SCLH		GENMASK(15, 8) +#define I2C_TIMINGR_SDADEL		GENMASK(19, 16) +#define I2C_TIMINGR_SCLDEL		GENMASK(23, 20) +#define I2C_TIMINGR_PRESC		GENMASK(31, 28) + +/* Bit definition for I2C_TIMEOUTR register */ +#define I2C_TIMEOUTR_TIMEOUTA		GENMASK(11, 0) +#define I2C_TIMEOUTR_TIDLE		BIT(12) +#define I2C_TIMEOUTR_TIMOUTEN		BIT(15) +#define I2C_TIMEOUTR_TIMEOUTB		GENMASK(27, 16) +#define I2C_TIMEOUTR_TEXTEN		BIT(31) + +/* Bit definition for I2C_ISR register */ +#define I2C_ISR_TXE			BIT(0) +#define I2C_ISR_TXIS			BIT(1) +#define I2C_ISR_RXNE			BIT(2) +#define I2C_ISR_ADDR			BIT(3) +#define I2C_ISR_NACKF			BIT(4) +#define I2C_ISR_STOPF			BIT(5) +#define I2C_ISR_TC			BIT(6) +#define I2C_ISR_TCR			BIT(7) +#define I2C_ISR_BERR			BIT(8) +#define I2C_ISR_ARLO			BIT(9) +#define I2C_ISR_OVR			BIT(10) +#define I2C_ISR_PECERR			BIT(11) +#define I2C_ISR_TIMEOUT			BIT(12) +#define I2C_ISR_ALERT			BIT(13) +#define I2C_ISR_BUSY			BIT(15) +#define I2C_ISR_DIR			BIT(16) +#define I2C_ISR_ADDCODE			GENMASK(23, 17) + +/* Bit definition for I2C_ICR register */ +#define I2C_ICR_ADDRCF			BIT(3) +#define I2C_ICR_NACKCF			BIT(4) +#define I2C_ICR_STOPCF			BIT(5) +#define I2C_ICR_BERRCF			BIT(8) +#define I2C_ICR_ARLOCF			BIT(9) +#define I2C_ICR_OVRCF			BIT(10) +#define I2C_ICR_PECCF			BIT(11) +#define I2C_ICR_TIMOUTCF		BIT(12) +#define I2C_ICR_ALERTCF			BIT(13) + +struct stm32_i2c_init_s { +	uint32_t timing;           /* Specifies the I2C_TIMINGR_register value +				    * This parameter is calculated by referring +				    * to I2C initialization section in Reference +				    * manual. +				    */ + +	uint32_t own_address1;     /* Specifies the first device own address. +				    * This parameter can be a 7-bit or 10-bit +				    * address. +				    */ + +	uint32_t addressing_mode;  /* Specifies if 7-bit or 10-bit addressing +				    * mode is selected. +				    * This parameter can be a value of @ref +				    * I2C_ADDRESSING_MODE. +				    */ + +	uint32_t dual_address_mode; /* Specifies if dual addressing mode is +				     * selected. +				     * This parameter can be a value of @ref +				     * I2C_DUAL_ADDRESSING_MODE. +				     */ + +	uint32_t own_address2;     /* Specifies the second device own address +				    * if dual addressing mode is selected. +				    * This parameter can be a 7-bit address. +				    */ + +	uint32_t own_address2_masks; /* Specifies the acknowledge mask address +				      * second device own address if dual +				      * addressing mode is selected. +				      * This parameter can be a value of @ref +				      * I2C_OWN_ADDRESS2_MASKS. +				      */ + +	uint32_t general_call_mode; /* Specifies if general call mode is +				     * selected. +				     * This parameter can be a value of @ref +				     * I2C_GENERAL_CALL_ADDRESSING_MODE. +				     */ + +	uint32_t no_stretch_mode;  /* Specifies if nostretch mode is +				    * selected. +				    * This parameter can be a value of @ref +				    * I2C_NOSTRETCH_MODE. +				    */ + +}; + +enum i2c_state_e { +	I2C_STATE_RESET          = 0x00U,   /* Peripheral is not yet +					     * initialized. +					     */ +	I2C_STATE_READY          = 0x20U,   /* Peripheral Initialized +					     * and ready for use. +					     */ +	I2C_STATE_BUSY           = 0x24U,   /* An internal process is +					     * ongoing. +					     */ +	I2C_STATE_BUSY_TX        = 0x21U,   /* Data Transmission process +					     * is ongoing. +					     */ +	I2C_STATE_BUSY_RX        = 0x22U,   /* Data Reception process +					     * is ongoing. +					     */ +	I2C_STATE_LISTEN         = 0x28U,   /* Address Listen Mode is +					     * ongoing. +					     */ +	I2C_STATE_BUSY_TX_LISTEN = 0x29U,   /* Address Listen Mode +					     * and Data Transmission +					     * process is ongoing. +					     */ +	I2C_STATE_BUSY_RX_LISTEN = 0x2AU,   /* Address Listen Mode +					     * and Data Reception +					     * process is ongoing. +					     */ +	I2C_STATE_ABORT          = 0x60U,   /* Abort user request ongoing. */ +	I2C_STATE_TIMEOUT        = 0xA0U,   /* Timeout state. */ +	I2C_STATE_ERROR          = 0xE0U    /* Error. */ + +}; + +enum i2c_mode_e { +	I2C_MODE_NONE   = 0x00U,   /* No I2C communication on going.       */ +	I2C_MODE_MASTER = 0x10U,   /* I2C communication is in Master Mode. */ +	I2C_MODE_SLAVE  = 0x20U,   /* I2C communication is in Slave Mode.  */ +	I2C_MODE_MEM    = 0x40U    /* I2C communication is in Memory Mode. */ + +}; + +#define I2C_ERROR_NONE		0x00000000U	/* No error              */ +#define I2C_ERROR_BERR		0x00000001U	/* BERR error            */ +#define I2C_ERROR_ARLO		0x00000002U	/* ARLO error            */ +#define I2C_ERROR_AF		0x00000004U	/* ACKF error            */ +#define I2C_ERROR_OVR		0x00000008U	/* OVR error             */ +#define I2C_ERROR_DMA		0x00000010U	/* DMA transfer error    */ +#define I2C_ERROR_TIMEOUT	0x00000020U	/* Timeout error         */ +#define I2C_ERROR_SIZE		0x00000040U	/* Size Management error */ + +struct i2c_handle_s { +	uint32_t i2c_base_addr;			/* Registers base address */ + +	struct stm32_i2c_init_s i2c_init;	/* Communication parameters */ + +	uint8_t *p_buff;			/* Pointer to transfer buffer */ + +	uint16_t xfer_size;			/* Transfer size */ + +	uint16_t xfer_count;			/* Transfer counter */ + +	uint32_t prev_state;			/* Communication previous +						 * state +						 */ + +	uint8_t lock;				/* Locking object */ + +	enum i2c_state_e i2c_state;		/* Communication state */ + +	enum i2c_mode_e i2c_mode;		/* Communication mode */ + +	uint32_t i2c_err;			/* Error code */ +}; + +#define I2C_ADDRESSINGMODE_7BIT		0x00000001U +#define I2C_ADDRESSINGMODE_10BIT	0x00000002U + +#define I2C_DUALADDRESS_DISABLE		0x00000000U +#define I2C_DUALADDRESS_ENABLE		I2C_OAR2_OA2EN + +#define I2C_GENERALCALL_DISABLE		0x00000000U +#define I2C_GENERALCALL_ENABLE		I2C_CR1_GCEN + +#define I2C_NOSTRETCH_DISABLE		0x00000000U +#define I2C_NOSTRETCH_ENABLE		I2C_CR1_NOSTRETCH + +#define I2C_MEMADD_SIZE_8BIT		0x00000001U +#define I2C_MEMADD_SIZE_16BIT		0x00000002U + +#define  I2C_RELOAD_MODE		I2C_CR2_RELOAD +#define  I2C_AUTOEND_MODE		I2C_CR2_AUTOEND +#define  I2C_SOFTEND_MODE		0x00000000U + +#define  I2C_NO_STARTSTOP		0x00000000U +#define  I2C_GENERATE_STOP		(BIT(31) | I2C_CR2_STOP) +#define  I2C_GENERATE_START_READ	(BIT(31) | I2C_CR2_START | \ +					 I2C_CR2_RD_WRN) +#define  I2C_GENERATE_START_WRITE	(BIT(31) | I2C_CR2_START) + +#define I2C_FLAG_TXE			I2C_ISR_TXE +#define I2C_FLAG_TXIS			I2C_ISR_TXIS +#define I2C_FLAG_RXNE			I2C_ISR_RXNE +#define I2C_FLAG_ADDR			I2C_ISR_ADDR +#define I2C_FLAG_AF			I2C_ISR_NACKF +#define I2C_FLAG_STOPF			I2C_ISR_STOPF +#define I2C_FLAG_TC			I2C_ISR_TC +#define I2C_FLAG_TCR			I2C_ISR_TCR +#define I2C_FLAG_BERR			I2C_ISR_BERR +#define I2C_FLAG_ARLO			I2C_ISR_ARLO +#define I2C_FLAG_OVR			I2C_ISR_OVR +#define I2C_FLAG_PECERR			I2C_ISR_PECERR +#define I2C_FLAG_TIMEOUT		I2C_ISR_TIMEOUT +#define I2C_FLAG_ALERT			I2C_ISR_ALERT +#define I2C_FLAG_BUSY			I2C_ISR_BUSY +#define I2C_FLAG_DIR			I2C_ISR_DIR + +#define I2C_RESET_CR2			(I2C_CR2_SADD | I2C_CR2_HEAD10R | \ +					 I2C_CR2_NBYTES | I2C_CR2_RELOAD  | \ +					 I2C_CR2_RD_WRN) + +#define I2C_ANALOGFILTER_ENABLE		((uint32_t)0x00000000U) +#define I2C_ANALOGFILTER_DISABLE	I2C_CR1_ANFOFF + +int stm32_i2c_init(struct i2c_handle_s *hi2c); + +int stm32_i2c_mem_write(struct i2c_handle_s *hi2c, uint16_t dev_addr, +			uint16_t mem_addr, uint16_t mem_add_size, +			uint8_t *p_data, uint16_t size, uint32_t timeout); +int stm32_i2c_mem_read(struct i2c_handle_s *hi2c, uint16_t dev_addr, +		       uint16_t mem_addr, uint16_t mem_add_size, +		       uint8_t *p_data, uint16_t size, uint32_t timeout); +int stm32_i2c_is_device_ready(struct i2c_handle_s *hi2c, uint16_t dev_addr, +			      uint32_t trials, uint32_t timeout); + +int stm32_i2c_config_analog_filter(struct i2c_handle_s *hi2c, +				   uint32_t analog_filter); + +#endif /* __STM32MP1_I2C_H */ diff --git a/include/drivers/st/stm32mp1_clk.h b/include/drivers/st/stm32mp1_clk.h new file mode 100644 index 00000000..85a1eb8f --- /dev/null +++ b/include/drivers/st/stm32mp1_clk.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __STM32MP1_CLK_H__ +#define __STM32MP1_CLK_H__ + +#include <arch_helpers.h> +#include <stdbool.h> + +int stm32mp1_clk_probe(void); +int stm32mp1_clk_init(void); +bool stm32mp1_clk_is_enabled(unsigned long id); +int stm32mp1_clk_enable(unsigned long id); +int stm32mp1_clk_disable(unsigned long id); +unsigned long stm32mp1_clk_get_rate(unsigned long id); +void stm32mp1_stgen_increment(unsigned long long offset_in_ms); + +static inline uint32_t get_timer(uint32_t base) +{ +	if (base == 0U) { +		return (uint32_t)(~read_cntpct_el0()); +	} + +	return base - (uint32_t)(~read_cntpct_el0()); +} + +#endif /* __STM32MP1_CLK_H__ */ diff --git a/include/drivers/st/stm32mp1_clkfunc.h b/include/drivers/st/stm32mp1_clkfunc.h new file mode 100644 index 00000000..635a9cd4 --- /dev/null +++ b/include/drivers/st/stm32mp1_clkfunc.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __STM32MP1_CLKFUNC_H__ +#define __STM32MP1_CLKFUNC_H__ + +#include <stdbool.h> + +enum stm32mp_osc_id { +	_HSI, +	_HSE, +	_CSI, +	_LSI, +	_LSE, +	_I2S_CKIN, +	_USB_PHY_48, +	NB_OSC, +	_UNKNOWN_OSC_ID = 0xFF +}; + +extern const char *stm32mp_osc_node_label[NB_OSC]; + +int fdt_osc_read_freq(const char *name, uint32_t *freq); +bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name); +uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id, +				     const char *prop_name, +				     uint32_t dflt_value); + +uint32_t fdt_rcc_read_addr(void); +int fdt_rcc_read_uint32_array(const char *prop_name, +			      uint32_t *array, uint32_t count); +int fdt_rcc_subnode_offset(const char *name); +const uint32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp); +bool fdt_get_rcc_secure_status(void); + +uintptr_t fdt_get_stgen_base(void); +int fdt_get_clock_id(int node); + +#endif /* __STM32MP1_CLKFUNC_H__ */ diff --git a/include/drivers/st/stm32mp1_ddr.h b/include/drivers/st/stm32mp1_ddr.h new file mode 100644 index 00000000..07656648 --- /dev/null +++ b/include/drivers/st/stm32mp1_ddr.h @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause + */ + +#ifndef _STM32MP1_DDR_H +#define _STM32MP1_DDR_H + +#include <stdbool.h> + +#define DT_DDR_COMPAT	"st,stm32mp1-ddr" + +struct stm32mp1_ddr_size { +	uint64_t base; +	uint64_t size; +}; + +/** + * struct ddr_info + * + * @dev: pointer for the device + * @info: UCLASS RAM information + * @ctl: DDR controleur base address + * @phy: DDR PHY base address + * @syscfg: syscfg base address + */ +struct ddr_info { +	struct stm32mp1_ddr_size info; +	struct stm32mp1_ddrctl *ctl; +	struct stm32mp1_ddrphy *phy; +	uintptr_t pwr; +	uintptr_t rcc; +}; + +struct stm32mp1_ddrctrl_reg { +	uint32_t mstr; +	uint32_t mrctrl0; +	uint32_t mrctrl1; +	uint32_t derateen; +	uint32_t derateint; +	uint32_t pwrctl; +	uint32_t pwrtmg; +	uint32_t hwlpctl; +	uint32_t rfshctl0; +	uint32_t rfshctl3; +	uint32_t crcparctl0; +	uint32_t zqctl0; +	uint32_t dfitmg0; +	uint32_t dfitmg1; +	uint32_t dfilpcfg0; +	uint32_t dfiupd0; +	uint32_t dfiupd1; +	uint32_t dfiupd2; +	uint32_t dfiphymstr; +	uint32_t odtmap; +	uint32_t dbg0; +	uint32_t dbg1; +	uint32_t dbgcmd; +	uint32_t poisoncfg; +	uint32_t pccfg; +}; + +struct stm32mp1_ddrctrl_timing { +	uint32_t rfshtmg; +	uint32_t dramtmg0; +	uint32_t dramtmg1; +	uint32_t dramtmg2; +	uint32_t dramtmg3; +	uint32_t dramtmg4; +	uint32_t dramtmg5; +	uint32_t dramtmg6; +	uint32_t dramtmg7; +	uint32_t dramtmg8; +	uint32_t dramtmg14; +	uint32_t odtcfg; +}; + +struct stm32mp1_ddrctrl_map { +	uint32_t addrmap1; +	uint32_t addrmap2; +	uint32_t addrmap3; +	uint32_t addrmap4; +	uint32_t addrmap5; +	uint32_t addrmap6; +	uint32_t addrmap9; +	uint32_t addrmap10; +	uint32_t addrmap11; +}; + +struct stm32mp1_ddrctrl_perf { +	uint32_t sched; +	uint32_t sched1; +	uint32_t perfhpr1; +	uint32_t perflpr1; +	uint32_t perfwr1; +	uint32_t pcfgr_0; +	uint32_t pcfgw_0; +	uint32_t pcfgqos0_0; +	uint32_t pcfgqos1_0; +	uint32_t pcfgwqos0_0; +	uint32_t pcfgwqos1_0; +	uint32_t pcfgr_1; +	uint32_t pcfgw_1; +	uint32_t pcfgqos0_1; +	uint32_t pcfgqos1_1; +	uint32_t pcfgwqos0_1; +	uint32_t pcfgwqos1_1; +}; + +struct stm32mp1_ddrphy_reg { +	uint32_t pgcr; +	uint32_t aciocr; +	uint32_t dxccr; +	uint32_t dsgcr; +	uint32_t dcr; +	uint32_t odtcr; +	uint32_t zq0cr1; +	uint32_t dx0gcr; +	uint32_t dx1gcr; +	uint32_t dx2gcr; +	uint32_t dx3gcr; +}; + +struct stm32mp1_ddrphy_timing { +	uint32_t ptr0; +	uint32_t ptr1; +	uint32_t ptr2; +	uint32_t dtpr0; +	uint32_t dtpr1; +	uint32_t dtpr2; +	uint32_t mr0; +	uint32_t mr1; +	uint32_t mr2; +	uint32_t mr3; +}; + +struct stm32mp1_ddrphy_cal { +	uint32_t dx0dllcr; +	uint32_t dx0dqtr; +	uint32_t dx0dqstr; +	uint32_t dx1dllcr; +	uint32_t dx1dqtr; +	uint32_t dx1dqstr; +	uint32_t dx2dllcr; +	uint32_t dx2dqtr; +	uint32_t dx2dqstr; +	uint32_t dx3dllcr; +	uint32_t dx3dqtr; +	uint32_t dx3dqstr; +}; + +struct stm32mp1_ddr_info { +	const char *name; +	uint16_t speed; /* in MHZ */ +	uint32_t 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, uint16_t mem_speed); +void stm32mp1_ddr_init(struct ddr_info *priv, +		       struct stm32mp1_ddr_config *config); +#endif /* _STM32MP1_DDR_H */ diff --git a/include/drivers/st/stm32mp1_ddr_helpers.h b/include/drivers/st/stm32mp1_ddr_helpers.h new file mode 100644 index 00000000..298a0804 --- /dev/null +++ b/include/drivers/st/stm32mp1_ddr_helpers.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __STM32MP1_DDR_HELPERS_H__ +#define __STM32MP1_DDR_HELPERS_H__ + +void ddr_enable_clock(void); + +#endif /* __STM32MP1_DDR_HELPERS_H__ */ diff --git a/include/drivers/st/stm32mp1_ddr_regs.h b/include/drivers/st/stm32mp1_ddr_regs.h new file mode 100644 index 00000000..64ad9655 --- /dev/null +++ b/include/drivers/st/stm32mp1_ddr_regs.h @@ -0,0 +1,413 @@ +/* + * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause + */ + +#ifndef _RAM_STM32MP1_DDR_REGS_H +#define _RAM_STM32MP1_DDR_REGS_H + +#include <utils_def.h> + +/* DDR3/LPDDR2/LPDDR3 Controller (DDRCTRL) registers */ +struct stm32mp1_ddrctl { +	uint32_t mstr ;		/* 0x0 Master */ +	uint32_t stat;		/* 0x4 Operating Mode Status */ +	uint8_t reserved008[0x10 - 0x8]; +	uint32_t mrctrl0;	/* 0x10 Control 0 */ +	uint32_t mrctrl1;	/* 0x14 Control 1 */ +	uint32_t mrstat;	/* 0x18 Status */ +	uint32_t reserved01c;	/* 0x1c */ +	uint32_t derateen;	/* 0x20 Temperature Derate Enable */ +	uint32_t derateint;	/* 0x24 Temperature Derate Interval */ +	uint8_t reserved028[0x30 - 0x28]; +	uint32_t pwrctl;	/* 0x30 Low Power Control */ +	uint32_t pwrtmg;	/* 0x34 Low Power Timing */ +	uint32_t hwlpctl;	/* 0x38 Hardware Low Power Control */ +	uint8_t reserved03c[0x50 - 0x3C]; +	uint32_t rfshctl0;	/* 0x50 Refresh Control 0 */ +	uint32_t reserved054;	/* 0x54 Refresh Control 1 */ +	uint32_t reserved058;	/* 0x58 Refresh Control 2 */ +	uint32_t reserved05C; +	uint32_t rfshctl3;	/* 0x60 Refresh Control 0 */ +	uint32_t rfshtmg;	/* 0x64 Refresh Timing */ +	uint8_t reserved068[0xc0 - 0x68]; +	uint32_t crcparctl0;		/* 0xc0 CRC Parity Control0 */ +	uint32_t reserved0c4;	/* 0xc4 CRC Parity Control1 */ +	uint32_t reserved0c8;	/* 0xc8 CRC Parity Control2 */ +	uint32_t crcparstat;		/* 0xcc CRC Parity Status */ +	uint32_t init0;		/* 0xd0 SDRAM Initialization 0 */ +	uint32_t init1;		/* 0xd4 SDRAM Initialization 1 */ +	uint32_t init2;		/* 0xd8 SDRAM Initialization 2 */ +	uint32_t init3;		/* 0xdc SDRAM Initialization 3 */ +	uint32_t init4;		/* 0xe0 SDRAM Initialization 4 */ +	uint32_t init5;		/* 0xe4 SDRAM Initialization 5 */ +	uint32_t reserved0e8; +	uint32_t reserved0ec; +	uint32_t dimmctl;	/* 0xf0 DIMM Control */ +	uint8_t reserved0f4[0x100 - 0xf4]; +	uint32_t dramtmg0;	/* 0x100 SDRAM Timing 0 */ +	uint32_t dramtmg1;	/* 0x104 SDRAM Timing 1 */ +	uint32_t dramtmg2;	/* 0x108 SDRAM Timing 2 */ +	uint32_t dramtmg3;	/* 0x10c SDRAM Timing 3 */ +	uint32_t dramtmg4;	/* 0x110 SDRAM Timing 4 */ +	uint32_t dramtmg5;	/* 0x114 SDRAM Timing 5 */ +	uint32_t dramtmg6;	/* 0x118 SDRAM Timing 6 */ +	uint32_t dramtmg7;	/* 0x11c SDRAM Timing 7 */ +	uint32_t dramtmg8;	/* 0x120 SDRAM Timing 8 */ +	uint8_t reserved124[0x138 - 0x124]; +	uint32_t dramtmg14;	/* 0x138 SDRAM Timing 14 */ +	uint32_t dramtmg15;	/* 0x13C SDRAM Timing 15 */ +	uint8_t reserved140[0x180 - 0x140]; +	uint32_t zqctl0;	/* 0x180 ZQ Control 0 */ +	uint32_t zqctl1;	/* 0x184 ZQ Control 1 */ +	uint32_t zqctl2;	/* 0x188 ZQ Control 2 */ +	uint32_t zqstat;	/* 0x18c ZQ Status */ +	uint32_t dfitmg0;	/* 0x190 DFI Timing 0 */ +	uint32_t dfitmg1;	/* 0x194 DFI Timing 1 */ +	uint32_t dfilpcfg0;	/* 0x198 DFI Low Power Configuration 0 */ +	uint32_t reserved19c; +	uint32_t dfiupd0;	/* 0x1a0 DFI Update 0 */ +	uint32_t dfiupd1;	/* 0x1a4 DFI Update 1 */ +	uint32_t dfiupd2;	/* 0x1a8 DFI Update 2 */ +	uint32_t reserved1ac; +	uint32_t dfimisc;	/* 0x1b0 DFI Miscellaneous Control */ +	uint8_t reserved1b4[0x1bc - 0x1b4]; +	uint32_t dfistat;	/* 0x1bc DFI Miscellaneous Control */ +	uint8_t reserved1c0[0x1c4 - 0x1c0]; +	uint32_t dfiphymstr;	/* 0x1c4 DFI PHY Master interface */ +	uint8_t reserved1c8[0x204 - 0x1c8]; +	uint32_t addrmap1;	/* 0x204 Address Map 1 */ +	uint32_t addrmap2;	/* 0x208 Address Map 2 */ +	uint32_t addrmap3;	/* 0x20c Address Map 3 */ +	uint32_t addrmap4;	/* 0x210 Address Map 4 */ +	uint32_t addrmap5;	/* 0x214 Address Map 5 */ +	uint32_t addrmap6;	/* 0x218 Address Map 6 */ +	uint8_t reserved21c[0x224 - 0x21c]; +	uint32_t addrmap9;	/* 0x224 Address Map 9 */ +	uint32_t addrmap10;	/* 0x228 Address Map 10 */ +	uint32_t addrmap11;	/* 0x22C Address Map 11 */ +	uint8_t reserved230[0x240 - 0x230]; +	uint32_t odtcfg;	/* 0x240 ODT Configuration */ +	uint32_t odtmap;	/* 0x244 ODT/Rank Map */ +	uint8_t reserved248[0x250 - 0x248]; +	uint32_t sched;		/* 0x250 Scheduler Control */ +	uint32_t sched1;	/* 0x254 Scheduler Control 1 */ +	uint32_t reserved258; +	uint32_t perfhpr1;	/* 0x25c High Priority Read CAM 1 */ +	uint32_t reserved260; +	uint32_t perflpr1;	/* 0x264 Low Priority Read CAM 1 */ +	uint32_t reserved268; +	uint32_t perfwr1;	/* 0x26c Write CAM 1 */ +	uint8_t reserved27c[0x300 - 0x270]; +	uint32_t dbg0;		/* 0x300 Debug 0 */ +	uint32_t dbg1;		/* 0x304 Debug 1 */ +	uint32_t dbgcam;	/* 0x308 CAM Debug */ +	uint32_t dbgcmd;	/* 0x30c Command Debug */ +	uint32_t dbgstat;	/* 0x310 Status Debug */ +	uint8_t reserved314[0x320 - 0x314]; +	uint32_t swctl;		/* 0x320 Software Programming Control Enable */ +	uint32_t swstat;	/* 0x324 Software Programming Control Status */ +	uint8_t reserved328[0x36c - 0x328]; +	uint32_t poisoncfg;	/* 0x36c AXI Poison Configuration Register */ +	uint32_t poisonstat;	/* 0x370 AXI Poison Status Register */ +	uint8_t reserved374[0x3fc - 0x374]; + +	/* Multi Port registers */ +	uint32_t pstat;		/* 0x3fc Port Status */ +	uint32_t pccfg;		/* 0x400 Port Common Configuration */ + +	/* PORT 0 */ +	uint32_t pcfgr_0;	/* 0x404 Configuration Read */ +	uint32_t pcfgw_0;	/* 0x408 Configuration Write */ +	uint8_t reserved40c[0x490 - 0x40c]; +	uint32_t pctrl_0;	/* 0x490 Port Control Register */ +	uint32_t pcfgqos0_0;	/* 0x494 Read QoS Configuration 0 */ +	uint32_t pcfgqos1_0;	/* 0x498 Read QoS Configuration 1 */ +	uint32_t pcfgwqos0_0;	/* 0x49c Write QoS Configuration 0 */ +	uint32_t pcfgwqos1_0;	/* 0x4a0 Write QoS Configuration 1 */ +	uint8_t reserved4a4[0x4b4 - 0x4a4]; + +	/* PORT 1 */ +	uint32_t pcfgr_1;	/* 0x4b4 Configuration Read */ +	uint32_t pcfgw_1;	/* 0x4b8 Configuration Write */ +	uint8_t reserved4bc[0x540 - 0x4bc]; +	uint32_t pctrl_1;	/* 0x540 Port 2 Control Register */ +	uint32_t pcfgqos0_1;	/* 0x544 Read QoS Configuration 0 */ +	uint32_t pcfgqos1_1;	/* 0x548 Read QoS Configuration 1 */ +	uint32_t pcfgwqos0_1;	/* 0x54c Write QoS Configuration 0 */ +	uint32_t pcfgwqos1_1;	/* 0x550 Write QoS Configuration 1 */ +} __packed; + +/* DDR Physical Interface Control (DDRPHYC) registers*/ +struct stm32mp1_ddrphy { +	uint32_t ridr;		/* 0x00 R Revision Identification */ +	uint32_t pir;		/* 0x04 R/W PHY Initialization */ +	uint32_t pgcr;		/* 0x08 R/W PHY General Configuration */ +	uint32_t pgsr;		/* 0x0C PHY General Status */ +	uint32_t dllgcr;	/* 0x10 R/W DLL General Control */ +	uint32_t acdllcr;	/* 0x14 R/W AC DLL Control */ +	uint32_t ptr0;		/* 0x18 R/W PHY Timing 0 */ +	uint32_t ptr1;		/* 0x1C R/W PHY Timing 1 */ +	uint32_t ptr2;		/* 0x20 R/W PHY Timing 2 */ +	uint32_t aciocr;	/* 0x24 AC I/O Configuration */ +	uint32_t dxccr;		/* 0x28 DATX8 Common Configuration */ +	uint32_t dsgcr;		/* 0x2C DDR System General Configuration */ +	uint32_t dcr;		/* 0x30 DRAM Configuration */ +	uint32_t dtpr0;		/* 0x34 DRAM Timing Parameters0 */ +	uint32_t dtpr1;		/* 0x38 DRAM Timing Parameters1 */ +	uint32_t dtpr2;		/* 0x3C DRAM Timing Parameters2 */ +	uint32_t mr0;		/* 0x40 Mode 0 */ +	uint32_t mr1;		/* 0x44 Mode 1 */ +	uint32_t mr2;		/* 0x48 Mode 2 */ +	uint32_t mr3;		/* 0x4C Mode 3 */ +	uint32_t odtcr;		/* 0x50 ODT Configuration */ +	uint32_t dtar;		/* 0x54 data training address */ +	uint32_t dtdr0;		/* 0x58 */ +	uint32_t dtdr1;		/* 0x5c */ +	uint8_t res1[0x0c0 - 0x060];	/* 0x60 */ +	uint32_t dcuar;		/* 0xc0 Address */ +	uint32_t dcudr;		/* 0xc4 DCU Data */ +	uint32_t dcurr;		/* 0xc8 DCU Run */ +	uint32_t dculr;		/* 0xcc DCU Loop */ +	uint32_t dcugcr;	/* 0xd0 DCU General Configuration */ +	uint32_t dcutpr;	/* 0xd4 DCU Timing Parameters */ +	uint32_t dcusr0;	/* 0xd8 DCU Status 0 */ +	uint32_t dcusr1;	/* 0xdc DCU Status 1 */ +	uint8_t res2[0x100 - 0xe0];	/* 0xe0 */ +	uint32_t bistrr;	/* 0x100 BIST Run */ +	uint32_t bistmskr0;	/* 0x104 BIST Mask 0 */ +	uint32_t bistmskr1;	/* 0x108 BIST Mask 0 */ +	uint32_t bistwcr;	/* 0x10c BIST Word Count */ +	uint32_t bistlsr;	/* 0x110 BIST LFSR Seed */ +	uint32_t bistar0;	/* 0x114 BIST Address 0 */ +	uint32_t bistar1;	/* 0x118 BIST Address 1 */ +	uint32_t bistar2;	/* 0x11c BIST Address 2 */ +	uint32_t bistupdr;	/* 0x120 BIST User Data Pattern */ +	uint32_t bistgsr;	/* 0x124 BIST General Status */ +	uint32_t bistwer;	/* 0x128 BIST Word Error */ +	uint32_t bistber0;	/* 0x12c BIST Bit Error 0 */ +	uint32_t bistber1;	/* 0x130 BIST Bit Error 1 */ +	uint32_t bistber2;	/* 0x134 BIST Bit Error 2 */ +	uint32_t bistwcsr;	/* 0x138 BIST Word Count Status */ +	uint32_t bistfwr0;	/* 0x13c BIST Fail Word 0 */ +	uint32_t bistfwr1;	/* 0x140 BIST Fail Word 1 */ +	uint8_t res3[0x178 - 0x144];	/* 0x144 */ +	uint32_t gpr0;		/* 0x178 General Purpose 0 (GPR0) */ +	uint32_t gpr1;		/* 0x17C General Purpose 1 (GPR1) */ +	uint32_t zq0cr0;	/* 0x180 zq 0 control 0 */ +	uint32_t zq0cr1;	/* 0x184 zq 0 control 1 */ +	uint32_t zq0sr0;	/* 0x188 zq 0 status 0 */ +	uint32_t zq0sr1;	/* 0x18C zq 0 status 1 */ +	uint8_t res4[0x1C0 - 0x190];	/* 0x190 */ +	uint32_t dx0gcr;	/* 0x1c0 Byte lane 0 General Configuration */ +	uint32_t dx0gsr0;	/* 0x1c4 Byte lane 0 General Status 0 */ +	uint32_t dx0gsr1;	/* 0x1c8 Byte lane 0 General Status 1 */ +	uint32_t dx0dllcr;	/* 0x1cc Byte lane 0 DLL Control */ +	uint32_t dx0dqtr;	/* 0x1d0 Byte lane 0 DQ Timing */ +	uint32_t dx0dqstr;	/* 0x1d4 Byte lane 0 DQS Timing */ +	uint8_t res5[0x200 - 0x1d8];	/* 0x1d8 */ +	uint32_t dx1gcr;	/* 0x200 Byte lane 1 General Configuration */ +	uint32_t dx1gsr0;	/* 0x204 Byte lane 1 General Status 0 */ +	uint32_t dx1gsr1;	/* 0x208 Byte lane 1 General Status 1 */ +	uint32_t dx1dllcr;	/* 0x20c Byte lane 1 DLL Control */ +	uint32_t dx1dqtr;	/* 0x210 Byte lane 1 DQ Timing */ +	uint32_t dx1dqstr;	/* 0x214 Byte lane 1 QS Timing */ +	uint8_t res6[0x240 - 0x218];	/* 0x218 */ +	uint32_t dx2gcr;	/* 0x240 Byte lane 2 General Configuration */ +	uint32_t dx2gsr0;	/* 0x244 Byte lane 2 General Status 0 */ +	uint32_t dx2gsr1;	/* 0x248 Byte lane 2 General Status 1 */ +	uint32_t dx2dllcr;	/* 0x24c Byte lane 2 DLL Control */ +	uint32_t dx2dqtr;	/* 0x250 Byte lane 2 DQ Timing */ +	uint32_t dx2dqstr;	/* 0x254 Byte lane 2 QS Timing */ +	uint8_t res7[0x280 - 0x258];	/* 0x258 */ +	uint32_t dx3gcr;	/* 0x280 Byte lane 3 General Configuration */ +	uint32_t dx3gsr0;	/* 0x284 Byte lane 3 General Status 0 */ +	uint32_t dx3gsr1;	/* 0x288 Byte lane 3 General Status 1 */ +	uint32_t dx3dllcr;	/* 0x28c Byte lane 3 DLL Control */ +	uint32_t dx3dqtr;	/* 0x290 Byte lane 3 DQ Timing */ +	uint32_t dx3dqstr;	/* 0x294 Byte lane 3 QS Timing */ +} __packed; + +/* DDR Controller registers offsets */ +#define DDRCTRL_MSTR				0x000 +#define DDRCTRL_STAT				0x004 +#define DDRCTRL_MRCTRL0				0x010 +#define DDRCTRL_MRSTAT				0x018 +#define DDRCTRL_PWRCTL				0x030 +#define DDRCTRL_PWRTMG				0x034 +#define DDRCTRL_HWLPCTL				0x038 +#define DDRCTRL_RFSHCTL3			0x060 +#define DDRCTRL_RFSHTMG				0x064 +#define DDRCTRL_INIT0				0x0D0 +#define DDRCTRL_DFIMISC				0x1B0 +#define DDRCTRL_DBG1				0x304 +#define DDRCTRL_DBGCAM				0x308 +#define DDRCTRL_DBGCMD				0x30C +#define DDRCTRL_DBGSTAT				0x310 +#define DDRCTRL_SWCTL				0x320 +#define DDRCTRL_SWSTAT				0x324 +#define DDRCTRL_PCTRL_0				0x490 +#define DDRCTRL_PCTRL_1				0x540 + +/* DDR Controller Register fields */ +#define DDRCTRL_MSTR_DDR3			BIT(0) +#define DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK	GENMASK(13, 12) +#define DDRCTRL_MSTR_DATA_BUS_WIDTH_FULL	0 +#define DDRCTRL_MSTR_DATA_BUS_WIDTH_HALF	BIT(12) +#define DDRCTRL_MSTR_DATA_BUS_WIDTH_QUARTER	BIT(13) +#define DDRCTRL_MSTR_DLL_OFF_MODE		BIT(15) + +#define DDRCTRL_STAT_OPERATING_MODE_MASK	GENMASK(2, 0) +#define DDRCTRL_STAT_OPERATING_MODE_NORMAL	BIT(0) +#define DDRCTRL_STAT_OPERATING_MODE_SR		(BIT(0) | BIT(1)) +#define DDRCTRL_STAT_SELFREF_TYPE_MASK		GENMASK(5, 4) +#define DDRCTRL_STAT_SELFREF_TYPE_ASR		(BIT(4) | BIT(5)) +#define DDRCTRL_STAT_SELFREF_TYPE_SR		BIT(5) + +#define DDRCTRL_MRCTRL0_MR_TYPE_WRITE		U(0) +/* Only one rank supported */ +#define DDRCTRL_MRCTRL0_MR_RANK_SHIFT		4 +#define DDRCTRL_MRCTRL0_MR_RANK_ALL \ +		(0x1U << 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_SELFREF_EN		BIT(0) +#define DDRCTRL_PWRCTL_POWERDOWN_EN		BIT(1) +#define DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE	BIT(3) +#define DDRCTRL_PWRCTL_SELFREF_SW		BIT(5) + +#define DDRCTRL_PWRTMG_SELFREF_TO_X32_MASK	GENMASK(19, 12) +#define DDRCTRL_PWRTMG_SELFREF_TO_X32_0		BIT(16) + +#define DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH	BIT(0) + +#define DDRCTRL_HWLPCTL_HW_LP_EN		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	GENMASK(31, 30) +#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) + +/* DDR PHY registers offsets */ +#define DDRPHYC_PIR				0x004 +#define DDRPHYC_PGCR				0x008 +#define DDRPHYC_PGSR				0x00C +#define DDRPHYC_DLLGCR				0x010 +#define DDRPHYC_ACDLLCR				0x014 +#define DDRPHYC_PTR0				0x018 +#define DDRPHYC_ACIOCR				0x024 +#define DDRPHYC_DXCCR				0x028 +#define DDRPHYC_DSGCR				0x02C +#define DDRPHYC_ZQ0CR0				0x180 +#define DDRPHYC_DX0GCR				0x1C0 +#define DDRPHYC_DX0DLLCR			0x1CC +#define DDRPHYC_DX1GCR				0x200 +#define DDRPHYC_DX1DLLCR			0x20C +#define DDRPHYC_DX2GCR				0x240 +#define DDRPHYC_DX2DLLCR			0x24C +#define DDRPHYC_DX3GCR				0x280 +#define DDRPHYC_DX3DLLCR			0x28C + +/* DDR PHY Register fields */ +#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_PTR0_TDLLSRST_OFFSET		0 +#define DDRPHYC_PTR0_TDLLSRST_MASK		GENMASK(5, 0) +#define DDRPHYC_PTR0_TDLLLOCK_OFFSET		6 +#define DDRPHYC_PTR0_TDLLLOCK_MASK		GENMASK(17, 6) +#define DDRPHYC_PTR0_TITMSRST_OFFSET		18 +#define DDRPHYC_PTR0_TITMSRST_MASK		GENMASK(21, 18) + +#define DDRPHYC_ACIOCR_ACPDD			BIT(3) +#define DDRPHYC_ACIOCR_ACPDR			BIT(4) +#define DDRPHYC_ACIOCR_CKPDD_MASK		GENMASK(10, 8) +#define DDRPHYC_ACIOCR_CKPDD_0			BIT(8) +#define DDRPHYC_ACIOCR_CKPDR_MASK		GENMASK(13, 11) +#define DDRPHYC_ACIOCR_CKPDR_0			BIT(11) +#define DDRPHYC_ACIOCR_CSPDD_MASK		GENMASK(21, 18) +#define DDRPHYC_ACIOCR_CSPDD_0			BIT(18) +#define DDRPHYC_ACIOCR_RSTPDD			BIT(27) +#define DDRPHYC_ACIOCR_RSTPDR			BIT(28) + +#define DDRPHYC_DXCCR_DXPDD			BIT(2) +#define DDRPHYC_DXCCR_DXPDR			BIT(3) + +#define DDRPHYC_DSGCR_CKEPDD_MASK		GENMASK(19, 16) +#define DDRPHYC_DSGCR_CKEPDD_0			BIT(16) +#define DDRPHYC_DSGCR_ODTPDD_MASK		GENMASK(23, 20) +#define DDRPHYC_DSGCR_ODTPDD_0			BIT(20) +#define DDRPHYC_DSGCR_NL2PD			BIT(24) + +#define DDRPHYC_ZQ0CRN_ZDATA_MASK		GENMASK(27, 0) +#define DDRPHYC_ZQ0CRN_ZDATA_SHIFT		0 +#define DDRPHYC_ZQ0CRN_ZDEN			BIT(28) +#define DDRPHYC_ZQ0CRN_ZQPD			BIT(31) + +#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 + +void ddr_enable_clock(void); + +#endif /* _RAM_STM32MP1_DDR_REGS_H */ diff --git a/include/drivers/st/stm32mp1_pmic.h b/include/drivers/st/stm32mp1_pmic.h new file mode 100644 index 00000000..5d94b404 --- /dev/null +++ b/include/drivers/st/stm32mp1_pmic.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __STM32MP1_PMIC_H__ +#define __STM32MP1_PMIC_H__ + +#include <stdbool.h> + +bool dt_check_pmic(void); +int dt_pmic_enable_boot_on_regulators(void); +void initialize_pmic_i2c(void); +void initialize_pmic(void); +int pmic_ddr_power_init(enum ddr_type ddr_type); + +#endif /* __STM32MP1_PMIC_H__ */ diff --git a/include/drivers/st/stm32mp1_pwr.h b/include/drivers/st/stm32mp1_pwr.h new file mode 100644 index 00000000..e5670429 --- /dev/null +++ b/include/drivers/st/stm32mp1_pwr.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __STM32MP1_PWR_H__ +#define __STM32MP1_PWR_H__ + +#include <utils_def.h> + +#define PWR_CR1			U(0x00) +#define PWR_CR2			U(0x08) +#define PWR_CR3			U(0x0C) +#define PWR_MPUCR		U(0x10) +#define PWR_WKUPCR		U(0x20) +#define PWR_MPUWKUPENR		U(0x28) + +#define PWR_CR1_LPDS		BIT(0) +#define PWR_CR1_LPCFG		BIT(1) +#define PWR_CR1_LVDS		BIT(2) +#define PWR_CR1_DBP		BIT(8) + +#define PWR_CR3_DDRSREN		BIT(10) +#define PWR_CR3_DDRSRDIS	BIT(11) +#define PWR_CR3_DDRRETEN	BIT(12) + +#define PWR_MPUCR_PDDS		BIT(0) +#define PWR_MPUCR_CSTDBYDIS	BIT(3) +#define PWR_MPUCR_CSSF		BIT(9) + +#endif /* __STM32MP1_PWR_H__ */ diff --git a/include/drivers/st/stm32mp1_ram.h b/include/drivers/st/stm32mp1_ram.h new file mode 100644 index 00000000..af961777 --- /dev/null +++ b/include/drivers/st/stm32mp1_ram.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2015-2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _STM32MP1_RAM_H +#define _STM32MP1_RAM_H + +int stm32mp1_ddr_probe(void); + +#endif /* _STM32MP1_RAM_H */ diff --git a/include/drivers/st/stm32mp1_rcc.h b/include/drivers/st/stm32mp1_rcc.h new file mode 100644 index 00000000..e28ca979 --- /dev/null +++ b/include/drivers/st/stm32mp1_rcc.h @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2015-2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __STM32MP1_RCC_H__ +#define __STM32MP1_RCC_H__ + +#include <utils_def.h> + +#define RCC_TZCR			U(0x00) +#define RCC_OCENSETR			U(0x0C) +#define RCC_OCENCLRR			U(0x10) +#define RCC_HSICFGR			U(0x18) +#define RCC_CSICFGR			U(0x1C) +#define RCC_MPCKSELR			U(0x20) +#define RCC_ASSCKSELR			U(0x24) +#define RCC_RCK12SELR			U(0x28) +#define RCC_MPCKDIVR			U(0x2C) +#define RCC_AXIDIVR			U(0x30) +#define RCC_APB4DIVR			U(0x3C) +#define RCC_APB5DIVR			U(0x40) +#define RCC_RTCDIVR			U(0x44) +#define RCC_MSSCKSELR			U(0x48) +#define RCC_PLL1CR			U(0x80) +#define RCC_PLL1CFGR1			U(0x84) +#define RCC_PLL1CFGR2			U(0x88) +#define RCC_PLL1FRACR			U(0x8C) +#define RCC_PLL1CSGR			U(0x90) +#define RCC_PLL2CR			U(0x94) +#define RCC_PLL2CFGR1			U(0x98) +#define RCC_PLL2CFGR2			U(0x9C) +#define RCC_PLL2FRACR			U(0xA0) +#define RCC_PLL2CSGR			U(0xA4) +#define RCC_I2C46CKSELR			U(0xC0) +#define RCC_SPI6CKSELR			U(0xC4) +#define RCC_UART1CKSELR			U(0xC8) +#define RCC_RNG1CKSELR			U(0xCC) +#define RCC_CPERCKSELR			U(0xD0) +#define RCC_STGENCKSELR			U(0xD4) +#define RCC_DDRITFCR			U(0xD8) +#define RCC_MP_BOOTCR			U(0x100) +#define RCC_MP_SREQSETR			U(0x104) +#define RCC_MP_SREQCLRR			U(0x108) +#define RCC_MP_GCR			U(0x10C) +#define RCC_MP_APRSTCR			U(0x110) +#define RCC_MP_APRSTSR			U(0x114) +#define RCC_BDCR			U(0x140) +#define RCC_RDLSICR			U(0x144) +#define RCC_APB4RSTSETR			U(0x180) +#define RCC_APB4RSTCLRR			U(0x184) +#define RCC_APB5RSTSETR			U(0x188) +#define RCC_APB5RSTCLRR			U(0x18C) +#define RCC_AHB5RSTSETR			U(0x190) +#define RCC_AHB5RSTCLRR			U(0x194) +#define RCC_AHB6RSTSETR			U(0x198) +#define RCC_AHB6RSTCLRR			U(0x19C) +#define RCC_TZAHB6RSTSETR		U(0x1A0) +#define RCC_TZAHB6RSTCLRR		U(0x1A4) +#define RCC_MP_APB4ENSETR		U(0x200) +#define RCC_MP_APB4ENCLRR		U(0x204) +#define RCC_MP_APB5ENSETR		U(0x208) +#define RCC_MP_APB5ENCLRR		U(0x20C) +#define RCC_MP_AHB5ENSETR		U(0x210) +#define RCC_MP_AHB5ENCLRR		U(0x214) +#define RCC_MP_AHB6ENSETR		U(0x218) +#define RCC_MP_AHB6ENCLRR		U(0x21C) +#define RCC_MP_TZAHB6ENSETR		U(0x220) +#define RCC_MP_TZAHB6ENCLRR		U(0x224) +#define RCC_MP_APB4LPENSETR		U(0x300) +#define RCC_MP_APB4LPENCLRR		U(0x304) +#define RCC_MP_APB5LPENSETR		U(0x308) +#define RCC_MP_APB5LPENCLRR		U(0x30C) +#define RCC_MP_AHB5LPENSETR		U(0x310) +#define RCC_MP_AHB5LPENCLRR		U(0x314) +#define RCC_MP_AHB6LPENSETR		U(0x318) +#define RCC_MP_AHB6LPENCLRR		U(0x31C) +#define RCC_MP_TZAHB6LPENSETR		U(0x320) +#define RCC_MP_TZAHB6LPENCLRR		U(0x324) +#define RCC_BR_RSTSCLRR			U(0x400) +#define RCC_MP_GRSTCSETR		U(0x404) +#define RCC_MP_RSTSCLRR			U(0x408) +#define RCC_MP_IWDGFZSETR		U(0x40C) +#define RCC_MP_IWDGFZCLRR		U(0x410) +#define RCC_MP_CIER			U(0x414) +#define RCC_MP_CIFR			U(0x418) +#define RCC_PWRLPDLYCR			U(0x41C) +#define RCC_MP_RSTSSETR			U(0x420) +#define RCC_MCO1CFGR			U(0x800) +#define RCC_MCO2CFGR			U(0x804) +#define RCC_OCRDYR			U(0x808) +#define RCC_DBGCFGR			U(0x80C) +#define RCC_RCK3SELR			U(0x820) +#define RCC_RCK4SELR			U(0x824) +#define RCC_TIMG1PRER			U(0x828) +#define RCC_TIMG2PRER			U(0x82C) +#define RCC_APB1DIVR			U(0x834) +#define RCC_APB2DIVR			U(0x838) +#define RCC_APB3DIVR			U(0x83C) +#define RCC_PLL3CR			U(0x880) +#define RCC_PLL3CFGR1			U(0x884) +#define RCC_PLL3CFGR2			U(0x888) +#define RCC_PLL3FRACR			U(0x88C) +#define RCC_PLL3CSGR			U(0x890) +#define RCC_PLL4CR			U(0x894) +#define RCC_PLL4CFGR1			U(0x898) +#define RCC_PLL4CFGR2			U(0x89C) +#define RCC_PLL4FRACR			U(0x8A0) +#define RCC_PLL4CSGR			U(0x8A4) +#define RCC_I2C12CKSELR			U(0x8C0) +#define RCC_I2C35CKSELR			U(0x8C4) +#define RCC_SAI1CKSELR			U(0x8C8) +#define RCC_SAI2CKSELR			U(0x8CC) +#define RCC_SAI3CKSELR			U(0x8D0) +#define RCC_SAI4CKSELR			U(0x8D4) +#define RCC_SPI2S1CKSELR		U(0x8D8) +#define RCC_SPI2S23CKSELR		U(0x8DC) +#define RCC_SPI45CKSELR			U(0x8E0) +#define RCC_UART6CKSELR			U(0x8E4) +#define RCC_UART24CKSELR		U(0x8E8) +#define RCC_UART35CKSELR		U(0x8EC) +#define RCC_UART78CKSELR		U(0x8F0) +#define RCC_SDMMC12CKSELR		U(0x8F4) +#define RCC_SDMMC3CKSELR		U(0x8F8) +#define RCC_ETHCKSELR			U(0x8FC) +#define RCC_QSPICKSELR			U(0x900) +#define RCC_FMCCKSELR			U(0x904) +#define RCC_FDCANCKSELR			U(0x90C) +#define RCC_SPDIFCKSELR			U(0x914) +#define RCC_CECCKSELR			U(0x918) +#define RCC_USBCKSELR			U(0x91C) +#define RCC_RNG2CKSELR			U(0x920) +#define RCC_DSICKSELR			U(0x924) +#define RCC_ADCCKSELR			U(0x928) +#define RCC_LPTIM45CKSELR		U(0x92C) +#define RCC_LPTIM23CKSELR		U(0x930) +#define RCC_LPTIM1CKSELR		U(0x934) +#define RCC_APB1RSTSETR			U(0x980) +#define RCC_APB1RSTCLRR			U(0x984) +#define RCC_APB2RSTSETR			U(0x988) +#define RCC_APB2RSTCLRR			U(0x98C) +#define RCC_APB3RSTSETR			U(0x990) +#define RCC_APB3RSTCLRR			U(0x994) +#define RCC_AHB2RSTSETR			U(0x998) +#define RCC_AHB2RSTCLRR			U(0x99C) +#define RCC_AHB3RSTSETR			U(0x9A0) +#define RCC_AHB3RSTCLRR			U(0x9A4) +#define RCC_AHB4RSTSETR			U(0x9A8) +#define RCC_AHB4RSTCLRR			U(0x9AC) +#define RCC_MP_APB1ENSETR		U(0xA00) +#define RCC_MP_APB1ENCLRR		U(0xA04) +#define RCC_MP_APB2ENSETR		U(0xA08) +#define RCC_MP_APB2ENCLRR		U(0xA0C) +#define RCC_MP_APB3ENSETR		U(0xA10) +#define RCC_MP_APB3ENCLRR		U(0xA14) +#define RCC_MP_AHB2ENSETR		U(0xA18) +#define RCC_MP_AHB2ENCLRR		U(0xA1C) +#define RCC_MP_AHB3ENSETR		U(0xA20) +#define RCC_MP_AHB3ENCLRR		U(0xA24) +#define RCC_MP_AHB4ENSETR		U(0xA28) +#define RCC_MP_AHB4ENCLRR		U(0xA2C) +#define RCC_MP_MLAHBENSETR		U(0xA38) +#define RCC_MP_MLAHBENCLRR		U(0xA3C) +#define RCC_MP_APB1LPENSETR		U(0xB00) +#define RCC_MP_APB1LPENCLRR		U(0xB04) +#define RCC_MP_APB2LPENSETR		U(0xB08) +#define RCC_MP_APB2LPENCLRR		U(0xB0C) +#define RCC_MP_APB3LPENSETR		U(0xB10) +#define RCC_MP_APB3LPENCLRR		U(0xB14) +#define RCC_MP_AHB2LPENSETR		U(0xB18) +#define RCC_MP_AHB2LPENCLRR		U(0xB1C) +#define RCC_MP_AHB3LPENSETR		U(0xB20) +#define RCC_MP_AHB3LPENCLRR		U(0xB24) +#define RCC_MP_AHB4LPENSETR		U(0xB28) +#define RCC_MP_AHB4LPENCLRR		U(0xB2C) +#define RCC_MP_AXIMLPENSETR		U(0xB30) +#define RCC_MP_AXIMLPENCLRR		U(0xB34) +#define RCC_MP_MLAHBLPENSETR		U(0xB38) +#define RCC_MP_MLAHBLPENCLRR		U(0xB3C) +#define RCC_VERR			U(0xFF4) +#define RCC_IDR				U(0xFF8) +#define RCC_SIDR			U(0xFFC) + +/* Values for RCC_TZCR register */ +#define RCC_TZCR_TZEN			BIT(0) + +/* Used for most of RCC_<x>SELR registers */ +#define RCC_SELR_SRC_MASK		GENMASK(2, 0) +#define RCC_SELR_REFCLK_SRC_MASK	GENMASK(1, 0) +#define RCC_SELR_SRCRDY			BIT(31) + +/* Values of RCC_MPCKSELR register */ +#define RCC_MPCKSELR_HSI		0x00000000 +#define RCC_MPCKSELR_HSE		0x00000001 +#define RCC_MPCKSELR_PLL		0x00000002 +#define RCC_MPCKSELR_PLL_MPUDIV		0x00000003 + +/* Values of RCC_ASSCKSELR register */ +#define RCC_ASSCKSELR_HSI		0x00000000 +#define RCC_ASSCKSELR_HSE		0x00000001 +#define RCC_ASSCKSELR_PLL		0x00000002 + +/* Values of RCC_MSSCKSELR register */ +#define RCC_MSSCKSELR_HSI		0x00000000 +#define RCC_MSSCKSELR_HSE		0x00000001 +#define RCC_MSSCKSELR_CSI		0x00000002 +#define RCC_MSSCKSELR_PLL		0x00000003 + +/* Values of RCC_CPERCKSELR register */ +#define RCC_CPERCKSELR_HSI		0x00000000 +#define RCC_CPERCKSELR_CSI		0x00000001 +#define RCC_CPERCKSELR_HSE		0x00000002 + +/* Used for most of DIVR register: max div for RTC */ +#define RCC_DIVR_DIV_MASK		GENMASK(5, 0) +#define RCC_DIVR_DIVRDY			BIT(31) + +/* Masks for specific DIVR registers */ +#define RCC_APBXDIV_MASK		GENMASK(2, 0) +#define RCC_MPUDIV_MASK			GENMASK(2, 0) +#define RCC_AXIDIV_MASK			GENMASK(2, 0) + +/* Offset between RCC_MP_xxxENSETR and RCC_MP_xxxENCLRR registers */ +#define RCC_MP_ENCLRR_OFFSET		U(4) + +/* Fields of RCC_BDCR register */ +#define RCC_BDCR_LSEON			BIT(0) +#define RCC_BDCR_LSEBYP			BIT(1) +#define RCC_BDCR_LSERDY			BIT(2) +#define RCC_BDCR_LSEDRV_MASK		GENMASK(5, 4) +#define RCC_BDCR_LSEDRV_SHIFT		4 +#define RCC_BDCR_LSECSSON		BIT(8) +#define RCC_BDCR_RTCCKEN		BIT(20) +#define RCC_BDCR_RTCSRC_MASK		GENMASK(17, 16) +#define RCC_BDCR_RTCSRC_SHIFT		16 +#define RCC_BDCR_VSWRST			BIT(31) + +/* Fields of RCC_RDLSICR register */ +#define RCC_RDLSICR_LSION		BIT(0) +#define RCC_RDLSICR_LSIRDY		BIT(1) + +/* Used for all RCC_PLL<n>CR registers */ +#define RCC_PLLNCR_PLLON		BIT(0) +#define RCC_PLLNCR_PLLRDY		BIT(1) +#define RCC_PLLNCR_DIVPEN		BIT(4) +#define RCC_PLLNCR_DIVQEN		BIT(5) +#define RCC_PLLNCR_DIVREN		BIT(6) +#define RCC_PLLNCR_DIVEN_SHIFT		4 + +/* Used for all RCC_PLL<n>CFGR1 registers */ +#define RCC_PLLNCFGR1_DIVM_SHIFT	16 +#define RCC_PLLNCFGR1_DIVM_MASK		GENMASK(21, 16) +#define RCC_PLLNCFGR1_DIVN_SHIFT	0 +#define RCC_PLLNCFGR1_DIVN_MASK		GENMASK(8, 0) +/* Only for PLL3 and PLL4 */ +#define RCC_PLLNCFGR1_IFRGE_SHIFT	24 +#define RCC_PLLNCFGR1_IFRGE_MASK	GENMASK(25, 24) + +/* Used for all RCC_PLL<n>CFGR2 registers */ +#define RCC_PLLNCFGR2_DIVX_MASK		GENMASK(6, 0) +#define RCC_PLLNCFGR2_DIVP_SHIFT	0 +#define RCC_PLLNCFGR2_DIVP_MASK		GENMASK(6, 0) +#define RCC_PLLNCFGR2_DIVQ_SHIFT	8 +#define RCC_PLLNCFGR2_DIVQ_MASK		GENMASK(14, 8) +#define RCC_PLLNCFGR2_DIVR_SHIFT	16 +#define RCC_PLLNCFGR2_DIVR_MASK		GENMASK(22, 16) + +/* Used for all RCC_PLL<n>FRACR registers */ +#define RCC_PLLNFRACR_FRACV_SHIFT	3 +#define RCC_PLLNFRACR_FRACV_MASK	GENMASK(15, 3) +#define RCC_PLLNFRACR_FRACLE		BIT(16) + +/* Used for all RCC_PLL<n>CSGR registers */ +#define RCC_PLLNCSGR_INC_STEP_SHIFT	16 +#define RCC_PLLNCSGR_INC_STEP_MASK	GENMASK(30, 16) +#define RCC_PLLNCSGR_MOD_PER_SHIFT	0 +#define RCC_PLLNCSGR_MOD_PER_MASK	GENMASK(12, 0) +#define RCC_PLLNCSGR_SSCG_MODE_SHIFT	15 +#define RCC_PLLNCSGR_SSCG_MODE_MASK	BIT(15) + +/* Used for RCC_OCENSETR and RCC_OCENCLRR registers */ +#define RCC_OCENR_HSION			BIT(0) +#define RCC_OCENR_CSION			BIT(4) +#define RCC_OCENR_HSEON			BIT(8) +#define RCC_OCENR_HSEBYP		BIT(10) +#define RCC_OCENR_HSECSSON		BIT(11) + +/* Fields of RCC_OCRDYR register */ +#define RCC_OCRDYR_HSIRDY		BIT(0) +#define RCC_OCRDYR_HSIDIVRDY		BIT(2) +#define RCC_OCRDYR_CSIRDY		BIT(4) +#define RCC_OCRDYR_HSERDY		BIT(8) + +/* Fields of RCC_DDRITFCR register */ +#define RCC_DDRITFCR_DDRC1EN		BIT(0) +#define RCC_DDRITFCR_DDRC1LPEN		BIT(1) +#define RCC_DDRITFCR_DDRC2EN		BIT(2) +#define RCC_DDRITFCR_DDRC2LPEN		BIT(3) +#define RCC_DDRITFCR_DDRPHYCEN		BIT(4) +#define RCC_DDRITFCR_DDRPHYCLPEN	BIT(5) +#define RCC_DDRITFCR_DDRCAPBEN		BIT(6) +#define RCC_DDRITFCR_DDRCAPBLPEN	BIT(7) +#define RCC_DDRITFCR_AXIDCGEN		BIT(8) +#define RCC_DDRITFCR_DDRPHYCAPBEN	BIT(9) +#define RCC_DDRITFCR_DDRPHYCAPBLPEN	BIT(10) +#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) +#define RCC_DDRITFCR_DDRCKMOD_MASK	GENMASK(22, 20) +#define RCC_DDRITFCR_DDRCKMOD_SHIFT	20 +#define RCC_DDRITFCR_DDRCKMOD_SSR	0 +#define RCC_DDRITFCR_DDRCKMOD_ASR1	BIT(20) +#define RCC_DDRITFCR_DDRCKMOD_HSR1	BIT(21) +#define RCC_DDRITFCR_GSKPCTRL		BIT(24) + +/* Fields of RCC_HSICFGR register */ +#define RCC_HSICFGR_HSIDIV_MASK		GENMASK(1, 0) + +/* Used for RCC_MCO related operations */ +#define RCC_MCOCFG_MCOON		BIT(12) +#define RCC_MCOCFG_MCODIV_MASK		GENMASK(7, 4) +#define RCC_MCOCFG_MCODIV_SHIFT		4 +#define RCC_MCOCFG_MCOSRC_MASK		GENMASK(2, 0) + +/* Fields of RCC_DBGCFGR register */ +#define RCC_DBGCFGR_DBGCKEN		BIT(8) + +/* RCC register fields for reset reasons */ +#define  RCC_MP_RSTSCLRR_PORRSTF	BIT(0) +#define  RCC_MP_RSTSCLRR_BORRSTF	BIT(1) +#define  RCC_MP_RSTSCLRR_PADRSTF	BIT(2) +#define  RCC_MP_RSTSCLRR_HCSSRSTF	BIT(3) +#define  RCC_MP_RSTSCLRR_VCORERSTF	BIT(4) +#define  RCC_MP_RSTSCLRR_MPSYSRSTF	BIT(6) +#define  RCC_MP_RSTSCLRR_IWDG1RSTF	BIT(8) +#define  RCC_MP_RSTSCLRR_IWDG2RSTF	BIT(9) +#define  RCC_MP_RSTSCLRR_STDBYRSTF	BIT(11) +#define  RCC_MP_RSTSCLRR_CSTDBYRSTF	BIT(12) + +/* Global Reset Register */ +#define RCC_MP_GRSTCSETR_MPSYSRST	BIT(0) + +/* Clock Source Interrupt Flag Register */ +#define RCC_MP_CIFR_MASK		U(0x110F1F) +#define RCC_MP_CIFR_WKUPF		BIT(20) + +/* Stop Request Set Register */ +#define RCC_MP_SREQSETR_STPREQ_P0	BIT(0) +#define RCC_MP_SREQSETR_STPREQ_P1	BIT(1) + +/* Stop Request Clear Register */ +#define RCC_MP_SREQCLRR_STPREQ_P0	BIT(0) +#define RCC_MP_SREQCLRR_STPREQ_P1	BIT(1) + +/* Values of RCC_UART24CKSELR register */ +#define RCC_UART24CKSELR_HSI		0x00000002 + +/* Values of RCC_MP_APB1ENSETR register */ +#define RCC_MP_APB1ENSETR_UART4EN	BIT(16) + +/* Values of RCC_MP_AHB4ENSETR register */ +#define RCC_MP_AHB4ENSETR_GPIOGEN	BIT(6) + +#endif /* __STM32MP1_RCC_H__ */ diff --git a/include/drivers/st/stm32mp1_reset.h b/include/drivers/st/stm32mp1_reset.h new file mode 100644 index 00000000..76ee09d8 --- /dev/null +++ b/include/drivers/st/stm32mp1_reset.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __STM32MP1_RESET_H__ +#define __STM32MP1_RESET_H__ + +#include <stdint.h> + +void stm32mp1_reset_assert(uint32_t reset_id); +void stm32mp1_reset_deassert(uint32_t reset_id); + +#endif /* __STM32MP1_RESET_H__ */ diff --git a/include/drivers/st/stpmu1.h b/include/drivers/st/stpmu1.h new file mode 100644 index 00000000..1b93ab2c --- /dev/null +++ b/include/drivers/st/stpmu1.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + + +#ifndef __STPMU1_H__ +#define __STPMU1_H__ + +#include <stm32_i2c.h> +#include <utils_def.h> + +#define TURN_ON_REG			0x1U +#define TURN_OFF_REG			0x2U +#define ICC_LDO_TURN_OFF_REG		0x3U +#define ICC_BUCK_TURN_OFF_REG		0x4U +#define RESET_STATUS_REG		0x5U +#define VERSION_STATUS_REG		0x6U +#define MAIN_CONTROL_REG		0x10U +#define PADS_PULL_REG			0x11U +#define BUCK_PULL_DOWN_REG		0x12U +#define LDO14_PULL_DOWN_REG		0x13U +#define LDO56_PULL_DOWN_REG		0x14U +#define VIN_CONTROL_REG			0x15U +#define PONKEY_TIMER_REG		0x16U +#define MASK_RANK_BUCK_REG		0x17U +#define MASK_RESET_BUCK_REG		0x18U +#define MASK_RANK_LDO_REG		0x19U +#define MASK_RESET_LDO_REG		0x1AU +#define WATCHDOG_CONTROL_REG		0x1BU +#define WATCHDOG_TIMER_REG		0x1CU +#define BUCK_ICC_TURNOFF_REG		0x1DU +#define LDO_ICC_TURNOFF_REG		0x1EU +#define BUCK_APM_CONTROL_REG		0x1FU +#define BUCK1_CONTROL_REG		0x20U +#define BUCK2_CONTROL_REG		0x21U +#define BUCK3_CONTROL_REG		0x22U +#define BUCK4_CONTROL_REG		0x23U +#define VREF_DDR_CONTROL_REG		0x24U +#define LDO1_CONTROL_REG		0x25U +#define LDO2_CONTROL_REG		0x26U +#define LDO3_CONTROL_REG		0x27U +#define LDO4_CONTROL_REG		0x28U +#define LDO5_CONTROL_REG		0x29U +#define LDO6_CONTROL_REG		0x2AU +#define BUCK1_PWRCTRL_REG		0x30U +#define BUCK2_PWRCTRL_REG		0x31U +#define BUCK3_PWRCTRL_REG		0x32U +#define BUCK4_PWRCTRL_REG		0x33U +#define VREF_DDR_PWRCTRL_REG		0x34U +#define LDO1_PWRCTRL_REG		0x35U +#define LDO2_PWRCTRL_REG		0x36U +#define LDO3_PWRCTRL_REG		0x37U +#define LDO4_PWRCTRL_REG		0x38U +#define LDO5_PWRCTRL_REG		0x39U +#define LDO6_PWRCTRL_REG		0x3AU +#define FREQUENCY_SPREADING_REG		0x3BU +#define USB_CONTROL_REG			0x40U +#define ITLATCH1_REG			0x50U +#define ITLATCH2_REG			0x51U +#define ITLATCH3_REG			0x52U +#define ITLATCH4_REG			0x53U +#define ITSETLATCH1_REG			0x60U +#define ITSETLATCH2_REG			0x61U +#define ITSETLATCH3_REG			0x62U +#define ITSETLATCH4_REG			0x63U +#define ITCLEARLATCH1_REG		0x70U +#define ITCLEARLATCH2_REG		0x71U +#define ITCLEARLATCH3_REG		0x72U +#define ITCLEARLATCH4_REG		0x73U +#define ITMASK1_REG			0x80U +#define ITMASK2_REG			0x81U +#define ITMASK3_REG			0x82U +#define ITMASK4_REG			0x83U +#define ITSETMASK1_REG			0x90U +#define ITSETMASK2_REG			0x91U +#define ITSETMASK3_REG			0x92U +#define ITSETMASK4_REG			0x93U +#define ITCLEARMASK1_REG		0xA0U +#define ITCLEARMASK2_REG		0xA1U +#define ITCLEARMASK3_REG		0xA2U +#define ITCLEARMASK4_REG		0xA3U +#define ITSOURCE1_REG			0xB0U +#define ITSOURCE2_REG			0xB1U +#define ITSOURCE3_REG			0xB2U +#define ITSOURCE4_REG			0xB3U +#define LDO_VOLTAGE_MASK		0x7CU +#define BUCK_VOLTAGE_MASK		0xFCU +#define LDO_BUCK_VOLTAGE_SHIFT		2 +#define LDO_ENABLE_MASK			0x01U +#define BUCK_ENABLE_MASK		0x01U +#define BUCK_HPLP_ENABLE_MASK		0x02U +#define LDO_HPLP_ENABLE_MASK		0x02U +#define LDO_BUCK_HPLP_SHIFT		1 +#define LDO_BUCK_RANK_MASK		0x01U +#define LDO_BUCK_RESET_MASK		0x01U +#define LDO_BUCK_PULL_DOWN_MASK		0x03U + +/* Main PMIC Control Register (MAIN_CONTROL_REG) */ +#define ICC_EVENT_ENABLED		BIT(4) +#define PWRCTRL_POLARITY_HIGH		BIT(3) +#define PWRCTRL_PIN_VALID		BIT(2) +#define RESTART_REQUEST_ENABLED		BIT(1) +#define SOFTWARE_SWITCH_OFF_ENABLED	BIT(0) + +/* Main PMIC PADS Control Register (PADS_PULL_REG) */ +#define WAKEUP_DETECTOR_DISABLED	BIT(4) +#define PWRCTRL_PD_ACTIVE		BIT(3) +#define PWRCTRL_PU_ACTIVE		BIT(2) +#define WAKEUP_PD_ACTIVE		BIT(1) +#define PONKEY_PU_ACTIVE		BIT(0) + +/* Main PMIC VINLOW Control Register (VIN_CONTROL_REGC DMSC) */ +#define SWIN_DETECTOR_ENABLED		BIT(7) +#define SWOUT_DETECTOR_ENABLED          BIT(6) +#define VINLOW_HYST_MASK		0x3 +#define VINLOW_HYST_SHIFT		4 +#define VINLOW_THRESHOLD_MASK		0x7 +#define VINLOW_THRESHOLD_SHIFT		1 +#define VINLOW_ENABLED			0x01 +#define VINLOW_CTRL_REG_MASK		0xFF + +/* USB Control Register */ +#define BOOST_OVP_DISABLED		BIT(7) +#define VBUS_OTG_DETECTION_DISABLED	BIT(6) +#define OCP_LIMIT_HIGH			BIT(3) +#define SWIN_SWOUT_ENABLED		BIT(2) +#define USBSW_OTG_SWITCH_ENABLED	BIT(1) + +int stpmu1_switch_off(void); +int stpmu1_register_read(uint8_t register_id, uint8_t *value); +int stpmu1_register_write(uint8_t register_id, uint8_t value); +int stpmu1_register_update(uint8_t register_id, uint8_t value, uint8_t mask); +int stpmu1_regulator_enable(const char *name); +int stpmu1_regulator_disable(const char *name); +uint8_t stpmu1_is_regulator_enabled(const char *name); +int stpmu1_regulator_voltage_set(const char *name, uint16_t millivolts); +void stpmu1_bind_i2c(struct i2c_handle_s *i2c_handle, uint16_t i2c_addr); + +#endif /* __STPMU1_H__ */ diff --git a/include/dt-bindings/clock/stm32mp1-clks.h b/include/dt-bindings/clock/stm32mp1-clks.h new file mode 100644 index 00000000..18bdb57f --- /dev/null +++ b/include/dt-bindings/clock/stm32mp1-clks.h @@ -0,0 +1,251 @@ +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + * Author: Gabriel Fernandez <gabriel.fernandez@st.com> for STMicroelectronics. + */ + +#ifndef _DT_BINDINGS_STM32MP1_CLKS_H_ +#define _DT_BINDINGS_STM32MP1_CLKS_H_ + +/* OSCILLATOR clocks */ +#define CK_HSE		0 +#define CK_CSI		1 +#define CK_LSI		2 +#define CK_LSE		3 +#define CK_HSI		4 +#define CK_HSE_DIV2	5 + +/* Bus clocks */ +#define TIM2		6 +#define TIM3		7 +#define TIM4		8 +#define TIM5		9 +#define TIM6		10 +#define TIM7		11 +#define TIM12		12 +#define TIM13		13 +#define TIM14		14 +#define LPTIM1		15 +#define SPI2		16 +#define SPI3		17 +#define USART2		18 +#define USART3		19 +#define UART4		20 +#define UART5		21 +#define UART7		22 +#define UART8		23 +#define I2C1		24 +#define I2C2		25 +#define I2C3		26 +#define I2C5		27 +#define SPDIF		28 +#define CEC		29 +#define DAC12		30 +#define MDIO		31 +#define TIM1		32 +#define TIM8		33 +#define TIM15		34 +#define TIM16		35 +#define TIM17		36 +#define SPI1		37 +#define SPI4		38 +#define SPI5		39 +#define USART6		40 +#define SAI1		41 +#define SAI2		42 +#define SAI3		43 +#define DFSDM		44 +#define FDCAN		45 +#define LPTIM2		46 +#define LPTIM3		47 +#define LPTIM4		48 +#define LPTIM5		49 +#define SAI4		50 +#define SYSCFG		51 +#define VREF		52 +#define TMPSENS		53 +#define PMBCTRL		54 +#define HDP		55 +#define LTDC		56 +#define DSI		57 +#define IWDG2		58 +#define USBPHY		59 +#define STGENRO		60 +#define SPI6		61 +#define I2C4		62 +#define I2C6		63 +#define USART1		64 +#define RTCAPB		65 +#define TZC1		66 +#define TZPC		67 +#define IWDG1		68 +#define BSEC		69 +#define STGEN		70 +#define DMA1		71 +#define DMA2		72 +#define DMAMUX		73 +#define ADC12		74 +#define USBO		75 +#define SDMMC3		76 +#define DCMI		77 +#define CRYP2		78 +#define HASH2		79 +#define RNG2		80 +#define CRC2		81 +#define HSEM		82 +#define IPCC		83 +#define GPIOA		84 +#define GPIOB		85 +#define GPIOC		86 +#define GPIOD		87 +#define GPIOE		88 +#define GPIOF		89 +#define GPIOG		90 +#define GPIOH		91 +#define GPIOI		92 +#define GPIOJ		93 +#define GPIOK		94 +#define GPIOZ		95 +#define CRYP1		96 +#define HASH1		97 +#define RNG1		98 +#define BKPSRAM		99 +#define MDMA		100 +#define GPU		101 +#define ETHCK		102 +#define ETHTX		103 +#define ETHRX		104 +#define ETHMAC		105 +#define FMC		106 +#define QSPI		107 +#define SDMMC1		108 +#define SDMMC2		109 +#define CRC1		110 +#define USBH		111 +#define ETHSTP		112 +#define TZC2		113 + +/* Kernel clocks */ +#define SDMMC1_K	118 +#define SDMMC2_K	119 +#define SDMMC3_K	120 +#define FMC_K		121 +#define QSPI_K		122 +#define ETHCK_K		123 +#define RNG1_K		124 +#define RNG2_K		125 +#define GPU_K		126 +#define USBPHY_K	127 +#define STGEN_K		128 +#define SPDIF_K		129 +#define SPI1_K		130 +#define SPI2_K		131 +#define SPI3_K		132 +#define SPI4_K		133 +#define SPI5_K		134 +#define SPI6_K		135 +#define CEC_K		136 +#define I2C1_K		137 +#define I2C2_K		138 +#define I2C3_K		139 +#define I2C4_K		140 +#define I2C5_K		141 +#define I2C6_K		142 +#define LPTIM1_K	143 +#define LPTIM2_K	144 +#define LPTIM3_K	145 +#define LPTIM4_K	146 +#define LPTIM5_K	147 +#define USART1_K	148 +#define USART2_K	149 +#define USART3_K	150 +#define UART4_K		151 +#define UART5_K		152 +#define USART6_K	153 +#define UART7_K		154 +#define UART8_K		155 +#define DFSDM_K		156 +#define FDCAN_K		157 +#define SAI1_K		158 +#define SAI2_K		159 +#define SAI3_K		160 +#define SAI4_K		161 +#define ADC12_K		162 +#define DSI_K		163 +#define DSI_PX		164 +#define ADFSDM_K	165 +#define USBO_K		166 +#define LTDC_PX		167 +#define DAC12_K		168 +#define ETHPTP_K	169 + +/* PLL */ +#define PLL1		176 +#define PLL2		177 +#define PLL3		178 +#define PLL4		179 + +/* ODF */ +#define PLL1_P		180 +#define PLL1_Q		181 +#define PLL1_R		182 +#define PLL2_P		183 +#define PLL2_Q		184 +#define PLL2_R		185 +#define PLL3_P		186 +#define PLL3_Q		187 +#define PLL3_R		188 +#define PLL4_P		189 +#define PLL4_Q		190 +#define PLL4_R		191 + +/* AUX */ +#define RTC		192 + +/* MCLK */ +#define CK_PER		193 +#define CK_MPU		194 +#define CK_AXI		195 +#define CK_MCU		196 + +/* Time base */ +#define TIM2_K		197 +#define TIM3_K		198 +#define TIM4_K		199 +#define TIM5_K		200 +#define TIM6_K		201 +#define TIM7_K		202 +#define TIM12_K		203 +#define TIM13_K		204 +#define TIM14_K		205 +#define TIM1_K		206 +#define TIM8_K		207 +#define TIM15_K		208 +#define TIM16_K		209 +#define TIM17_K		210 + +/* MCO clocks */ +#define CK_MCO1		211 +#define CK_MCO2		212 + +/* TRACE & DEBUG clocks */ +#define CK_DBG		214 +#define CK_TRACE	215 + +/* DDR */ +#define DDRC1		220 +#define DDRC1LP		221 +#define DDRC2		222 +#define DDRC2LP		223 +#define DDRPHYC		224 +#define DDRPHYCLP	225 +#define DDRCAPB		226 +#define DDRCAPBLP	227 +#define AXIDCG		228 +#define DDRPHYCAPB	229 +#define DDRPHYCAPBLP	230 +#define DDRPERFM	231 + +#define STM32MP1_LAST_CLK 232 + +#endif /* _DT_BINDINGS_STM32MP1_CLKS_H_ */ diff --git a/include/dt-bindings/clock/stm32mp1-clksrc.h b/include/dt-bindings/clock/stm32mp1-clksrc.h new file mode 100644 index 00000000..818f4b76 --- /dev/null +++ b/include/dt-bindings/clock/stm32mp1-clksrc.h @@ -0,0 +1,283 @@ +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/* + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved + */ + +#ifndef _DT_BINDINGS_CLOCK_STM32MP1_CLKSRC_H_ +#define _DT_BINDINGS_CLOCK_STM32MP1_CLKSRC_H_ + +/* PLL output is enable when x=1, with x=p,q or r */ +#define PQR(p, q, r)	(((p) & 1) | (((q) & 1) << 1) | (((r) & 1) << 2)) + +/* st,clksrc: mandatory clock source */ + +#define CLK_MPU_HSI		0x00000200 +#define CLK_MPU_HSE		0x00000201 +#define CLK_MPU_PLL1P		0x00000202 +#define CLK_MPU_PLL1P_DIV	0x00000203 + +#define CLK_AXI_HSI		0x00000240 +#define CLK_AXI_HSE		0x00000241 +#define CLK_AXI_PLL2P		0x00000242 + +#define CLK_MCU_HSI		0x00000480 +#define CLK_MCU_HSE		0x00000481 +#define CLK_MCU_CSI		0x00000482 +#define CLK_MCU_PLL3P		0x00000483 + +#define CLK_PLL12_HSI		0x00000280 +#define CLK_PLL12_HSE		0x00000281 + +#define CLK_PLL3_HSI		0x00008200 +#define CLK_PLL3_HSE		0x00008201 +#define CLK_PLL3_CSI		0x00008202 + +#define CLK_PLL4_HSI		0x00008240 +#define CLK_PLL4_HSE		0x00008241 +#define CLK_PLL4_CSI		0x00008242 +#define CLK_PLL4_I2SCKIN	0x00008243 + +#define CLK_RTC_DISABLED	0x00001400 +#define CLK_RTC_LSE		0x00001401 +#define CLK_RTC_LSI		0x00001402 +#define CLK_RTC_HSE		0x00001403 + +#define CLK_MCO1_HSI		0x00008000 +#define CLK_MCO1_HSE		0x00008001 +#define CLK_MCO1_CSI		0x00008002 +#define CLK_MCO1_LSI		0x00008003 +#define CLK_MCO1_LSE		0x00008004 +#define CLK_MCO1_DISABLED	0x0000800F + +#define CLK_MCO2_MPU		0x00008040 +#define CLK_MCO2_AXI		0x00008041 +#define CLK_MCO2_MCU		0x00008042 +#define CLK_MCO2_PLL4P		0x00008043 +#define CLK_MCO2_HSE		0x00008044 +#define CLK_MCO2_HSI		0x00008045 +#define CLK_MCO2_DISABLED	0x0000804F + +/* st,pkcs: peripheral kernel clock source */ + +#define CLK_I2C12_PCLK1		0x00008C00 +#define CLK_I2C12_PLL4R		0x00008C01 +#define CLK_I2C12_HSI		0x00008C02 +#define CLK_I2C12_CSI		0x00008C03 +#define CLK_I2C12_DISABLED	0x00008C07 + +#define CLK_I2C35_PCLK1		0x00008C40 +#define CLK_I2C35_PLL4R		0x00008C41 +#define CLK_I2C35_HSI		0x00008C42 +#define CLK_I2C35_CSI		0x00008C43 +#define CLK_I2C35_DISABLED	0x00008C47 + +#define CLK_I2C46_PCLK5		0x00000C00 +#define CLK_I2C46_PLL3Q		0x00000C01 +#define CLK_I2C46_HSI		0x00000C02 +#define CLK_I2C46_CSI		0x00000C03 +#define CLK_I2C46_DISABLED	0x00000C07 + +#define CLK_SAI1_PLL4Q		0x00008C80 +#define CLK_SAI1_PLL3Q		0x00008C81 +#define CLK_SAI1_I2SCKIN	0x00008C82 +#define CLK_SAI1_CKPER		0x00008C83 +#define CLK_SAI1_PLL3R		0x00008C84 +#define CLK_SAI1_DISABLED	0x00008C87 + +#define CLK_SAI2_PLL4Q		0x00008CC0 +#define CLK_SAI2_PLL3Q		0x00008CC1 +#define CLK_SAI2_I2SCKIN	0x00008CC2 +#define CLK_SAI2_CKPER		0x00008CC3 +#define CLK_SAI2_SPDIF		0x00008CC4 +#define CLK_SAI2_PLL3R		0x00008CC5 +#define CLK_SAI2_DISABLED	0x00008CC7 + +#define CLK_SAI3_PLL4Q		0x00008D00 +#define CLK_SAI3_PLL3Q		0x00008D01 +#define CLK_SAI3_I2SCKIN	0x00008D02 +#define CLK_SAI3_CKPER		0x00008D03 +#define CLK_SAI3_PLL3R		0x00008D04 +#define CLK_SAI3_DISABLED	0x00008D07 + +#define CLK_SAI4_PLL4Q		0x00008D40 +#define CLK_SAI4_PLL3Q		0x00008D41 +#define CLK_SAI4_I2SCKIN	0x00008D42 +#define CLK_SAI4_CKPER		0x00008D43 +#define CLK_SAI4_PLL3R		0x00008D44 +#define CLK_SAI4_DISABLED	0x00008D47 + +#define CLK_SPI2S1_PLL4P	0x00008D80 +#define CLK_SPI2S1_PLL3Q	0x00008D81 +#define CLK_SPI2S1_I2SCKIN	0x00008D82 +#define CLK_SPI2S1_CKPER	0x00008D83 +#define CLK_SPI2S1_PLL3R	0x00008D84 +#define CLK_SPI2S1_DISABLED	0x00008D87 + +#define CLK_SPI2S23_PLL4P	0x00008DC0 +#define CLK_SPI2S23_PLL3Q	0x00008DC1 +#define CLK_SPI2S23_I2SCKIN	0x00008DC2 +#define CLK_SPI2S23_CKPER	0x00008DC3 +#define CLK_SPI2S23_PLL3R	0x00008DC4 +#define CLK_SPI2S23_DISABLED	0x00008DC7 + +#define CLK_SPI45_PCLK2		0x00008E00 +#define CLK_SPI45_PLL4Q		0x00008E01 +#define CLK_SPI45_HSI		0x00008E02 +#define CLK_SPI45_CSI		0x00008E03 +#define CLK_SPI45_HSE		0x00008E04 +#define CLK_SPI45_DISABLED	0x00008E07 + +#define CLK_SPI6_PCLK5		0x00000C40 +#define CLK_SPI6_PLL4Q		0x00000C41 +#define CLK_SPI6_HSI		0x00000C42 +#define CLK_SPI6_CSI		0x00000C43 +#define CLK_SPI6_HSE		0x00000C44 +#define CLK_SPI6_PLL3Q		0x00000C45 +#define CLK_SPI6_DISABLED	0x00000C47 + +#define CLK_UART6_PCLK2		0x00008E40 +#define CLK_UART6_PLL4Q		0x00008E41 +#define CLK_UART6_HSI		0x00008E42 +#define CLK_UART6_CSI		0x00008E43 +#define CLK_UART6_HSE		0x00008E44 +#define CLK_UART6_DISABLED	0x00008E47 + +#define CLK_UART24_PCLK1	0x00008E80 +#define CLK_UART24_PLL4Q	0x00008E81 +#define CLK_UART24_HSI		0x00008E82 +#define CLK_UART24_CSI		0x00008E83 +#define CLK_UART24_HSE		0x00008E84 +#define CLK_UART24_DISABLED	0x00008E87 + +#define CLK_UART35_PCLK1	0x00008EC0 +#define CLK_UART35_PLL4Q	0x00008EC1 +#define CLK_UART35_HSI		0x00008EC2 +#define CLK_UART35_CSI		0x00008EC3 +#define CLK_UART35_HSE		0x00008EC4 +#define CLK_UART35_DISABLED	0x00008EC7 + +#define CLK_UART78_PCLK1	0x00008F00 +#define CLK_UART78_PLL4Q	0x00008F01 +#define CLK_UART78_HSI		0x00008F02 +#define CLK_UART78_CSI		0x00008F03 +#define CLK_UART78_HSE		0x00008F04 +#define CLK_UART78_DISABLED	0x00008F07 + +#define CLK_UART1_PCLK5		0x00000C80 +#define CLK_UART1_PLL3Q		0x00000C81 +#define CLK_UART1_HSI		0x00000C82 +#define CLK_UART1_CSI		0x00000C83 +#define CLK_UART1_PLL4Q		0x00000C84 +#define CLK_UART1_HSE		0x00000C85 +#define CLK_UART1_DISABLED	0x00000C87 + +#define CLK_SDMMC12_HCLK6	0x00008F40 +#define CLK_SDMMC12_PLL3R	0x00008F41 +#define CLK_SDMMC12_PLL4P	0x00008F42 +#define CLK_SDMMC12_HSI		0x00008F43 +#define CLK_SDMMC12_DISABLED	0x00008F47 + +#define CLK_SDMMC3_HCLK2	0x00008F80 +#define CLK_SDMMC3_PLL3R	0x00008F81 +#define CLK_SDMMC3_PLL4P	0x00008F82 +#define CLK_SDMMC3_HSI		0x00008F83 +#define CLK_SDMMC3_DISABLED	0x00008F87 + +#define CLK_ETH_PLL4P		0x00008FC0 +#define CLK_ETH_PLL3Q		0x00008FC1 +#define CLK_ETH_DISABLED	0x00008FC3 + +#define CLK_QSPI_ACLK		0x00009000 +#define CLK_QSPI_PLL3R		0x00009001 +#define CLK_QSPI_PLL4P		0x00009002 +#define CLK_QSPI_CKPER		0x00009003 + +#define CLK_FMC_ACLK		0x00009040 +#define CLK_FMC_PLL3R		0x00009041 +#define CLK_FMC_PLL4P		0x00009042 +#define CLK_FMC_CKPER		0x00009043 + +#define CLK_FDCAN_HSE		0x000090C0 +#define CLK_FDCAN_PLL3Q		0x000090C1 +#define CLK_FDCAN_PLL4Q		0x000090C2 +#define CLK_FDCAN_PLL4R		0x000090C3 + +#define CLK_SPDIF_PLL4P		0x00009140 +#define CLK_SPDIF_PLL3Q		0x00009141 +#define CLK_SPDIF_HSI		0x00009142 +#define CLK_SPDIF_DISABLED	0x00009143 + +#define CLK_CEC_LSE		0x00009180 +#define CLK_CEC_LSI		0x00009181 +#define CLK_CEC_CSI_DIV122	0x00009182 +#define CLK_CEC_DISABLED	0x00009183 + +#define CLK_USBPHY_HSE		0x000091C0 +#define CLK_USBPHY_PLL4R	0x000091C1 +#define CLK_USBPHY_HSE_DIV2	0x000091C2 +#define CLK_USBPHY_DISABLED	0x000091C3 + +#define CLK_USBO_PLL4R		0x800091C0 +#define CLK_USBO_USBPHY		0x800091C1 + +#define CLK_RNG1_CSI		0x00000CC0 +#define CLK_RNG1_PLL4R		0x00000CC1 +#define CLK_RNG1_LSE		0x00000CC2 +#define CLK_RNG1_LSI		0x00000CC3 + +#define CLK_RNG2_CSI		0x00009200 +#define CLK_RNG2_PLL4R		0x00009201 +#define CLK_RNG2_LSE		0x00009202 +#define CLK_RNG2_LSI		0x00009203 + +#define CLK_CKPER_HSI		0x00000D00 +#define CLK_CKPER_CSI		0x00000D01 +#define CLK_CKPER_HSE		0x00000D02 +#define CLK_CKPER_DISABLED	0x00000D03 + +#define CLK_STGEN_HSI		0x00000D40 +#define CLK_STGEN_HSE		0x00000D41 +#define CLK_STGEN_DISABLED	0x00000D43 + +#define CLK_DSI_DSIPLL		0x00009240 +#define CLK_DSI_PLL4P		0x00009241 + +#define CLK_ADC_PLL4R		0x00009280 +#define CLK_ADC_CKPER		0x00009281 +#define CLK_ADC_PLL3Q		0x00009282 +#define CLK_ADC_DISABLED	0x00009283 + +#define CLK_LPTIM45_PCLK3	0x000092C0 +#define CLK_LPTIM45_PLL4P	0x000092C1 +#define CLK_LPTIM45_PLL3Q	0x000092C2 +#define CLK_LPTIM45_LSE		0x000092C3 +#define CLK_LPTIM45_LSI		0x000092C4 +#define CLK_LPTIM45_CKPER	0x000092C5 +#define CLK_LPTIM45_DISABLED	0x000092C7 + +#define CLK_LPTIM23_PCLK3	0x00009300 +#define CLK_LPTIM23_PLL4Q	0x00009301 +#define CLK_LPTIM23_CKPER	0x00009302 +#define CLK_LPTIM23_LSE		0x00009303 +#define CLK_LPTIM23_LSI		0x00009304 +#define CLK_LPTIM23_DISABLED	0x00009307 + +#define CLK_LPTIM1_PCLK1	0x00009340 +#define CLK_LPTIM1_PLL4P	0x00009341 +#define CLK_LPTIM1_PLL3Q	0x00009342 +#define CLK_LPTIM1_LSE		0x00009343 +#define CLK_LPTIM1_LSI		0x00009344 +#define CLK_LPTIM1_CKPER	0x00009345 +#define CLK_LPTIM1_DISABLED	0x00009347 + +/* define for st,pll /csg */ +#define SSCG_MODE_CENTER_SPREAD	0 +#define SSCG_MODE_DOWN_SPREAD	1 + +/* define for st,drive */ +#define LSEDRV_LOWEST		0 +#define LSEDRV_MEDIUM_LOW	1 +#define LSEDRV_MEDIUM_HIGH	2 +#define LSEDRV_HIGHEST		3 + +#endif diff --git a/include/dt-bindings/pinctrl/stm32-pinfunc.h b/include/dt-bindings/pinctrl/stm32-pinfunc.h new file mode 100644 index 00000000..e2f1f1b4 --- /dev/null +++ b/include/dt-bindings/pinctrl/stm32-pinfunc.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* + * Copyright (C) STMicroelectronics 2017 - All Rights Reserved + * Author: Torgue Alexandre <alexandre.torgue@st.com> for STMicroelectronics. + */ + +#ifndef _DT_BINDINGS_STM32_PINFUNC_H +#define _DT_BINDINGS_STM32_PINFUNC_H + +/*  define PIN modes */ +#define GPIO	0x0 +#define AF0	0x1 +#define AF1	0x2 +#define AF2	0x3 +#define AF3	0x4 +#define AF4	0x5 +#define AF5	0x6 +#define AF6	0x7 +#define AF7	0x8 +#define AF8	0x9 +#define AF9	0xa +#define AF10	0xb +#define AF11	0xc +#define AF12	0xd +#define AF13	0xe +#define AF14	0xf +#define AF15	0x10 +#define ANALOG	0x11 + +/* define Pins number*/ +#define PIN_NO(port, line)	(((port) - 'A') * 0x10 + (line)) + +#define STM32_PINMUX(port, line, mode) (((PIN_NO(port, line)) << 8) | (mode)) + +#endif /* _DT_BINDINGS_STM32_PINFUNC_H */ diff --git a/include/dt-bindings/reset/stm32mp1-resets.h b/include/dt-bindings/reset/stm32mp1-resets.h new file mode 100644 index 00000000..f0c3aaef --- /dev/null +++ b/include/dt-bindings/reset/stm32mp1-resets.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */ +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + * Author: Gabriel Fernandez <gabriel.fernandez@st.com> for STMicroelectronics. + */ + +#ifndef _DT_BINDINGS_STM32MP1_RESET_H_ +#define _DT_BINDINGS_STM32MP1_RESET_H_ + +#define LTDC_R		3072 +#define DSI_R		3076 +#define DDRPERFM_R	3080 +#define USBPHY_R	3088 +#define SPI6_R		3136 +#define I2C4_R		3138 +#define I2C6_R		3139 +#define USART1_R	3140 +#define STGEN_R		3156 +#define GPIOZ_R		3200 +#define CRYP1_R		3204 +#define HASH1_R		3205 +#define RNG1_R		3206 +#define AXIM_R		3216 +#define GPU_R		3269 +#define ETHMAC_R	3274 +#define FMC_R		3276 +#define QSPI_R		3278 +#define SDMMC1_R	3280 +#define SDMMC2_R	3281 +#define CRC1_R		3284 +#define USBH_R		3288 +#define MDMA_R		3328 +#define MCU_R		8225 +#define TIM2_R		19456 +#define TIM3_R		19457 +#define TIM4_R		19458 +#define TIM5_R		19459 +#define TIM6_R		19460 +#define TIM7_R		19461 +#define TIM12_R		16462 +#define TIM13_R		16463 +#define TIM14_R		16464 +#define LPTIM1_R	19465 +#define SPI2_R		19467 +#define SPI3_R		19468 +#define USART2_R	19470 +#define USART3_R	19471 +#define UART4_R		19472 +#define UART5_R		19473 +#define UART7_R		19474 +#define UART8_R		19475 +#define I2C1_R		19477 +#define I2C2_R		19478 +#define I2C3_R		19479 +#define I2C5_R		19480 +#define SPDIF_R		19482 +#define CEC_R		19483 +#define DAC12_R		19485 +#define MDIO_R		19847 +#define TIM1_R		19520 +#define TIM8_R		19521 +#define TIM15_R		19522 +#define TIM16_R		19523 +#define TIM17_R		19524 +#define SPI1_R		19528 +#define SPI4_R		19529 +#define SPI5_R		19530 +#define USART6_R	19533 +#define SAI1_R		19536 +#define SAI2_R		19537 +#define SAI3_R		19538 +#define DFSDM_R		19540 +#define FDCAN_R		19544 +#define LPTIM2_R	19584 +#define LPTIM3_R	19585 +#define LPTIM4_R	19586 +#define LPTIM5_R	19587 +#define SAI4_R		19592 +#define SYSCFG_R	19595 +#define VREF_R		19597 +#define TMPSENS_R	19600 +#define PMBCTRL_R	19601 +#define DMA1_R		19648 +#define DMA2_R		19649 +#define DMAMUX_R	19650 +#define ADC12_R		19653 +#define USBO_R		19656 +#define SDMMC3_R	19664 +#define CAMITF_R	19712 +#define CRYP2_R		19716 +#define HASH2_R		19717 +#define RNG2_R		19718 +#define CRC2_R		19719 +#define HSEM_R		19723 +#define MBOX_R		19724 +#define GPIOA_R		19776 +#define GPIOB_R		19777 +#define GPIOC_R		19778 +#define GPIOD_R		19779 +#define GPIOE_R		19780 +#define GPIOF_R		19781 +#define GPIOG_R		19782 +#define GPIOH_R		19783 +#define GPIOI_R		19784 +#define GPIOJ_R		19785 +#define GPIOK_R		19786 + +#endif /* _DT_BINDINGS_STM32MP1_RESET_H_ */ diff --git a/maintainers.rst b/maintainers.rst index 76fede82..28127f89 100644 --- a/maintainers.rst +++ b/maintainers.rst @@ -125,6 +125,16 @@ RockChip platform port  :G: `rockchip-linux`_  :F: plat/rockchip/ +STM32MP1 platform port +---------------------- +:M: Yann Gautier <yann.gautier@st.com> +:G: `Yann-lms`_ +:F: docs/plat/stm32mp1.rst +:F: fdts/stm32\* +:F: include/dt-bindings/\*/stm32\* +:F: plat/st/ +:F: tools/stm32image/ +  Synquacer platform port  -----------------------  :M: Sumit Garg <sumit.garg@linaro.org> @@ -184,3 +194,4 @@ Xilinx platform port  .. _soby-mathew: https://github.com/soby-mathew  .. _TonyXie06: https://github.com/TonyXie06  .. _vwadekar: https://github.com/vwadekar +.. _Yann-lms: https://github.com/Yann-lms diff --git a/plat/st/stm32mp1/bl2_io_storage.c b/plat/st/stm32mp1/bl2_io_storage.c new file mode 100644 index 00000000..7346c0cf --- /dev/null +++ b/plat/st/stm32mp1/bl2_io_storage.c @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch_helpers.h> +#include <assert.h> +#include <boot_api.h> +#include <debug.h> +#include <io_driver.h> +#include <io_dummy.h> +#include <io_storage.h> +#include <mmio.h> +#include <platform.h> +#include <platform_def.h> +#include <stm32mp1_private.h> +#include <stm32mp1_rcc.h> +#include <string.h> +#include <utils.h> + +/* IO devices */ +static const io_dev_connector_t *dummy_dev_con; +static uintptr_t dummy_dev_handle; +static uintptr_t dummy_dev_spec; + +static const io_block_spec_t bl32_block_spec = { +	.offset = BL32_BASE, +	.length = STM32MP1_BL32_SIZE +}; + +static const io_block_spec_t bl2_block_spec = { +	.offset = BL2_BASE, +	.length = STM32MP1_BL2_SIZE, +}; + +static int open_dummy(const uintptr_t spec); + +struct plat_io_policy { +	uintptr_t *dev_handle; +	uintptr_t image_spec; +	int (*check)(const uintptr_t spec); +}; + +static const struct plat_io_policy policies[] = { +	[BL2_IMAGE_ID] = { +		.dev_handle = &dummy_dev_handle, +		.image_spec = (uintptr_t)&bl2_block_spec, +		.check = open_dummy +	}, +	[BL32_IMAGE_ID] = { +		.dev_handle = &dummy_dev_handle, +		.image_spec = (uintptr_t)&bl32_block_spec, +		.check = open_dummy +	}, +}; + +static int open_dummy(const uintptr_t spec) +{ +	return io_dev_init(dummy_dev_handle, 0); +} + +static void print_boot_device(boot_api_context_t *boot_context) +{ +	switch (boot_context->boot_interface_selected) { +	case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_SD: +		INFO("Using SDMMC\n"); +		break; +	case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC: +		INFO("Using EMMC\n"); +		break; +	default: +		ERROR("Boot interface not found\n"); +		panic(); +		break; +	} + +	if (boot_context->boot_interface_instance != 0U) { +		INFO("  Instance %d\n", boot_context->boot_interface_instance); +	} +} + +static void print_reset_reason(void) +{ +	uint32_t rstsr = mmio_read_32(RCC_BASE + RCC_MP_RSTSCLRR); + +	if (rstsr == 0U) { +		WARN("Reset reason unknown\n"); +		return; +	} + +	INFO("Reset reason (0x%x):\n", rstsr); + +	if ((rstsr & RCC_MP_RSTSCLRR_PADRSTF) == 0U) { +		if ((rstsr & RCC_MP_RSTSCLRR_STDBYRSTF) != 0U) { +			INFO("System exits from STANDBY\n"); +			return; +		} + +		if ((rstsr & RCC_MP_RSTSCLRR_CSTDBYRSTF) != 0U) { +			INFO("MPU exits from CSTANDBY\n"); +			return; +		} +	} + +	if ((rstsr & RCC_MP_RSTSCLRR_PORRSTF) != 0U) { +		INFO("  Power-on Reset (rst_por)\n"); +		return; +	} + +	if ((rstsr & RCC_MP_RSTSCLRR_BORRSTF) != 0U) { +		INFO("  Brownout Reset (rst_bor)\n"); +		return; +	} + +	if ((rstsr & RCC_MP_RSTSCLRR_MPSYSRSTF) != 0U) { +		INFO("  System reset generated by MPU (MPSYSRST)\n"); +		return; +	} + +	if ((rstsr & RCC_MP_RSTSCLRR_HCSSRSTF) != 0U) { +		INFO("  Reset due to a clock failure on HSE\n"); +		return; +	} + +	if ((rstsr & RCC_MP_RSTSCLRR_IWDG1RSTF) != 0U) { +		INFO("  IWDG1 Reset (rst_iwdg1)\n"); +		return; +	} + +	if ((rstsr & RCC_MP_RSTSCLRR_IWDG2RSTF) != 0U) { +		INFO("  IWDG2 Reset (rst_iwdg2)\n"); +		return; +	} + +	if ((rstsr & RCC_MP_RSTSCLRR_PADRSTF) != 0U) { +		INFO("  Pad Reset from NRST\n"); +		return; +	} + +	if ((rstsr & RCC_MP_RSTSCLRR_VCORERSTF) != 0U) { +		INFO("  Reset due to a failure of VDD_CORE\n"); +		return; +	} + +	ERROR("  Unidentified reset reason\n"); +} + +void stm32mp1_io_setup(void) +{ +	int io_result __unused; +	boot_api_context_t *boot_context = +		(boot_api_context_t *)stm32mp1_get_boot_ctx_address(); + +	print_reset_reason(); + +	print_boot_device(boot_context); + +	if ((boot_context->boot_partition_used_toboot == 1U) || +	    (boot_context->boot_partition_used_toboot == 2U)) { +		INFO("Boot used partition fsbl%d\n", +		     boot_context->boot_partition_used_toboot); +	} + +	io_result = register_io_dev_dummy(&dummy_dev_con); +	assert(io_result == 0); + +	io_result = io_dev_open(dummy_dev_con, dummy_dev_spec, +				&dummy_dev_handle); +	assert(io_result == 0); +} + +/* + * Return an IO device handle and specification which can be used to access + * an image. Use this to enforce platform load policy. + */ +int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle, +			  uintptr_t *image_spec) +{ +	int rc; +	const struct plat_io_policy *policy; + +	assert(image_id < ARRAY_SIZE(policies)); + +	policy = &policies[image_id]; +	rc = policy->check(policy->image_spec); +	if (rc == 0) { +		*image_spec = policy->image_spec; +		*dev_handle = *(policy->dev_handle); +	} + +	return rc; +} diff --git a/plat/st/stm32mp1/bl2_plat_setup.c b/plat/st/stm32mp1/bl2_plat_setup.c new file mode 100644 index 00000000..9f2d8bd0 --- /dev/null +++ b/plat/st/stm32mp1/bl2_plat_setup.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch_helpers.h> +#include <assert.h> +#include <bl_common.h> +#include <boot_api.h> +#include <console.h> +#include <debug.h> +#include <delay_timer.h> +#include <desc_image_load.h> +#include <generic_delay_timer.h> +#include <mmio.h> +#include <platform.h> +#include <platform_def.h> +#include <stm32mp1_clk.h> +#include <stm32mp1_dt.h> +#include <stm32mp1_pmic.h> +#include <stm32mp1_private.h> +#include <stm32mp1_context.h> +#include <stm32mp1_pwr.h> +#include <stm32mp1_ram.h> +#include <stm32mp1_rcc.h> +#include <stm32mp1_reset.h> +#include <string.h> +#include <xlat_tables_v2.h> + +void bl2_el3_early_platform_setup(u_register_t arg0, u_register_t arg1, +				  u_register_t arg2, u_register_t arg3) +{ +	stm32mp1_save_boot_ctx_address(arg0); +} + +void bl2_platform_setup(void) +{ +	int ret; + +	if (dt_check_pmic()) { +		initialize_pmic(); +	} + +	ret = stm32mp1_ddr_probe(); +	if (ret < 0) { +		ERROR("Invalid DDR init: error %d\n", ret); +		panic(); +	} + +	INFO("BL2 runs SP_MIN setup\n"); +} + +void bl2_el3_plat_arch_setup(void) +{ +	int32_t result; +	struct dt_node_info dt_dev_info; +	const char *board_model; +	boot_api_context_t *boot_context = +		(boot_api_context_t *)stm32mp1_get_boot_ctx_address(); +	uint32_t clk_rate; + +	/* +	 * Disable the backup domain write protection. +	 * The protection is enable at each reset by hardware +	 * and must be disabled by software. +	 */ +	mmio_setbits_32(PWR_BASE + PWR_CR1, PWR_CR1_DBP); + +	while ((mmio_read_32(PWR_BASE + PWR_CR1) & PWR_CR1_DBP) == 0U) { +		; +	} + +	/* Reset backup domain on cold boot cases */ +	if ((mmio_read_32(RCC_BASE + RCC_BDCR) & RCC_BDCR_RTCSRC_MASK) == 0U) { +		mmio_setbits_32(RCC_BASE + RCC_BDCR, RCC_BDCR_VSWRST); + +		while ((mmio_read_32(RCC_BASE + RCC_BDCR) & RCC_BDCR_VSWRST) == +		       0U) { +			; +		} + +		mmio_clrbits_32(RCC_BASE + RCC_BDCR, RCC_BDCR_VSWRST); +	} + +	mmap_add_region(BL_CODE_BASE, BL_CODE_BASE, +			BL_CODE_END - BL_CODE_BASE, +			MT_CODE | MT_SECURE); + +	/* Prevent corruption of preloaded BL32 */ +	mmap_add_region(BL32_BASE, BL32_BASE, +			BL32_LIMIT - BL32_BASE, +			MT_MEMORY | MT_RO | MT_SECURE); + +	/* Prevent corruption of preloaded Device Tree */ +	mmap_add_region(DTB_BASE, DTB_BASE, +			DTB_LIMIT - DTB_BASE, +			MT_MEMORY | MT_RO | MT_SECURE); + +	configure_mmu(); + +	generic_delay_timer_init(); + +	if (dt_open_and_check() < 0) { +		panic(); +	} + +	if (stm32mp1_clk_probe() < 0) { +		panic(); +	} + +	if (stm32mp1_clk_init() < 0) { +		panic(); +	} + +	result = dt_get_stdout_uart_info(&dt_dev_info); + +	if ((result <= 0) || +	    (dt_dev_info.status == 0U) || +	    (dt_dev_info.clock < 0) || +	    (dt_dev_info.reset < 0)) { +		goto skip_console_init; +	} + +	if (dt_set_stdout_pinctrl() != 0) { +		goto skip_console_init; +	} + +	if (stm32mp1_clk_enable((unsigned long)dt_dev_info.clock) != 0) { +		goto skip_console_init; +	} + +	stm32mp1_reset_assert((uint32_t)dt_dev_info.reset); +	udelay(2); +	stm32mp1_reset_deassert((uint32_t)dt_dev_info.reset); +	mdelay(1); + +	clk_rate = stm32mp1_clk_get_rate((unsigned long)dt_dev_info.clock); + +	if (console_init(dt_dev_info.base, clk_rate, +			 STM32MP1_UART_BAUDRATE) == 0) { +		panic(); +	} + +	board_model = dt_get_board_model(); +	if (board_model != NULL) { +		NOTICE("%s\n", board_model); +	} + +skip_console_init: + +	if (stm32_save_boot_interface(boot_context->boot_interface_selected, +				      boot_context->boot_interface_instance) != +	    0) { +		ERROR("Cannot save boot interface\n"); +	} + +	stm32mp1_arch_security_setup(); + +	stm32mp1_io_setup(); +} diff --git a/plat/st/stm32mp1/include/boot_api.h b/plat/st/stm32mp1/include/boot_api.h new file mode 100644 index 00000000..71c35934 --- /dev/null +++ b/plat/st/stm32mp1/include/boot_api.h @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __BOOT_API_H +#define __BOOT_API_H + +#include <stdint.h> + +/* + * Possible value of boot context field 'boot_interface_sel' + */ + +/* Value of field 'boot_interface_sel' when no boot occurred */ +#define BOOT_API_CTX_BOOT_INTERFACE_SEL_NO			0x0U + +/* Boot occurred on SD */ +#define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_SD		0x1U + +/* Boot occurred on EMMC */ +#define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC		0x2U + +/** + * @brief  Possible value of boot context field 'EmmcXferStatus' + */ +/* + * Possible value of boot context field 'emmc_xfer_status' + */ +#define BOOT_API_CTX_EMMC_XFER_STATUS_NOT_STARTED			0x0U +#define BOOT_API_CTX_EMMC_XFER_STATUS_DATAEND_DETECTED			0x1U +#define BOOT_API_CTX_EMMC_XFER_STATUS_XFER_OVERALL_TIMEOUT_DETECTED	0x2U +#define BOOT_API_CTX_EMMC_XFER_STATUS_XFER_DATA_TIMEOUT			0x3U + +/* + * Possible value of boot context field 'emmc_error_status' + */ +#define BOOT_API_CTX_EMMC_ERROR_STATUS_NONE                     0x0U +#define BOOT_API_CTX_EMMC_ERROR_STATUS_CMD_TIMEOUT              0x1U +#define BOOT_API_CTX_EMMC_ERROR_STATUS_ACK_TIMEOUT              0x2U +#define BOOT_API_CTX_EMMC_ERROR_STATUS_DATA_CRC_FAIL            0x3U +#define BOOT_API_CTX_EMMC_ERROR_STATUS_NOT_ENOUGH_BOOT_DATA_RX  0x4U +#define BOOT_API_CTX_EMMC_ERROR_STATUS_HEADER_NOT_FOUND         0x5U +#define BOOT_API_CTX_EMMC_ERROR_STATUS_HEADER_SIZE_ZERO         0x6U +#define BOOT_API_CTX_EMMC_ERROR_STATUS_IMAGE_NOT_COMPLETE       0x7U + +/* Image Header related definitions */ + +/* Definition of header version */ +#define BOOT_API_HEADER_VERSION					0x00010000U + +/* + * Magic number used to detect header in memory + * Its value must be 'S' 'T' 'M' 0x32, i.e 0x324D5453 as field + * 'bootapi_image_header_t.magic' + * This identifies the start of a boot image. + */ +#define BOOT_API_IMAGE_HEADER_MAGIC_NB				0x324D5453U + +/* Definitions related to Authentication used in image header structure */ +#define BOOT_API_ECDSA_PUB_KEY_LEN_IN_BYTES			64 +#define BOOT_API_ECDSA_SIGNATURE_LEN_IN_BYTES			64 +#define BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES			32 + +/* Possible values of the field 'boot_api_image_header_t.ecc_algo_type' */ +#define BOOT_API_ECDSA_ALGO_TYPE_P256NIST			1 +#define BOOT_API_ECDSA_ALGO_TYPE_BRAINPOOL256			2 + +/* + * Cores secure magic numbers + * Constant to be stored in bakcup register + * BOOT_API_MAGIC_NUMBER_TAMP_BCK_REG_IDX + */ +#define BOOT_API_A7_CORE0_MAGIC_NUMBER				0xCA7FACE0U +#define BOOT_API_A7_CORE1_MAGIC_NUMBER				0xCA7FACE1U + +/* + * TAMP_BCK4R register index + * This register is used to write a Magic Number in order to restart + * Cortex A7 Core 1 and make it execute @ branch address from TAMP_BCK5R + */ +#define BOOT_API_CORE1_MAGIC_NUMBER_TAMP_BCK_REG_IDX		4U + +/* + * TAMP_BCK5R register index + * This register is used to contain the branch address of + * Cortex A7 Core 1 when restarted by a TAMP_BCK4R magic number writing + */ +#define BOOT_API_CORE1_BRANCH_ADDRESS_TAMP_BCK_REG_IDX		5U + +/* + * Possible value of boot context field 'hse_clock_value_in_hz' + */ +#define BOOT_API_CTX_HSE_CLOCK_VALUE_UNDEFINED			0U +#define BOOT_API_CTX_HSE_CLOCK_VALUE_24_MHZ			24000000U +#define BOOT_API_CTX_HSE_CLOCK_VALUE_25_MHZ			25000000U +#define BOOT_API_CTX_HSE_CLOCK_VALUE_26_MHZ			26000000U + +/* + * Possible value of boot context field 'boot_partition_used_toboot' + */ +#define BOOT_API_CTX_BOOT_PARTITION_UNDEFINED			0U + +/* Used FSBL1 to boot */ +#define BOOT_API_CTX_BOOT_PARTITION_FSBL1			1U + +/* Used FSBL2 to boot */ +#define BOOT_API_CTX_BOOT_PARTITION_FSBL2			2U + +/* OTP_CFG0 */ +#define BOOT_API_OTP_MODE_WORD_NB				0 +/* Closed = OTP_CFG0[6] */ +#define BOOT_API_OTP_MODE_CLOSED_BIT_POS			6 + +/* + * Boot Context related definitions + */ + +/* + * Boot core boot configuration structure + * Specifies all items of the cold boot configuration + * Memory and peripheral part. + */ +typedef struct { +	/* +	 * Boot interface used to boot : take values from defines +	 * BOOT_API_CTX_BOOT_INTERFACE_SEL_XXX above +	 */ +	uint16_t boot_interface_selected; +	uint16_t boot_interface_instance; +	uint32_t reserved1[13]; +	uint32_t otp_afmux_values[3]; +	uint32_t reserved[9]; +	/* +	 * Information specific to an SD boot +	 * Updated each time an SD boot is at least attempted, +	 * even if not successful +	 * Note : This is useful to understand why an SD boot failed +	 * in particular +	 */ +	uint32_t sd_err_internal_timeout_cnt; +	uint32_t sd_err_dcrc_fail_cnt; +	uint32_t sd_err_dtimeout_cnt; +	uint32_t sd_err_ctimeout_cnt; +	uint32_t sd_err_ccrc_fail_cnt; +	uint32_t sd_overall_retry_cnt; +	/* +	 * Information specific to an eMMC boot +	 * Updated each time an eMMC boot is at least attempted, +	 * even if not successful +	 * Note : This is useful to understand why an eMMC boot failed +	 * in particular +	 */ +	uint32_t emmc_xfer_status; +	uint32_t emmc_error_status; +	uint32_t emmc_nbbytes_rxcopied_tosysram_download_area; +	uint32_t hse_clock_value_in_hz; +	/* +	 * Boot partition : +	 * ie FSBL partition on which the boot was successful +	 */ +	uint32_t boot_partition_used_toboot; + +} __packed boot_api_context_t; + +/* + * Image Header related definitions + */ + +/* + * Structure used to define the common Header format used for FSBL, xloader, + * ... and in particular used by bootROM for FSBL header readout. + * FSBL header size is 256 Bytes = 0x100 + */ +typedef struct { +	/* BOOT_API_IMAGE_HEADER_MAGIC_NB */ +	uint32_t magic; +	uint8_t image_signature[BOOT_API_ECDSA_SIGNATURE_LEN_IN_BYTES]; +	/* +	 * Checksum of payload +	 * 32-bit sum all all payload bytes considered as 8 bit unigned numbers, +	 * discarding any overflow bits. +	 * Use to check UART/USB downloaded image integrity when signature +	 * is not used (i.e bit 0 : 'No_sig_check' = 1 in option flags) +	 */ +	uint32_t payload_checksum; +	/* Image header version : should have value BOOT_API_HEADER_VERSION */ +	uint32_t header_version; +	/* Image length in bytes */ +	uint32_t image_length; +	/* +	 * Image Entry point address : should be in the SYSRAM area +	 * and at least within the download area range +	 */ +	uint32_t image_entry_point; +	/* Reserved */ +	uint32_t reserved1; +	/* +	 * Image load address : not used by bootROM but to be consistent +	 * with header format for other packages (xloader, ...) +	 */ +	uint32_t load_address; +	/* Reserved */ +	uint32_t reserved2; +	/* Image version to be compared by bootROM with monotonic +	 * counter value in OTP_CFG4 prior executing the downloaded image +	 */ +	uint32_t image_version; +	/* +	 * Option flags: +	 * Bit 0 : No signature check request : 'No_sig_check' +	 *      value 1 : for No signature check request +	 *      value 0 : No request to bypass the signature check +	 * Note : No signature check is never allowed on a Secured chip +	 */ +	uint32_t option_flags; +	/* +	 * Type of ECC algorithm to use  : +	 * value 1 : for P-256 NIST algorithm +	 * value 2 : for Brainpool 256 algorithm +	 * See definitions 'BOOT_API_ECDSA_ALGO_TYPE_XXX' above. +	 */ +	uint32_t ecc_algo_type; +	/* +	 * OEM ECC Public Key (aka Root pubk) provided in header on 512 bits. +	 * The SHA-256 hash of the OEM ECC pubk must match the one stored +	 * in OTP cells. +	 */ +	uint8_t ecc_pubk[BOOT_API_ECDSA_PUB_KEY_LEN_IN_BYTES]; +	/* Pad up to 256 byte total size */ +	uint8_t pad[84]; +} __packed boot_api_image_header_t; + +#endif /* __BOOT_API_H */ diff --git a/plat/st/stm32mp1/include/platform_def.h b/plat/st/stm32mp1/include/platform_def.h new file mode 100644 index 00000000..47e1ffcf --- /dev/null +++ b/plat/st/stm32mp1/include/platform_def.h @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PLATFORM_DEF_H +#define PLATFORM_DEF_H + +#include <arch.h> +#include <common_def.h> +#include <gic_common.h> +#include <utils_def.h> +#include "../stm32mp1_def.h" + +/******************************************************************************* + * Generic platform constants + ******************************************************************************/ + +/* Size of cacheable stacks */ +#if defined(IMAGE_BL32) +#define PLATFORM_STACK_SIZE		0x600 +#else +#define PLATFORM_STACK_SIZE		0xC00 +#endif + +/* SSBL = second stage boot loader */ +#define BL33_IMAGE_NAME			"ssbl" + +#define STM32MP1_PRIMARY_CPU		U(0x0) + +#define PLATFORM_CACHE_LINE_SIZE	64 +#define PLATFORM_CLUSTER_COUNT		ULL(1) +#define PLATFORM_CLUSTER0_CORE_COUNT	U(2) +#define PLATFORM_CLUSTER1_CORE_COUNT	U(0) +#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER1_CORE_COUNT + \ +					 PLATFORM_CLUSTER0_CORE_COUNT) +#define PLATFORM_MAX_CPUS_PER_CLUSTER	2 + +#define MAX_IO_DEVICES			4 +#define MAX_IO_HANDLES			4 + +/******************************************************************************* + * BL2 specific defines. + ******************************************************************************/ +/* + * Put BL2 just below BL3-1. BL2_BASE is calculated using the current BL2 debug + * size plus a little space for growth. + */ +#define BL2_BASE			STM32MP1_BL2_BASE +#define BL2_LIMIT			(STM32MP1_BL2_BASE + \ +					 STM32MP1_BL2_SIZE) + +/******************************************************************************* + * BL32 specific defines. + ******************************************************************************/ +#define BL32_BASE			STM32MP1_BL32_BASE +#define BL32_LIMIT			(STM32MP1_BL32_BASE + \ +					 STM32MP1_BL32_SIZE) + +/******************************************************************************* + * BL33 specific defines. + ******************************************************************************/ +#define BL33_BASE			STM32MP1_BL33_BASE + +/* + * Load address of BL33 for this platform port + */ +#define PLAT_STM32MP1_NS_IMAGE_OFFSET	BL33_BASE + +/******************************************************************************* + * DTB specific defines. + ******************************************************************************/ +#define DTB_BASE			STM32MP1_DTB_BASE +#define DTB_LIMIT			(STM32MP1_DTB_BASE + \ +					 STM32MP1_DTB_SIZE) + +/******************************************************************************* + * Platform specific page table and MMU setup constants + ******************************************************************************/ +#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32) +#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32) + +/******************************************************************************* + * Declarations and constants to access the mailboxes safely. Each mailbox is + * aligned on the biggest cache line size in the platform. This is known only + * to the platform as it might have a combination of integrated and external + * caches. Such alignment ensures that two maiboxes do not sit on the same cache + * line at any cache level. They could belong to different cpus/clusters & + * get written while being protected by different locks causing corruption of + * a valid mailbox address. + ******************************************************************************/ +#define CACHE_WRITEBACK_SHIFT		6 +#define CACHE_WRITEBACK_GRANULE		(U(1) << CACHE_WRITEBACK_SHIFT) + +/* + * Secure Interrupt: based on the standard ARM mapping + */ +#define ARM_IRQ_SEC_PHY_TIMER		U(29) + +#define ARM_IRQ_SEC_SGI_0		U(8) +#define ARM_IRQ_SEC_SGI_1		U(9) +#define ARM_IRQ_SEC_SGI_2		U(10) +#define ARM_IRQ_SEC_SGI_3		U(11) +#define ARM_IRQ_SEC_SGI_4		U(12) +#define ARM_IRQ_SEC_SGI_5		U(13) +#define ARM_IRQ_SEC_SGI_6		U(14) +#define ARM_IRQ_SEC_SGI_7		U(15) + +#define STM32MP1_IRQ_TZC400		U(36) +#define STM32MP1_IRQ_TAMPSERRS		U(229) +#define STM32MP1_IRQ_AXIERRIRQ		U(244) + +/* + * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3 + * terminology. On a GICv2 system or mode, the lists will be merged and treated + * as Group 0 interrupts. + */ +#define PLATFORM_G1S_PROPS(grp) \ +	INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER,		\ +		       GIC_HIGHEST_SEC_PRIORITY,	\ +		       grp, GIC_INTR_CFG_LEVEL),	\ +	INTR_PROP_DESC(STM32MP1_IRQ_TAMPSERRS,		\ +		       GIC_HIGHEST_SEC_PRIORITY,	\ +		       grp, GIC_INTR_CFG_LEVEL),	\ +	INTR_PROP_DESC(STM32MP1_IRQ_AXIERRIRQ,		\ +		       GIC_HIGHEST_SEC_PRIORITY,	\ +		       grp, GIC_INTR_CFG_LEVEL),	\ +	INTR_PROP_DESC(STM32MP1_IRQ_TZC400,		\ +		       GIC_HIGHEST_SEC_PRIORITY,	\ +		       grp, GIC_INTR_CFG_LEVEL),	\ +	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_1,		\ +		       GIC_HIGHEST_SEC_PRIORITY,	\ +		       grp, GIC_INTR_CFG_EDGE),		\ +	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_2,		\ +		       GIC_HIGHEST_SEC_PRIORITY,	\ +		       grp, GIC_INTR_CFG_EDGE),		\ +	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_3,		\ +		       GIC_HIGHEST_SEC_PRIORITY,	\ +		       grp, GIC_INTR_CFG_EDGE),		\ +	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_4,		\ +		       GIC_HIGHEST_SEC_PRIORITY,	\ +		       grp, GIC_INTR_CFG_EDGE),		\ +	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_5,		\ +		       GIC_HIGHEST_SEC_PRIORITY,	\ +		       grp, GIC_INTR_CFG_EDGE),		\ +	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_7,		\ +		       GIC_HIGHEST_SEC_PRIORITY,	\ +		       grp, GIC_INTR_CFG_EDGE) + +#define PLATFORM_G0_PROPS(grp) \ +	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_0,		\ +		       GIC_HIGHEST_SEC_PRIORITY,	\ +		       grp, GIC_INTR_CFG_EDGE),		\ +	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_6,		\ +		       GIC_HIGHEST_SEC_PRIORITY,	\ +		       grp, GIC_INTR_CFG_EDGE) + +/* + * Power + */ +#define PLAT_MAX_PWR_LVL	U(1) + +/* Local power state for power domains in Run state. */ +#define ARM_LOCAL_STATE_RUN	U(0) +/* Local power state for retention. Valid only for CPU power domains */ +#define ARM_LOCAL_STATE_RET	U(1) +/* Local power state for power-down. Valid for CPU and cluster power domains */ +#define ARM_LOCAL_STATE_OFF	U(2) +/* + * This macro defines the deepest retention state possible. + * A higher state id will represent an invalid or a power down state. + */ +#define PLAT_MAX_RET_STATE		ARM_LOCAL_STATE_RET +/* + * This macro defines the deepest power down states possible. Any state ID + * higher than this is invalid. + */ +#define PLAT_MAX_OFF_STATE		ARM_LOCAL_STATE_OFF + +/******************************************************************************* + * Size of the per-cpu data in bytes that should be reserved in the generic + * per-cpu data structure for the FVP port. + ******************************************************************************/ +#define PLAT_PCPU_DATA_SIZE	2 + +#endif /* PLATFORM_DEF_H */ diff --git a/plat/st/stm32mp1/include/stm32mp1_context.h b/plat/st/stm32mp1/include/stm32mp1_context.h new file mode 100644 index 00000000..fd08afc7 --- /dev/null +++ b/plat/st/stm32mp1/include/stm32mp1_context.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __STM32MP1_CONTEXT_H__ +#define __STM32MP1_CONTEXT_H__ + +#include <stdint.h> + +int stm32_save_boot_interface(uint32_t interface, uint32_t instance); + +#endif /* __STM32MP1_CONTEXT_H__ */ diff --git a/plat/st/stm32mp1/include/stm32mp1_dt.h b/plat/st/stm32mp1/include/stm32mp1_dt.h new file mode 100644 index 00000000..58e10d19 --- /dev/null +++ b/plat/st/stm32mp1/include/stm32mp1_dt.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __STM32MP1_DT_H__ +#define __STM32MP1_DT_H__ + +#include <stdbool.h> + +struct dt_node_info { +	uint32_t base; +	int32_t clock; +	int32_t reset; +	bool status; +	bool sec_status; +}; + +/******************************************************************************* + * Function and variable prototypes + ******************************************************************************/ +int dt_open_and_check(void); +int fdt_get_address(void **fdt_addr); +bool fdt_check_node(int node); +bool fdt_check_status(int node); +bool fdt_check_secure_status(int node); +uint32_t fdt_read_uint32_default(int node, const char *prop_name, +				 uint32_t dflt_value); +int fdt_read_uint32_array(int node, const char *prop_name, +			  uint32_t *array, uint32_t count); +int dt_set_pinctrl_config(int node); +int dt_set_stdout_pinctrl(void); +void dt_fill_device_info(struct dt_node_info *info, int node); +int dt_get_node(struct dt_node_info *info, int offset, const char *compat); +int dt_get_stdout_uart_info(struct dt_node_info *info); +int dt_get_stdout_node_offset(void); +uint32_t dt_get_ddr_size(void); +const char *dt_get_board_model(void); + +#endif /* __STM32MP1_DT_H__ */ diff --git a/plat/st/stm32mp1/include/stm32mp1_private.h b/plat/st/stm32mp1/include/stm32mp1_private.h new file mode 100644 index 00000000..a789d53e --- /dev/null +++ b/plat/st/stm32mp1/include/stm32mp1_private.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __STM32MP1_PRIVATE_H__ +#define __STM32MP1_PRIVATE_H__ + +void stm32mp1_io_setup(void); +void configure_mmu(void); + +void stm32mp1_arch_security_setup(void); +void stm32mp1_security_setup(void); + +void stm32mp1_save_boot_ctx_address(uintptr_t address); +uintptr_t stm32mp1_get_boot_ctx_address(void); + +void stm32mp1_gic_pcpu_init(void); +void stm32mp1_gic_init(void); + +#endif /* __STM32MP1_PRIVATE_H__ */ diff --git a/plat/st/stm32mp1/plat_bl2_mem_params_desc.c b/plat/st/stm32mp1/plat_bl2_mem_params_desc.c new file mode 100644 index 00000000..6f5bc4cc --- /dev/null +++ b/plat/st/stm32mp1/plat_bl2_mem_params_desc.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <bl_common.h> +#include <desc_image_load.h> +#include <platform.h> +#include <platform_def.h> + +/******************************************************************************* + * Following descriptor provides BL image/ep information that gets used + * by BL2 to load the images and also subset of this information is + * passed to next BL image. The image loading sequence is managed by + * populating the images in required loading order. The image execution + * sequence is managed by populating the `next_handoff_image_id` with + * the next executable image id. + ******************************************************************************/ +static bl_mem_params_node_t bl2_mem_params_descs[] = { +	/* Fill BL32 related information */ +	{ +		.image_id = BL32_IMAGE_ID, + +		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, +				      VERSION_2, entry_point_info_t, +				      SECURE | EXECUTABLE | EP_FIRST_EXE), + +		.ep_info.pc = BL32_BASE, +		.ep_info.spsr = SPSR_MODE32(MODE32_svc, SPSR_T_ARM, +					    SPSR_E_LITTLE, +					    DISABLE_ALL_EXCEPTIONS), + +		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, +				      VERSION_2, image_info_t, +				      IMAGE_ATTRIB_PLAT_SETUP), + +		.image_info.image_base = BL32_BASE, +		.image_info.image_max_size = BL32_LIMIT - BL32_BASE, + +		.next_handoff_image_id = BL33_IMAGE_ID, +	}, + +	/* Fill BL33 related information */ +	{ +		.image_id = BL33_IMAGE_ID, + +		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, +				      VERSION_2, entry_point_info_t, +				      NON_SECURE | EXECUTABLE), + +		.ep_info.pc = PLAT_STM32MP1_NS_IMAGE_OFFSET, +		.ep_info.spsr = SPSR_MODE32(MODE32_svc, SPSR_T_ARM, +					    SPSR_E_LITTLE, +					    DISABLE_ALL_EXCEPTIONS), + +		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, +				      VERSION_2, image_info_t, 0), + +		.image_info.image_base = PLAT_STM32MP1_NS_IMAGE_OFFSET, +		.image_info.image_max_size = STM32MP1_DDR_MAX_SIZE - +			(PLAT_STM32MP1_NS_IMAGE_OFFSET - STM32MP1_DDR_BASE), + +		.next_handoff_image_id = INVALID_IMAGE_ID, +	} +}; + +REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs) diff --git a/plat/st/stm32mp1/plat_image_load.c b/plat/st/stm32mp1/plat_image_load.c new file mode 100644 index 00000000..3c6d677a --- /dev/null +++ b/plat/st/stm32mp1/plat_image_load.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <desc_image_load.h> + +/******************************************************************************* + * This function flushes the data structures so that they are visible + * in memory for the next BL image. + ******************************************************************************/ +void plat_flush_next_bl_params(void) +{ +	flush_bl_params_desc(); +} + +/******************************************************************************* + * This function returns the list of loadable images. + ******************************************************************************/ +bl_load_info_t *plat_get_bl_image_load_info(void) +{ +	return get_bl_load_info_from_mem_params_desc(); +} + +/******************************************************************************* + * This function returns the list of executable images. + ******************************************************************************/ +bl_params_t *plat_get_next_bl_params(void) +{ +	return get_next_bl_params_from_mem_params_desc(); +} diff --git a/plat/st/stm32mp1/platform.mk b/plat/st/stm32mp1/platform.mk new file mode 100644 index 00000000..3f938d90 --- /dev/null +++ b/plat/st/stm32mp1/platform.mk @@ -0,0 +1,148 @@ +# +# Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +ARM_CORTEX_A7		:=	yes +ARM_WITH_NEON		:=	yes +LOAD_IMAGE_V2		:=	1 +BL2_AT_EL3		:=	1 +ENABLE_PLAT_COMPAT	:=	0 +USE_COHERENT_MEM	:=	0 + +STM32_TF_VERSION	?=	0 + +# Not needed for Cortex-A7 +WORKAROUND_CVE_2017_5715:=	0 + +PLAT_INCLUDES		:=	-Iplat/st/stm32mp1/include/ +PLAT_INCLUDES		+=	-Iinclude/common/tbbr +PLAT_INCLUDES		+=	-Iinclude/drivers/st + +# Device tree +STM32_DTB_FILE_NAME	?=	stm32mp157c-ev1.dtb +FDT_SOURCES		:=	$(addprefix fdts/, $(patsubst %.dtb,%.dts,$(STM32_DTB_FILE_NAME))) +DTC_FLAGS		+=	-Wno-unit_address_vs_reg + +include lib/libfdt/libfdt.mk + +PLAT_BL_COMMON_SOURCES	:=	plat/st/stm32mp1/stm32mp1_common.c + +PLAT_BL_COMMON_SOURCES	+=	drivers/console/aarch32/console.S			\ +				drivers/st/uart/aarch32/stm32_console.S + +ifneq (${ENABLE_STACK_PROTECTOR},0) +PLAT_BL_COMMON_SOURCES	+=	plat/st/stm32mp1/stm32mp1_stack_protector.c +endif + +include lib/xlat_tables_v2/xlat_tables.mk +PLAT_BL_COMMON_SOURCES	+=	${XLAT_TABLES_LIB_SRCS} + +PLAT_BL_COMMON_SOURCES	+=	lib/cpus/aarch32/cortex_a7.S + +PLAT_BL_COMMON_SOURCES	+=	${LIBFDT_SRCS}						\ +				drivers/arm/tzc/tzc400.c				\ +				drivers/delay_timer/delay_timer.c			\ +				drivers/delay_timer/generic_delay_timer.c		\ +				drivers/st/clk/stm32mp1_clk.c				\ +				drivers/st/clk/stm32mp1_clkfunc.c			\ +				drivers/st/ddr/stm32mp1_ddr_helpers.c			\ +				drivers/st/gpio/stm32_gpio.c				\ +				drivers/st/pmic/stm32_i2c.c				\ +				drivers/st/pmic/stm32mp1_pmic.c				\ +				drivers/st/pmic/stpmu1.c				\ +				drivers/st/reset/stm32mp1_reset.c			\ +				plat/st/stm32mp1/stm32mp1_context.c			\ +				plat/st/stm32mp1/stm32mp1_dt.c				\ +				plat/st/stm32mp1/stm32mp1_helper.S			\ +				plat/st/stm32mp1/stm32mp1_security.c + +BL2_SOURCES		+=	drivers/io/io_dummy.c					\ +				drivers/io/io_storage.c					\ +				plat/st/stm32mp1/bl2_io_storage.c			\ +				plat/st/stm32mp1/bl2_plat_setup.c + +BL2_SOURCES		+=	drivers/st/ddr/stm32mp1_ddr.c				\ +				drivers/st/ddr/stm32mp1_ram.c + +BL2_SOURCES		+=	common/desc_image_load.c				\ +				plat/st/stm32mp1/plat_bl2_mem_params_desc.c		\ +				plat/st/stm32mp1/plat_image_load.c + +# For memory footprint optimization, build with thumb and interwork support +ASFLAGS			+=	-mthumb -mthumb-interwork +TF_CFLAGS		+=	-mthumb -mthumb-interwork + +# Macros and rules to build TF binary +STM32_TF_ELF_LDFLAGS	:=	--hash-style=gnu --as-needed +STM32_DT_BASENAME	:=	$(STM32_DTB_FILE_NAME:.dtb=) +STM32_TF_STM32		:=	${BUILD_PLAT}/tf-a-${STM32_DT_BASENAME}.stm32 +STM32_TF_BINARY		:=	$(STM32_TF_STM32:.stm32=.bin) +STM32_TF_MAPFILE	:=	$(STM32_TF_STM32:.stm32=.map) +STM32_TF_LINKERFILE	:=	$(STM32_TF_STM32:.stm32=.ld) +STM32_TF_ELF		:=	$(STM32_TF_STM32:.stm32=.elf) +STM32_TF_DTBFILE	:=      ${BUILD_PLAT}/fdts/${STM32_DTB_FILE_NAME} +STM32_TF_OBJS		:=	${BUILD_PLAT}/stm32mp1.o + +# Variables for use with stm32image +STM32IMAGEPATH		?= tools/stm32image +STM32IMAGE		?= ${STM32IMAGEPATH}/stm32image${BIN_EXT} + +.PHONY:			${STM32_TF_STM32} +.SUFFIXES: + +all: check_dtc_version ${STM32_TF_STM32} stm32image + +ifeq ($(AARCH32_SP),sp_min) +# BL32 is built only if using SP_MIN +BL32_DEP		:= bl32 +BL32_PATH		:= -DBL32_BIN_PATH=\"${BUILD_PLAT}/bl32.bin\" +endif + +distclean realclean clean: clean_stm32image + +stm32image: +	${Q}${MAKE} CPPFLAGS="" --no-print-directory -C ${STM32IMAGEPATH} + +clean_stm32image: +	${Q}${MAKE} --no-print-directory -C ${STM32IMAGEPATH} clean + +check_dtc_version: +	$(eval DTC_V = $(shell $(DTC) -v | awk '{print $$NF}')) +	$(eval DTC_VERSION = $(shell printf "%d" $(shell echo ${DTC_V} | cut -d- -f1 | sed "s/\./0/g"))) +	@if [ ${DTC_VERSION} -lt 10404 ]; then \ +		echo "dtc version too old (${DTC_V}), you need at least version 1.4.4"; \ +		false; \ +	fi + + +${STM32_TF_OBJS}:	plat/st/stm32mp1/stm32mp1.S bl2 ${BL32_DEP} ${STM32_TF_DTBFILE} +			@echo "  AS      $<" +			${Q}${AS} ${ASFLAGS} ${TF_CFLAGS} \ +				${BL32_PATH} \ +				-DBL2_BIN_PATH=\"${BUILD_PLAT}/bl2.bin\" \ +				-DDTB_BIN_PATH=\"${STM32_TF_DTBFILE}\" \ +				-c plat/st/stm32mp1/stm32mp1.S -o $@ + +${STM32_TF_LINKERFILE}:	plat/st/stm32mp1/stm32mp1.ld.S +			@echo "  LDS     $<" +			${Q}${AS} ${ASFLAGS} ${TF_CFLAGS} -P -E $< -o $@ + +${STM32_TF_ELF}:	${STM32_TF_OBJS} ${STM32_TF_LINKERFILE} +			@echo "  LDS     $<" +			${Q}${LD} -o $@ ${STM32_TF_ELF_LDFLAGS} -Map=${STM32_TF_MAPFILE} --script ${STM32_TF_LINKERFILE} ${STM32_TF_OBJS} + +${STM32_TF_BINARY}:	${STM32_TF_ELF} +			${Q}${OC} -O binary ${STM32_TF_ELF} $@ +			@echo +			@echo "Built $@ successfully" +			@echo + +${STM32_TF_STM32}:	stm32image ${STM32_TF_BINARY} +			@echo +			@echo "Generated $@" +			$(eval LOADADDR =  $(shell cat ${STM32_TF_MAPFILE} | grep RAM | awk '{print $$2}')) +			$(eval ENTRY =  $(shell cat ${STM32_TF_MAPFILE} | grep "__BL2_IMAGE_START" | awk '{print $$1}')) +			${STM32IMAGE} -s ${STM32_TF_BINARY} -d $@ -l $(LOADADDR) -e ${ENTRY} -v ${STM32_TF_VERSION} +			@echo diff --git a/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk b/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk new file mode 100644 index 00000000..9fde1538 --- /dev/null +++ b/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk @@ -0,0 +1,21 @@ +# +# Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +SP_MIN_WITH_SECURE_FIQ	:=	1 + +BL32_SOURCES		+=	plat/common/aarch32/platform_mp_stack.S		\ +				plat/st/stm32mp1/sp_min/sp_min_setup.c		\ +				plat/st/stm32mp1/stm32mp1_pm.c			\ +				plat/st/stm32mp1/stm32mp1_topology.c +# Generic GIC v2 +BL32_SOURCES		+=	drivers/arm/gic/common/gic_common.c	\ +				drivers/arm/gic/v2/gicv2_helpers.c	\ +				drivers/arm/gic/v2/gicv2_main.c		\ +				plat/common/plat_gicv2.c		\ +				plat/st/stm32mp1/stm32mp1_gic.c + +# Generic PSCI +BL32_SOURCES		+=	plat/common/plat_psci_common.c diff --git a/plat/st/stm32mp1/sp_min/sp_min_setup.c b/plat/st/stm32mp1/sp_min/sp_min_setup.c new file mode 100644 index 00000000..1329bdb8 --- /dev/null +++ b/plat/st/stm32mp1/sp_min/sp_min_setup.c @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch_helpers.h> +#include <arm_gic.h> +#include <assert.h> +#include <bl_common.h> +#include <console.h> +#include <context.h> +#include <context_mgmt.h> +#include <debug.h> +#include <dt-bindings/clock/stm32mp1-clks.h> +#include <generic_delay_timer.h> +#include <mmio.h> +#include <platform.h> +#include <platform_def.h> +#include <platform_sp_min.h> +#include <stm32mp1_clk.h> +#include <stm32mp1_dt.h> +#include <stm32mp1_private.h> +#include <string.h> +#include <tzc400.h> +#include <xlat_tables_v2.h> + +/****************************************************************************** + * Placeholder variables for copying the arguments that have been passed to + * BL32 from BL2. + ******************************************************************************/ +static entry_point_info_t bl33_image_ep_info; + +/******************************************************************************* + * Interrupt handler for FIQ (secure IRQ) + ******************************************************************************/ +void sp_min_plat_fiq_handler(uint32_t id) +{ +	switch (id) { +	case STM32MP1_IRQ_TZC400: +		ERROR("STM32MP1_IRQ_TZC400 generated\n"); +		panic(); +		break; +	case STM32MP1_IRQ_AXIERRIRQ: +		ERROR("STM32MP1_IRQ_AXIERRIRQ generated\n"); +		panic(); +		break; +	default: +		ERROR("SECURE IT handler not define for it : %i", id); +		break; +	} +} + +/******************************************************************************* + * Return a pointer to the 'entry_point_info' structure of the next image for + * the security state specified. BL33 corresponds to the non-secure image type + * while BL32 corresponds to the secure image type. A NULL pointer is returned + * if the image does not exist. + ******************************************************************************/ +entry_point_info_t *sp_min_plat_get_bl33_ep_info(void) +{ +	entry_point_info_t *next_image_info; + +	next_image_info = &bl33_image_ep_info; + +	if (next_image_info->pc == 0U) { +		return NULL; +	} + +	return next_image_info; +} + +/******************************************************************************* + * Perform any BL32 specific platform actions. + ******************************************************************************/ +void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1, +				  u_register_t arg2, u_register_t arg3) +{ +	struct dt_node_info dt_dev_info; +	int result; +	bl_params_t *params_from_bl2 = (bl_params_t *)arg0; + +	/* Imprecise aborts can be masked in NonSecure */ +	write_scr(read_scr() | SCR_AW_BIT); + +	assert(params_from_bl2 != NULL); +	assert(params_from_bl2->h.type == PARAM_BL_PARAMS); +	assert(params_from_bl2->h.version >= VERSION_2); + +	bl_params_node_t *bl_params = params_from_bl2->head; + +	/* +	 * Copy BL33 entry point information. +	 * They are stored in Secure RAM, in BL2's address space. +	 */ +	while (bl_params != NULL) { +		if (bl_params->image_id == BL33_IMAGE_ID) { +			bl33_image_ep_info = *bl_params->ep_info; +			break; +		} + +		bl_params = bl_params->next_params_info; +	} + +	if (dt_open_and_check() < 0) { +		panic(); +	} + +	if (stm32mp1_clk_probe() < 0) { +		panic(); +	} + +	result = dt_get_stdout_uart_info(&dt_dev_info); + +	if ((result > 0) && dt_dev_info.status) { +		if (console_init(dt_dev_info.base, 0, STM32MP1_UART_BAUDRATE) +		    == 0) { +			panic(); +		} +	} +} + +/******************************************************************************* + * Initialize the MMU, security and the GIC. + ******************************************************************************/ +void sp_min_platform_setup(void) +{ +	mmap_add_region(BL_CODE_BASE, BL_CODE_BASE, +			BL_CODE_END - BL_CODE_BASE, +			MT_CODE | MT_SECURE); + +	configure_mmu(); + +	/* Initialize tzc400 after DDR initialization */ +	stm32mp1_security_setup(); + +	generic_delay_timer_init(); + +	stm32mp1_gic_init(); +} + +void sp_min_plat_arch_setup(void) +{ +} diff --git a/plat/st/stm32mp1/stm32mp1.S b/plat/st/stm32mp1/stm32mp1.S new file mode 100644 index 00000000..7255fe5a --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1.S @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifdef BL32_BIN_PATH +.section .bl32_image +.incbin BL32_BIN_PATH +#endif + +.section .bl2_image +.incbin BL2_BIN_PATH + +.section .dtb_image +.incbin DTB_BIN_PATH diff --git a/plat/st/stm32mp1/stm32mp1.ld.S b/plat/st/stm32mp1/stm32mp1.ld.S new file mode 100644 index 00000000..0d7a8bb7 --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1.ld.S @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __STM32MP1_LD_S__ +#define __STM32MP1_LD_S__ +#include <platform_def.h> +#include <xlat_tables_defs.h> + +OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT) +OUTPUT_ARCH(PLATFORM_LINKER_ARCH) + +ENTRY(__BL2_IMAGE_START__) + +MEMORY { +	HEADER (rw) : ORIGIN = 0x00000000, LENGTH = 0x3000 +	RAM (rwx) : ORIGIN = STM32MP1_BINARY_BASE, LENGTH = STM32MP1_BINARY_SIZE +} + +SECTIONS +{ +    /* +     * TF mapping must conform to ROM code specification. +     */ +    .header : { +        __HEADER_START__ = .; +        KEEP(*(.header)) +        . = ALIGN(4); +        __HEADER_END__ = .; +    } >HEADER + +    . = STM32MP1_BINARY_BASE; +    .data . : { +        . = ALIGN(PAGE_SIZE); +        __DATA_START__ = .; +        *(.data*) + +        /* +         * dtb. +         * The strongest and only alignment contraint is MMU 4K page. +         * Indeed as images below will be removed, 4K pages will be re-used. +         */ +        . = ( STM32MP1_DTB_BASE - STM32MP1_BINARY_BASE ); +        __DTB_IMAGE_START__ = .; +        *(.dtb_image*) +        __DTB_IMAGE_END__ = .; + +        /* +         * bl2. +         * The strongest and only alignment contraint is MMU 4K page. +         * Indeed as images below will be removed, 4K pages will be re-used. +         */ +        . = ( STM32MP1_BL2_BASE - STM32MP1_BINARY_BASE ); +        __BL2_IMAGE_START__ = .; +        *(.bl2_image*) +        __BL2_IMAGE_END__ = .; + +        /* +         * bl32 will be settled by bl2. +         * The strongest and only alignment constraint is 8 words to simplify +         * memraise8 assembly code. +         */ +        . = ( STM32MP1_BL32_BASE - STM32MP1_BINARY_BASE ); +        __BL32_IMAGE_START__ = .; +        *(.bl32_image*) +        __BL32_IMAGE_END__ = .; + +        __DATA_END__ = .; +    } >RAM + +    __TF_END__ = .; + +} +#endif /*__STM32MP1_LD_S__*/ diff --git a/plat/st/stm32mp1/stm32mp1_common.c b/plat/st/stm32mp1/stm32mp1_common.c new file mode 100644 index 00000000..68ca7db3 --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_common.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch_helpers.h> +#include <assert.h> +#include <bl_common.h> +#include <debug.h> +#include <gicv2.h> +#include <mmio.h> +#include <platform_def.h> +#include <platform.h> +#include <stm32mp1_private.h> +#include <xlat_tables_v2.h> + +#define MAP_SRAM	MAP_REGION_FLAT(STM32MP1_SRAM_BASE, \ +					STM32MP1_SRAM_SIZE, \ +					MT_MEMORY | \ +					MT_RW | \ +					MT_SECURE | \ +					MT_EXECUTE_NEVER) + +#define MAP_DEVICE1	MAP_REGION_FLAT(STM32MP1_DEVICE1_BASE, \ +					STM32MP1_DEVICE1_SIZE, \ +					MT_DEVICE | \ +					MT_RW | \ +					MT_SECURE | \ +					MT_EXECUTE_NEVER) + +#define MAP_DEVICE2	MAP_REGION_FLAT(STM32MP1_DEVICE2_BASE, \ +					STM32MP1_DEVICE2_SIZE, \ +					MT_DEVICE | \ +					MT_RW | \ +					MT_SECURE | \ +					MT_EXECUTE_NEVER) + +#define MAP_DDR		MAP_REGION_FLAT(STM32MP1_DDR_BASE, \ +					STM32MP1_DDR_MAX_SIZE, \ +					MT_MEMORY | \ +					MT_RW | \ +					MT_SECURE | \ +					MT_EXECUTE_NEVER) + +#define MAP_DDR_NS	MAP_REGION_FLAT(STM32MP1_DDR_BASE, \ +					STM32MP1_DDR_MAX_SIZE, \ +					MT_MEMORY | \ +					MT_RW | \ +					MT_NS | \ +					MT_EXECUTE_NEVER) + +#if defined(IMAGE_BL2) +static const mmap_region_t stm32mp1_mmap[] = { +	MAP_SRAM, +	MAP_DEVICE1, +	MAP_DEVICE2, +	MAP_DDR, +	{0} +}; +#endif +#if defined(IMAGE_BL32) +static const mmap_region_t stm32mp1_mmap[] = { +	MAP_SRAM, +	MAP_DEVICE1, +	MAP_DEVICE2, +	MAP_DDR_NS, +	{0} +}; +#endif + +void configure_mmu(void) +{ +	mmap_add(stm32mp1_mmap); +	init_xlat_tables(); + +	enable_mmu_secure(0); +} + +uintptr_t plat_get_ns_image_entrypoint(void) +{ +	return BL33_BASE; +} + +unsigned int plat_get_syscnt_freq2(void) +{ +	return read_cntfrq_el0(); +} + +/* Functions to save and get boot context address given by ROM code */ +static uintptr_t boot_ctx_address; + +void stm32mp1_save_boot_ctx_address(uintptr_t address) +{ +	boot_ctx_address = address; +} + +uintptr_t stm32mp1_get_boot_ctx_address(void) +{ +	return boot_ctx_address; +} diff --git a/plat/st/stm32mp1/stm32mp1_context.c b/plat/st/stm32mp1/stm32mp1_context.c new file mode 100644 index 00000000..245fd17d --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_context.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <dt-bindings/clock/stm32mp1-clks.h> +#include <errno.h> +#include <mmio.h> +#include <platform_def.h> +#include <stm32mp1_clk.h> +#include <stm32mp1_context.h> + +#define TAMP_BOOT_ITF_BACKUP_REG_ID	U(20) +#define TAMP_BOOT_ITF_MASK		U(0x0000FF00) +#define TAMP_BOOT_ITF_SHIFT		8 + +int stm32_save_boot_interface(uint32_t interface, uint32_t instance) +{ +	uint32_t tamp_clk_off = 0; +	uint32_t bkpr_itf_idx = tamp_bkpr(TAMP_BOOT_ITF_BACKUP_REG_ID); + +	if (!stm32mp1_clk_is_enabled(RTCAPB)) { +		tamp_clk_off = 1; +		if (stm32mp1_clk_enable(RTCAPB) != 0) { +			return -EINVAL; +		} +	} + +	mmio_clrsetbits_32(bkpr_itf_idx, +			   TAMP_BOOT_ITF_MASK, +			   ((interface << 4) | (instance & 0xFU)) << +			   TAMP_BOOT_ITF_SHIFT); + +	if (tamp_clk_off != 0U) { +		if (stm32mp1_clk_disable(RTCAPB) != 0) { +			return -EINVAL; +		} +	} + +	return 0; +} diff --git a/plat/st/stm32mp1/stm32mp1_def.h b/plat/st/stm32mp1/stm32mp1_def.h new file mode 100644 index 00000000..bb3fecf6 --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_def.h @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef STM32MP1_DEF_H +#define STM32MP1_DEF_H + +#include <tbbr_img_def.h> +#include <utils_def.h> +#include <xlat_tables_defs.h> + +/******************************************************************************* + * STM32MP1 memory map related constants + ******************************************************************************/ + +#define STM32MP1_SRAM_BASE		U(0x2FFC0000) +#define STM32MP1_SRAM_SIZE		U(0x00040000) + +/* DDR configuration */ +#define STM32MP1_DDR_BASE		U(0xC0000000) +#define STM32MP1_DDR_SIZE_DFLT		U(0x20000000)	/* 512 MB */ +#define STM32MP1_DDR_MAX_SIZE		U(0x40000000)	/* Max 1GB */ +#define STM32MP1_DDR_SPEED_DFLT		528 + +/* DDR power initializations */ +#ifndef __ASSEMBLY__ +enum ddr_type { +	STM32MP_DDR3, +	STM32MP_LPDDR2, +}; +#endif + +/* Section used inside TF binaries */ +#define STM32MP1_PARAM_LOAD_SIZE	U(0x00002400)	/* 9 Ko for param */ +/* 256 Octets reserved for header */ +#define STM32MP1_HEADER_SIZE		U(0x00000100) + +#define STM32MP1_BINARY_BASE		(STM32MP1_SRAM_BASE +		\ +					 STM32MP1_PARAM_LOAD_SIZE +	\ +					 STM32MP1_HEADER_SIZE) + +#define STM32MP1_BINARY_SIZE		(STM32MP1_SRAM_SIZE -		\ +					 (STM32MP1_PARAM_LOAD_SIZE +	\ +					  STM32MP1_HEADER_SIZE)) + +#if STACK_PROTECTOR_ENABLED +#define STM32MP1_BL32_SIZE		U(0x00012000)	/* 72 Ko for BL32 */ +#else +#define STM32MP1_BL32_SIZE		U(0x00011000)	/* 68 Ko for BL32 */ +#endif + +#define STM32MP1_BL32_BASE		(STM32MP1_SRAM_BASE + \ +					 STM32MP1_SRAM_SIZE - \ +					 STM32MP1_BL32_SIZE) + +#if STACK_PROTECTOR_ENABLED +#define STM32MP1_BL2_SIZE		U(0x00015000)	/* 84 Ko for BL2 */ +#else +#define STM32MP1_BL2_SIZE		U(0x00013000)	/* 76 Ko for BL2 */ +#endif + +#define STM32MP1_BL2_BASE		(STM32MP1_BL32_BASE - \ +					 STM32MP1_BL2_SIZE) + +/* BL2 and BL32/sp_min require 5 tables */ +#define MAX_XLAT_TABLES			5 + +/* + * MAX_MMAP_REGIONS is usually: + * BL stm32mp1_mmap size + mmap regions in *_plat_arch_setup + */ +#if defined(IMAGE_BL2) +  #define MAX_MMAP_REGIONS		11 +#endif +#if defined(IMAGE_BL32) +  #define MAX_MMAP_REGIONS		6 +#endif + +/* DTB initialization value */ +#define STM32MP1_DTB_SIZE		U(0x00004000)	/* 16Ko for DTB */ + +#define STM32MP1_DTB_BASE		(STM32MP1_BL2_BASE - \ +					 STM32MP1_DTB_SIZE) + +#define STM32MP1_BL33_BASE		(STM32MP1_DDR_BASE + U(0x100000)) + +/******************************************************************************* + * STM32MP1 device/io map related constants (used for MMU) + ******************************************************************************/ +#define STM32MP1_DEVICE1_BASE		U(0x40000000) +#define STM32MP1_DEVICE1_SIZE		U(0x40000000) + +#define STM32MP1_DEVICE2_BASE		U(0x80000000) +#define STM32MP1_DEVICE2_SIZE		U(0x40000000) + +/******************************************************************************* + * STM32MP1 RCC + ******************************************************************************/ +#define RCC_BASE			U(0x50000000) + +/******************************************************************************* + * STM32MP1 PWR + ******************************************************************************/ +#define PWR_BASE			U(0x50001000) + +/******************************************************************************* + * STM32MP1 UART + ******************************************************************************/ +#define USART1_BASE			U(0x5C000000) +#define USART2_BASE			U(0x4000E000) +#define USART3_BASE			U(0x4000F000) +#define UART4_BASE			U(0x40010000) +#define UART5_BASE			U(0x40011000) +#define USART6_BASE			U(0x44003000) +#define UART7_BASE			U(0x40018000) +#define UART8_BASE			U(0x40019000) +#define STM32MP1_DEBUG_USART_BASE	UART4_BASE +#define STM32MP1_UART_BAUDRATE		115200 + +/******************************************************************************* + * STM32MP1 GIC-400 + ******************************************************************************/ +#define STM32MP1_GICD_BASE		U(0xA0021000) +#define STM32MP1_GICC_BASE		U(0xA0022000) +#define STM32MP1_GICH_BASE		U(0xA0024000) +#define STM32MP1_GICV_BASE		U(0xA0026000) + +/******************************************************************************* + * STM32MP1 TZC (TZ400) + ******************************************************************************/ +#define STM32MP1_TZC_BASE		U(0x5C006000) + +#define STM32MP1_TZC_A7_ID		U(0) +#define STM32MP1_TZC_LCD_ID		U(3) +#define STM32MP1_TZC_GPU_ID		U(4) +#define STM32MP1_TZC_MDMA_ID		U(5) +#define STM32MP1_TZC_DMA_ID		U(6) +#define STM32MP1_TZC_USB_HOST_ID	U(7) +#define STM32MP1_TZC_USB_OTG_ID		U(8) +#define STM32MP1_TZC_SDMMC_ID		U(9) +#define STM32MP1_TZC_ETH_ID		U(10) +#define STM32MP1_TZC_DAP_ID		U(15) + +#define STM32MP1_MEMORY_NS		0 +#define STM32MP1_MEMORY_SECURE		1 + +#define STM32MP1_FILTER_BIT_ALL		3 + +/******************************************************************************* + * STM32MP1 SDMMC + ******************************************************************************/ +#define STM32MP1_SDMMC1_BASE		U(0x58005000) +#define STM32MP1_SDMMC2_BASE		U(0x58007000) +#define STM32MP1_SDMMC3_BASE		U(0x48004000) + +#define STM32MP1_SD_INIT_FREQ			400000		/*400 KHz*/ +#define STM32MP1_SD_NORMAL_SPEED_MAX_FREQ	25000000	/*25 MHz*/ +#define STM32MP1_SD_HIGH_SPEED_MAX_FREQ		50000000	/*50 MHz*/ +#define STM32MP1_EMMC_INIT_FREQ			STM32MP1_SD_INIT_FREQ +#define STM32MP1_EMMC_NORMAL_SPEED_MAX_FREQ	26000000	/*26 MHz*/ +#define STM32MP1_EMMC_HIGH_SPEED_MAX_FREQ	52000000	/*52 MHz*/ + +/******************************************************************************* + * STM32MP1 TAMP + ******************************************************************************/ +#define TAMP_BASE			U(0x5C00A000) +#define TAMP_BKP_REGISTER_BASE		(TAMP_BASE + U(0x100)) + +#if !(defined(__LINKER__) || defined(__ASSEMBLY__)) +static inline uint32_t tamp_bkpr(uint32_t idx) +{ +	return TAMP_BKP_REGISTER_BASE + (idx << 2); +} +#endif + +/******************************************************************************* + * STM32MP1 DDRCTRL + ******************************************************************************/ +#define DDRCTRL_BASE			U(0x5A003000) + +/******************************************************************************* + * STM32MP1 DDRPHYC + ******************************************************************************/ +#define DDRPHYC_BASE			U(0x5A004000) + +/******************************************************************************* + * STM32MP1 I2C4 + ******************************************************************************/ +#define I2C4_BASE			U(0x5C002000) + +#endif /* STM32MP1_DEF_H */ diff --git a/plat/st/stm32mp1/stm32mp1_dt.c b/plat/st/stm32mp1/stm32mp1_dt.c new file mode 100644 index 00000000..bde968a0 --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_dt.c @@ -0,0 +1,476 @@ +/* + * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <debug.h> +#include <libfdt.h> +#include <platform_def.h> +#include <stm32_gpio.h> +#include <stm32mp1_clk.h> +#include <stm32mp1_clkfunc.h> +#include <stm32mp1_ddr.h> +#include <stm32mp1_dt.h> +#include <stm32mp1_ram.h> + +#define DT_GPIO_BANK_SHIFT	12 +#define DT_GPIO_BANK_MASK	0x1F000U +#define DT_GPIO_PIN_SHIFT	8 +#define DT_GPIO_PIN_MASK	0xF00U +#define DT_GPIO_MODE_MASK	0xFFU + +static int fdt_checked; + +static void *fdt = (void *)(uintptr_t)STM32MP1_DTB_BASE; + +/******************************************************************************* + * This function gets the pin settings from DT information. + * When analyze and parsing is done, set the GPIO registers. + * Return 0 on success, else return a negative FDT_ERR_xxx error code. + ******************************************************************************/ +static int dt_set_gpio_config(int node) +{ +	const fdt32_t *cuint, *slewrate; +	int len, pinctrl_node, pinctrl_subnode; +	uint32_t i; +	uint32_t speed = GPIO_SPEED_LOW; +	uint32_t pull = GPIO_NO_PULL; + +	cuint = fdt_getprop(fdt, node, "pinmux", &len); +	if (cuint == NULL) { +		return -FDT_ERR_NOTFOUND; +	} + +	pinctrl_node = fdt_parent_offset(fdt, fdt_parent_offset(fdt, node)); +	if (pinctrl_node < 0) { +		return -FDT_ERR_NOTFOUND; +	} + +	slewrate = fdt_getprop(fdt, node, "slew-rate", NULL); +	if (slewrate != NULL) { +		speed = fdt32_to_cpu(*slewrate); +	} + +	if (fdt_getprop(fdt, node, "bias-pull-up", NULL) != NULL) { +		pull = GPIO_PULL_UP; +	} else if (fdt_getprop(fdt, node, "bias-pull-down", NULL) != NULL) { +		pull = GPIO_PULL_DOWN; +	} else { +		VERBOSE("No bias configured in node %d\n", node); +	} + +	for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) { +		uint32_t pincfg; +		uint32_t bank; +		uint32_t pin; +		uint32_t mode; +		uint32_t alternate = GPIO_ALTERNATE_0; + +		pincfg = fdt32_to_cpu(*cuint); +		cuint++; + +		bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT; + +		pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT; + +		mode = pincfg & DT_GPIO_MODE_MASK; + +		switch (mode) { +		case 0: +			mode = GPIO_MODE_INPUT; +			break; +		case 1 ... 16: +			alternate = mode - 1U; +			mode = GPIO_MODE_ALTERNATE; +			break; +		case 17: +			mode = GPIO_MODE_ANALOG; +			break; +		default: +			mode = GPIO_MODE_OUTPUT; +			break; +		} + +		if (fdt_getprop(fdt, node, "drive-open-drain", NULL) != NULL) { +			mode |= GPIO_OPEN_DRAIN; +		} + +		fdt_for_each_subnode(pinctrl_subnode, fdt, pinctrl_node) { +			uint32_t bank_offset; +			const fdt32_t *cuint2; + +			if (fdt_getprop(fdt, pinctrl_subnode, +					"gpio-controller", NULL) == NULL) { +				continue; +			} + +			cuint2 = fdt_getprop(fdt, pinctrl_subnode, "reg", NULL); +			if (cuint2 == NULL) { +				continue; +			} + +			if (bank == GPIO_BANK_Z) { +				bank_offset = 0; +			} else { +				bank_offset = bank * STM32_GPIO_BANK_OFFSET; +			} + +			if (fdt32_to_cpu(*cuint2) == bank_offset) { +				int clk_id = fdt_get_clock_id(pinctrl_subnode); + +				if (clk_id < 0) { +					return -FDT_ERR_NOTFOUND; +				} + +				if (stm32mp1_clk_enable((unsigned long)clk_id) < +				    0) { +					return -FDT_ERR_BADVALUE; +				} + +				break; +			} +		} + +		set_gpio(bank, pin, mode, speed, pull, alternate); +	} + +	return 0; +} + +/******************************************************************************* + * This function checks device tree file with its header. + * Returns 0 if success, and a negative value else. + ******************************************************************************/ +int dt_open_and_check(void) +{ +	int ret = fdt_check_header(fdt); + +	if (ret == 0) { +		fdt_checked = 1; +	} + +	return ret; +} + +/******************************************************************************* + * This function gets the address of the DT. + * If DT is OK, fdt_addr is filled with DT address. + * Returns 1 if success, 0 otherwise. + ******************************************************************************/ +int fdt_get_address(void **fdt_addr) +{ +	if (fdt_checked == 1) { +		*fdt_addr = fdt; +	} + +	return fdt_checked; +} + +/******************************************************************************* + * This function check the presence of a node (generic use of fdt library). + * Returns true if present, false else. + ******************************************************************************/ +bool fdt_check_node(int node) +{ +	int len; +	const char *cchar; + +	cchar = fdt_get_name(fdt, node, &len); + +	return (cchar != NULL) && (len >= 0); +} + +/******************************************************************************* + * This function check the status of a node (generic use of fdt library). + * Returns true if "okay" or missing, false else. + ******************************************************************************/ +bool fdt_check_status(int node) +{ +	int len; +	const char *cchar; + +	cchar = fdt_getprop(fdt, node, "status", &len); +	if (cchar == NULL) { +		return true; +	} + +	return strncmp(cchar, "okay", (size_t)len) == 0; +} + +/******************************************************************************* + * This function check the secure-status of a node (generic use of fdt library). + * Returns true if "okay" or missing, false else. + ******************************************************************************/ +bool fdt_check_secure_status(int node) +{ +	int len; +	const char *cchar; + +	cchar = fdt_getprop(fdt, node, "secure-status", &len); +	if (cchar == NULL) { +		return true; +	} + +	return strncmp(cchar, "okay", (size_t)len) == 0; +} + +/******************************************************************************* + * This function reads a value of a node property (generic use of fdt + * library). + * Returns value if success, and a default value if property not found. + * Default value is passed as parameter. + ******************************************************************************/ +uint32_t fdt_read_uint32_default(int node, const char *prop_name, +				 uint32_t dflt_value) +{ +	const fdt32_t *cuint; +	int lenp; + +	cuint = fdt_getprop(fdt, node, prop_name, &lenp); +	if (cuint == NULL) { +		return dflt_value; +	} + +	return fdt32_to_cpu(*cuint); +} + +/******************************************************************************* + * This function reads a series of parameters in a node property + * (generic use of fdt library). + * It reads the values inside the device tree, from property name and node. + * The number of parameters is also indicated as entry parameter. + * Returns 0 if success, and a negative value else. + * If success, values are stored at the third parameter address. + ******************************************************************************/ +int fdt_read_uint32_array(int node, const char *prop_name, uint32_t *array, +			  uint32_t count) +{ +	const fdt32_t *cuint; +	int len; +	uint32_t i; + +	cuint = fdt_getprop(fdt, node, prop_name, &len); +	if (cuint == NULL) { +		return -FDT_ERR_NOTFOUND; +	} + +	if ((uint32_t)len != (count * sizeof(uint32_t))) { +		return -FDT_ERR_BADLAYOUT; +	} + +	for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) { +		*array = fdt32_to_cpu(*cuint); +		array++; +		cuint++; +	} + +	return 0; +} + +/******************************************************************************* + * This function gets the pin settings from DT information. + * When analyze and parsing is done, set the GPIO registers. + * Returns 0 if success, and a negative value else. + ******************************************************************************/ +int dt_set_pinctrl_config(int node) +{ +	const fdt32_t *cuint; +	int lenp = 0; +	uint32_t i; + +	if (!fdt_check_status(node)) { +		return -FDT_ERR_NOTFOUND; +	} + +	cuint = fdt_getprop(fdt, node, "pinctrl-0", &lenp); +	if (cuint == NULL) { +		return -FDT_ERR_NOTFOUND; +	} + +	for (i = 0; i < ((uint32_t)lenp / 4U); i++) { +		int phandle_node, phandle_subnode; + +		phandle_node = +			fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint)); +		if (phandle_node < 0) { +			return -FDT_ERR_NOTFOUND; +		} + +		fdt_for_each_subnode(phandle_subnode, fdt, phandle_node) { +			int ret = dt_set_gpio_config(phandle_subnode); + +			if (ret < 0) { +				return ret; +			} +		} + +		cuint++; +	} + +	return 0; +} + +/******************************************************************************* + * This function gets the stdout pin configuration information from the DT. + * And then calls the sub-function to treat it and set GPIO registers. + * Returns 0 if success, and a negative value else. + ******************************************************************************/ +int dt_set_stdout_pinctrl(void) +{ +	int node; + +	node = dt_get_stdout_node_offset(); +	if (node < 0) { +		return -FDT_ERR_NOTFOUND; +	} + +	return dt_set_pinctrl_config(node); +} + +/******************************************************************************* + * This function fills the generic information from a given node. + ******************************************************************************/ +void dt_fill_device_info(struct dt_node_info *info, int node) +{ +	const fdt32_t *cuint; + +	cuint = fdt_getprop(fdt, node, "reg", NULL); +	if (cuint != NULL) { +		info->base = fdt32_to_cpu(*cuint); +	} else { +		info->base = 0; +	} + +	cuint = fdt_getprop(fdt, node, "clocks", NULL); +	if (cuint != NULL) { +		cuint++; +		info->clock = (int)fdt32_to_cpu(*cuint); +	} else { +		info->clock = -1; +	} + +	cuint = fdt_getprop(fdt, node, "resets", NULL); +	if (cuint != NULL) { +		cuint++; +		info->reset = (int)fdt32_to_cpu(*cuint); +	} else { +		info->reset = -1; +	} + +	info->status = fdt_check_status(node); +	info->sec_status = fdt_check_secure_status(node); +} + +/******************************************************************************* + * This function retrieve the generic information from DT. + * Returns node if success, and a negative value else. + ******************************************************************************/ +int dt_get_node(struct dt_node_info *info, int offset, const char *compat) +{ +	int node; + +	node = fdt_node_offset_by_compatible(fdt, offset, compat); +	if (node < 0) { +		return -FDT_ERR_NOTFOUND; +	} + +	dt_fill_device_info(info, node); + +	return node; +} + +/******************************************************************************* + * This function gets the UART instance info of stdout from the DT. + * Returns node if success, and a negative value else. + ******************************************************************************/ +int dt_get_stdout_uart_info(struct dt_node_info *info) +{ +	int node; + +	node = dt_get_stdout_node_offset(); +	if (node < 0) { +		return -FDT_ERR_NOTFOUND; +	} + +	dt_fill_device_info(info, node); + +	return node; +} + +/******************************************************************************* + * This function gets the stdout path node. + * It reads the value indicated inside the device tree. + * Returns node if success, and a negative value else. + ******************************************************************************/ +int dt_get_stdout_node_offset(void) +{ +	int node; +	const char *cchar; + +	node = fdt_path_offset(fdt, "/chosen"); +	if (node < 0) { +		return -FDT_ERR_NOTFOUND; +	} + +	cchar = fdt_getprop(fdt, node, "stdout-path", NULL); +	if (cchar == NULL) { +		return -FDT_ERR_NOTFOUND; +	} + +	node = -FDT_ERR_NOTFOUND; +	if (strchr(cchar, (int)':') != NULL) { +		const char *name; +		char *str = (char *)cchar; +		int len = 0; + +		while (strncmp(":", str, 1)) { +			len++; +			str++; +		} + +		name = fdt_get_alias_namelen(fdt, cchar, len); + +		if (name != NULL) { +			node = fdt_path_offset(fdt, name); +		} +	} else { +		node = fdt_path_offset(fdt, cchar); +	} + +	return node; +} + +/******************************************************************************* + * This function gets DDR size information from the DT. + * Returns value in bytes if success, and STM32MP1_DDR_SIZE_DFLT else. + ******************************************************************************/ +uint32_t dt_get_ddr_size(void) +{ +	int node; + +	node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT); +	if (node < 0) { +		INFO("%s: Cannot read DDR node in DT\n", __func__); +		return STM32MP1_DDR_SIZE_DFLT; +	} + +	return fdt_read_uint32_default(node, "st,mem-size", +				       STM32MP1_DDR_SIZE_DFLT); +} + +/******************************************************************************* + * This function retrieves board model from DT + * Returns string taken from model node, NULL otherwise + ******************************************************************************/ +const char *dt_get_board_model(void) +{ +	int node = fdt_path_offset(fdt, "/"); + +	if (node < 0) { +		return NULL; +	} + +	return (const char *)fdt_getprop(fdt, node, "model", NULL); +} diff --git a/plat/st/stm32mp1/stm32mp1_gic.c b/plat/st/stm32mp1/stm32mp1_gic.c new file mode 100644 index 00000000..11eb0a3e --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_gic.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <bl_common.h> +#include <gicv2.h> +#include <platform.h> +#include <platform_def.h> +#include <utils.h> + +#include <stm32mp1_private.h> + +/****************************************************************************** + * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0 + * interrupts. + *****************************************************************************/ +static const interrupt_prop_t stm32mp1_interrupt_props[] = { +	PLATFORM_G1S_PROPS(GICV2_INTR_GROUP0), +	PLATFORM_G0_PROPS(GICV2_INTR_GROUP0) +}; + +static unsigned int target_mask_array[PLATFORM_CORE_COUNT]; + +static const gicv2_driver_data_t platform_gic_data = { +	.gicd_base = STM32MP1_GICD_BASE, +	.gicc_base = STM32MP1_GICC_BASE, +	.interrupt_props = stm32mp1_interrupt_props, +	.interrupt_props_num = ARRAY_SIZE(stm32mp1_interrupt_props), +	.target_masks = target_mask_array, +	.target_masks_num = ARRAY_SIZE(target_mask_array), +}; + +void stm32mp1_gic_init(void) +{ +	gicv2_driver_init(&platform_gic_data); +	gicv2_distif_init(); + +	stm32mp1_gic_pcpu_init(); +} + +void stm32mp1_gic_pcpu_init(void) +{ +	gicv2_pcpu_distif_init(); +	gicv2_set_pe_target_mask(plat_my_core_pos()); +	gicv2_cpuif_enable(); +} diff --git a/plat/st/stm32mp1/stm32mp1_helper.S b/plat/st/stm32mp1/stm32mp1_helper.S new file mode 100644 index 00000000..b0ea0d8e --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_helper.S @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> +#include <bl_common.h> +#include <platform_def.h> +#include <stm32_gpio.h> +#include <stm32mp1_rcc.h> + +#define GPIO_BANK_G_ADDRESS	0x50008000 +#define GPIO_TX_PORT		11 +#define GPIO_TX_SHIFT		(GPIO_TX_PORT << 1) +#define GPIO_TX_ALT_SHIFT	((GPIO_TX_PORT - GPIO_ALT_LOWER_LIMIT) << 2) +#define STM32MP1_HSI_CLK	64000000 + +	.globl	platform_mem_init +	.globl	plat_report_exception +	.globl	plat_get_my_entrypoint +	.globl	plat_secondary_cold_boot_setup +	.globl	plat_reset_handler +	.globl	plat_is_my_cpu_primary +	.globl	plat_my_core_pos +	.globl	plat_crash_console_init +	.globl	plat_crash_console_flush +	.globl	plat_crash_console_putc +	.globl	plat_panic_handler + +func platform_mem_init +	/* Nothing to do, don't need to init SYSRAM */ +	bx	lr +endfunc platform_mem_init + +func plat_report_exception +	bx	lr +endfunc plat_report_exception + +func plat_reset_handler +	bx	lr +endfunc plat_reset_handler + +	/* ------------------------------------------------------------------ +	 * unsigned long plat_get_my_entrypoint (void); +	 * +	 * Main job of this routine is to distinguish between a cold and warm +	 * boot. +	 * +	 * Currently supports only cold boot +	 * ------------------------------------------------------------------ +	 */ +func plat_get_my_entrypoint +	mov	r0, #0 +	bx	lr +endfunc plat_get_my_entrypoint + +	/* --------------------------------------------- +	 * void plat_secondary_cold_boot_setup (void); +	 * +	 * Cold-booting secondary CPUs is not supported. +	 * --------------------------------------------- +	 */ +func plat_secondary_cold_boot_setup +	b	. +endfunc plat_secondary_cold_boot_setup + +	/* ----------------------------------------------------- +	 * unsigned int plat_is_my_cpu_primary (void); +	 * +	 * Find out whether the current cpu is the primary cpu. +	 * ----------------------------------------------------- +	 */ +func plat_is_my_cpu_primary +	ldcopr	r0, MPIDR +	ldr	r1, =(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK) +	and	r0, r1 +	cmp	r0, #STM32MP1_PRIMARY_CPU +	moveq	r0, #1 +	movne	r0, #0 +	bx	lr +endfunc plat_is_my_cpu_primary + +	/* ------------------------------------------- +	 *  int plat_stm32mp1_get_core_pos(int mpidr); +	 * +	 *  Return CorePos = (ClusterId * 4) + CoreId +	 * ------------------------------------------- +	 */ +func plat_stm32mp1_get_core_pos +	and	r1, r0, #MPIDR_CPU_MASK +	and	r0, r0, #MPIDR_CLUSTER_MASK +	add	r0, r1, r0, LSR #6 +	bx	lr +endfunc plat_stm32mp1_get_core_pos + +	/* ------------------------------------ +	 *  unsigned int plat_my_core_pos(void) +	 * ------------------------------------ +	 */ +func plat_my_core_pos +	ldcopr	r0, MPIDR +	b	plat_stm32mp1_get_core_pos +endfunc plat_my_core_pos + +	/* --------------------------------------------- +	 * int plat_crash_console_init(void) +	 * +	 * Initialize the crash console without a C Runtime stack. +	 * --------------------------------------------- +	 */ +func plat_crash_console_init +	/* Enable GPIOs for UART4 TX */ +	ldr	r1, =(RCC_BASE + RCC_MP_AHB4ENSETR) +	ldr	r2, [r1] +	/* Configure GPIO G11 */ +	orr	r2, r2, #RCC_MP_AHB4ENSETR_GPIOGEN +	str	r2, [r1] +	ldr	r1, =GPIO_BANK_G_ADDRESS +	/* Set GPIO mode alternate */ +	ldr	r2, [r1, #GPIO_MODE_OFFSET] +	bic	r2, r2, #(GPIO_MODE_MASK << GPIO_TX_SHIFT) +	orr	r2, r2, #(GPIO_MODE_ALTERNATE << GPIO_TX_SHIFT) +	str	r2, [r1, #GPIO_MODE_OFFSET] +	/* Set GPIO speed low */ +	ldr	r2, [r1, #GPIO_SPEED_OFFSET] +	bic	r2, r2, #(GPIO_SPEED_MASK << GPIO_TX_SHIFT) +	str	r2, [r1, #GPIO_SPEED_OFFSET] +	/* Set no-pull */ +	ldr	r2, [r1, #GPIO_PUPD_OFFSET] +	bic	r2, r2, #(GPIO_PULL_MASK << GPIO_TX_SHIFT) +	str	r2, [r1, #GPIO_PUPD_OFFSET] +	/* Set alternate AF6 */ +	ldr	r2, [r1, #GPIO_AFRH_OFFSET] +	bic	r2, r2, #(GPIO_ALTERNATE_MASK << GPIO_TX_ALT_SHIFT) +	orr	r2, r2, #(GPIO_ALTERNATE_6 << GPIO_TX_ALT_SHIFT) +	str	r2, [r1, #GPIO_AFRH_OFFSET] + +	/* Enable UART clock, with HSI source */ +	ldr	r1, =(RCC_BASE + RCC_UART24CKSELR) +	mov	r2, #RCC_UART24CKSELR_HSI +	str	r2, [r1] +	ldr	r1, =(RCC_BASE + RCC_MP_APB1ENSETR) +	ldr	r2, [r1] +	orr	r2, r2, #RCC_MP_APB1ENSETR_UART4EN +	str	r2, [r1] + +	ldr	r0, =STM32MP1_DEBUG_USART_BASE +	ldr	r1, =STM32MP1_HSI_CLK +	ldr	r2, =STM32MP1_UART_BAUDRATE +	b	console_core_init +endfunc plat_crash_console_init + +	/* --------------------------------------------- +	 * int plat_crash_console_flush(void) +	 * +	 * Flush the crash console without a C Runtime stack. +	 * --------------------------------------------- +	 */ +func plat_crash_console_flush +	ldr	r1, =STM32MP1_DEBUG_USART_BASE +	b	console_core_flush +endfunc plat_crash_console_flush + +	/* --------------------------------------------- +	 * int plat_crash_console_putc(int c) +	 * +	 * Print a character on the crash console without a C Runtime stack. +	 * Clobber list : r1 - r3 +	 * +	 * In case of bootloading through uart, we keep console crash as this. +	 * Characters could be sent to the programmer, but will be ignored. +	 * No specific code in that case. +	 * --------------------------------------------- +	 */ +func plat_crash_console_putc +	ldr	r1, =STM32MP1_DEBUG_USART_BASE +	b	console_core_putc +endfunc plat_crash_console_putc diff --git a/plat/st/stm32mp1/stm32mp1_pm.c b/plat/st/stm32mp1/stm32mp1_pm.c new file mode 100644 index 00000000..e24af0e5 --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_pm.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch_helpers.h> +#include <assert.h> +#include <boot_api.h> +#include <debug.h> +#include <dt-bindings/clock/stm32mp1-clks.h> +#include <errno.h> +#include <gic_common.h> +#include <gicv2.h> +#include <mmio.h> +#include <platform_def.h> +#include <platform.h> +#include <psci.h> +#include <stm32mp1_clk.h> +#include <stm32mp1_private.h> +#include <stm32mp1_rcc.h> + +static uint32_t stm32_sec_entrypoint; +static uint32_t cntfrq_core0; + +#define SEND_SECURE_IT_TO_CORE_1	0x20000U + +/******************************************************************************* + * STM32MP1 handler called when a CPU is about to enter standby. + * call by core 1 to enter in wfi + ******************************************************************************/ +static void stm32_cpu_standby(plat_local_state_t cpu_state) +{ +	uint32_t interrupt = GIC_SPURIOUS_INTERRUPT; + +	assert(cpu_state == ARM_LOCAL_STATE_RET); + +	/* +	 * Enter standby state +	 * dsb is good practice before using wfi to enter low power states +	 */ +	dsb(); +	while (interrupt == GIC_SPURIOUS_INTERRUPT) { +		wfi(); + +		/* Acknoledge IT */ +		interrupt = gicv2_acknowledge_interrupt(); +		/* If Interrupt == 1022 it will be acknowledged by non secure */ +		if ((interrupt != PENDING_G1_INTID) && +		    (interrupt != GIC_SPURIOUS_INTERRUPT)) { +			gicv2_end_of_interrupt(interrupt); +		} +	} +} + +/******************************************************************************* + * STM32MP1 handler called when a power domain is about to be turned on. The + * mpidr determines the CPU to be turned on. + * call by core  0 to activate core 1 + ******************************************************************************/ +static int stm32_pwr_domain_on(u_register_t mpidr) +{ +	unsigned long current_cpu_mpidr = read_mpidr_el1(); +	uint32_t tamp_clk_off = 0; +	uint32_t bkpr_core1_addr = +		tamp_bkpr(BOOT_API_CORE1_BRANCH_ADDRESS_TAMP_BCK_REG_IDX); +	uint32_t bkpr_core1_magic = +		tamp_bkpr(BOOT_API_CORE1_MAGIC_NUMBER_TAMP_BCK_REG_IDX); + +	if (mpidr == current_cpu_mpidr) { +		return PSCI_E_INVALID_PARAMS; +	} + +	if ((stm32_sec_entrypoint < STM32MP1_SRAM_BASE) || +	    (stm32_sec_entrypoint > (STM32MP1_SRAM_BASE + +				     (STM32MP1_SRAM_SIZE - 1)))) { +		return PSCI_E_INVALID_ADDRESS; +	} + +	if (!stm32mp1_clk_is_enabled(RTCAPB)) { +		tamp_clk_off = 1; +		if (stm32mp1_clk_enable(RTCAPB) != 0) { +			panic(); +		} +	} + +	cntfrq_core0 = read_cntfrq_el0(); + +	/* Write entrypoint in backup RAM register */ +	mmio_write_32(bkpr_core1_addr, stm32_sec_entrypoint); + +	/* Write magic number in backup register */ +	mmio_write_32(bkpr_core1_magic, BOOT_API_A7_CORE1_MAGIC_NUMBER); + +	if (tamp_clk_off != 0U) { +		if (stm32mp1_clk_disable(RTCAPB) != 0) { +			panic(); +		} +	} + +	/* Generate an IT to core 1 */ +	mmio_write_32(STM32MP1_GICD_BASE + GICD_SGIR, +		      SEND_SECURE_IT_TO_CORE_1 | ARM_IRQ_SEC_SGI_0); + +	return PSCI_E_SUCCESS; +} + +/******************************************************************************* + * STM32MP1 handler called when a power domain is about to be turned off. The + * target_state encodes the power state that each level should transition to. + ******************************************************************************/ +static void stm32_pwr_domain_off(const psci_power_state_t *target_state) +{ +	/* Nothing to do */ +} + +/******************************************************************************* + * STM32MP1 handler called when a power domain is about to be suspended. The + * target_state encodes the power state that each level should transition to. + ******************************************************************************/ +static void stm32_pwr_domain_suspend(const psci_power_state_t *target_state) +{ +	/* Nothing to do, power domain is not disabled */ +} + +/******************************************************************************* + * STM32MP1 handler called when a power domain has just been powered on after + * being turned off earlier. The target_state encodes the low power state that + * each level has woken up from. + * call by core 1 just after wake up + ******************************************************************************/ +static void stm32_pwr_domain_on_finish(const psci_power_state_t *target_state) +{ +	stm32mp1_gic_pcpu_init(); + +	write_cntfrq_el0(cntfrq_core0); +} + +/******************************************************************************* + * STM32MP1 handler called when a power domain has just been powered on after + * having been suspended earlier. The target_state encodes the low power state + * that each level has woken up from. + ******************************************************************************/ +static void stm32_pwr_domain_suspend_finish(const psci_power_state_t +					    *target_state) +{ +	/* Nothing to do, power domain is not disabled */ +} + +static void __dead2 stm32_pwr_domain_pwr_down_wfi(const psci_power_state_t +						  *target_state) +{ +	ERROR("stm32mpu1 Power Down WFI: operation not handled.\n"); +	panic(); +} + +static void __dead2 stm32_system_off(void) +{ +	ERROR("stm32mpu1 System Off: operation not handled.\n"); +	panic(); +} + +static void __dead2 stm32_system_reset(void) +{ +	mmio_setbits_32(RCC_BASE + RCC_MP_GRSTCSETR, RCC_MP_GRSTCSETR_MPSYSRST); + +	/* Loop in case system reset is not immediately caught */ +	for ( ; ; ) { +		; +	} +} + +static int stm32_validate_power_state(unsigned int power_state, +				      psci_power_state_t *req_state) +{ +	int pstate = psci_get_pstate_type(power_state); + +	if (pstate != 0) { +		return PSCI_E_INVALID_PARAMS; +	} + +	if (psci_get_pstate_pwrlvl(power_state)) { +		return PSCI_E_INVALID_PARAMS; +	} + +	if (psci_get_pstate_id(power_state)) { +		return PSCI_E_INVALID_PARAMS; +	} + +	req_state->pwr_domain_state[0] = ARM_LOCAL_STATE_RET; +	req_state->pwr_domain_state[1] = ARM_LOCAL_STATE_RUN; + +	return PSCI_E_SUCCESS; +} + +static int stm32_validate_ns_entrypoint(uintptr_t entrypoint) +{ +	/* The non-secure entry point must be in DDR */ +	if (entrypoint < STM32MP1_DDR_BASE) { +		return PSCI_E_INVALID_ADDRESS; +	} + +	return PSCI_E_SUCCESS; +} + +static int stm32_node_hw_state(u_register_t target_cpu, +			       unsigned int power_level) +{ +	/* +	 * The format of 'power_level' is implementation-defined, but 0 must +	 * mean a CPU. Only allow level 0. +	 */ +	if (power_level != MPIDR_AFFLVL0) { +		return PSCI_E_INVALID_PARAMS; +	} + +	/* +	 * From psci view the CPU 0 is always ON, +	 * CPU 1 can be SUSPEND or RUNNING. +	 * Therefore do not manage POWER OFF state and always return HW_ON. +	 */ + +	return (int)HW_ON; +} + +/******************************************************************************* + * Export the platform handlers. The ARM Standard platform layer will take care + * of registering the handlers with PSCI. + ******************************************************************************/ +static const plat_psci_ops_t stm32_psci_ops = { +	.cpu_standby = stm32_cpu_standby, +	.pwr_domain_on = stm32_pwr_domain_on, +	.pwr_domain_off = stm32_pwr_domain_off, +	.pwr_domain_suspend = stm32_pwr_domain_suspend, +	.pwr_domain_on_finish = stm32_pwr_domain_on_finish, +	.pwr_domain_suspend_finish = stm32_pwr_domain_suspend_finish, +	.pwr_domain_pwr_down_wfi = stm32_pwr_domain_pwr_down_wfi, +	.system_off = stm32_system_off, +	.system_reset = stm32_system_reset, +	.validate_power_state = stm32_validate_power_state, +	.validate_ns_entrypoint = stm32_validate_ns_entrypoint, +	.get_node_hw_state = stm32_node_hw_state +}; + +/******************************************************************************* + * Export the platform specific power ops. + ******************************************************************************/ +int plat_setup_psci_ops(uintptr_t sec_entrypoint, +			const plat_psci_ops_t **psci_ops) +{ +	stm32_sec_entrypoint = sec_entrypoint; +	*psci_ops = &stm32_psci_ops; + +	return 0; +} diff --git a/plat/st/stm32mp1/stm32mp1_security.c b/plat/st/stm32mp1/stm32mp1_security.c new file mode 100644 index 00000000..e783c14e --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_security.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <debug.h> +#include <dt-bindings/clock/stm32mp1-clks.h> +#include <mmio.h> +#include <stdint.h> +#include <stm32mp1_clk.h> +#include <stm32mp1_dt.h> +#include <stm32mp1_private.h> +#include <stm32mp1_rcc.h> +#include <tzc400.h> +#include "platform_def.h" + +/******************************************************************************* + * Initialize the TrustZone Controller. Configure Region 0 with Secure RW access + * and allow Non-Secure masters full access. + ******************************************************************************/ +static void init_tzc400(void) +{ +	unsigned long long region_base, region_top; +	unsigned long long ddr_base = STM32MP1_DDR_BASE; +	unsigned long long ddr_size = (unsigned long long)dt_get_ddr_size(); + +	tzc400_init(STM32MP1_TZC_BASE); + +	tzc400_disable_filters(); + +	/* Region 1 set to cover all DRAM at 0xC000_0000. Apply the +	 * same configuration to all filters in the TZC. +	 */ +	region_base = ddr_base; +	region_top = ddr_base + (ddr_size - 1U); +	tzc400_configure_region(STM32MP1_FILTER_BIT_ALL, 1, +			region_base, +			region_top, +			TZC_REGION_S_RDWR, +			TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_A7_ID) | +			TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_GPU_ID) | +			TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_LCD_ID) | +			TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_MDMA_ID) | +			TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_DMA_ID) | +			TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_USB_HOST_ID) | +			TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_USB_OTG_ID) | +			TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_SDMMC_ID) | +			TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_ETH_ID) | +			TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_DAP_ID)); + +	/* Raise an exception if a NS device tries to access secure memory */ +	tzc400_set_action(TZC_ACTION_ERR); + +	tzc400_enable_filters(); +} + +/******************************************************************************* + * Initialize the TrustZone Controller. + * Early initialization create only one region with full access to secure. + * This setting is used before and during DDR initialization. + ******************************************************************************/ +static void early_init_tzc400(void) +{ +	uint32_t rstsr, rst_standby; + +	rstsr = mmio_read_32(RCC_BASE + RCC_MP_RSTSCLRR); + +	/* No warning if return from (C)STANDBY */ +	rst_standby = rstsr & +		(RCC_MP_RSTSCLRR_STDBYRSTF | RCC_MP_RSTSCLRR_CSTDBYRSTF); + +	if (stm32mp1_clk_is_enabled(TZC1) && (rst_standby == 0U)) { +		WARN("TZC400 port 1 clock already enable\n"); +	} + +	if (stm32mp1_clk_is_enabled(TZC2) && (rst_standby == 0U)) { +		WARN("TZC400 port 2 clock already enable\n"); +	} + +	if (stm32mp1_clk_enable(TZC1) != 0) { +		ERROR("Cannot enable TZC1 clock\n"); +		panic(); +	} +	if (stm32mp1_clk_enable(TZC2) != 0) { +		ERROR("Cannot enable TZC2 clock\n"); +		panic(); +	} + +	tzc400_init(STM32MP1_TZC_BASE); + +	tzc400_disable_filters(); + +	/* +	 * Region 1 set to cover Non-Secure DRAM at 0x8000_0000. Apply the +	 * same configuration to all filters in the TZC. +	 */ +	tzc400_configure_region(STM32MP1_FILTER_BIT_ALL, 1, +				STM32MP1_DDR_BASE, +				STM32MP1_DDR_BASE + +				(STM32MP1_DDR_MAX_SIZE - 1U), +				TZC_REGION_S_RDWR, +				TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_SDMMC_ID)); + +	/* Raise an exception if a NS device tries to access secure memory */ +	tzc400_set_action(TZC_ACTION_ERR); + +	tzc400_enable_filters(); +} + +/******************************************************************************* + * Initialize the secure environment. At this moment only the TrustZone + * Controller is initialized. + ******************************************************************************/ +void stm32mp1_arch_security_setup(void) +{ +	early_init_tzc400(); +} + +/******************************************************************************* + * Initialize the secure environment. At this moment only the TrustZone + * Controller is initialized. + ******************************************************************************/ +void stm32mp1_security_setup(void) +{ +	init_tzc400(); +} diff --git a/plat/st/stm32mp1/stm32mp1_stack_protector.c b/plat/st/stm32mp1/stm32mp1_stack_protector.c new file mode 100644 index 00000000..c6813009 --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_stack_protector.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch_helpers.h> +#include <platform.h> +#include <stdint.h> + +#define RANDOM_CANARY_VALUE	2144346116U + +u_register_t plat_get_stack_protector_canary(void) +{ +	/* +	 * Ideally, a random number should be returned instead of the +	 * combination of a timer's value and a compile-time constant. +	 */ +	return RANDOM_CANARY_VALUE ^ (u_register_t)read_cntpct_el0(); +} + diff --git a/plat/st/stm32mp1/stm32mp1_topology.c b/plat/st/stm32mp1/stm32mp1_topology.c new file mode 100644 index 00000000..405aa33e --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_topology.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <platform_def.h> +#include <platform.h> +#include <psci.h> + +/* 1 cluster, all cores into */ +static const unsigned char stm32mp1_power_domain_tree_desc[] = { +	PLATFORM_CLUSTER_COUNT, +	PLATFORM_CORE_COUNT, +}; + +/* This function returns the platform topology */ +const unsigned char *plat_get_power_domain_tree_desc(void) +{ +	return stm32mp1_power_domain_tree_desc; +} + +/******************************************************************************* + * This function implements a part of the critical interface between the psci + * generic layer and the platform that allows the former to query the platform + * to convert an MPIDR to a unique linear index. An error code (-1) is returned + * in case the MPIDR is invalid. + ******************************************************************************/ +int plat_core_pos_by_mpidr(u_register_t mpidr) +{ +	unsigned int cluster_id, cpu_id; +	u_register_t mpidr_copy = mpidr; + +	mpidr_copy &= MPIDR_AFFINITY_MASK; + +	if ((mpidr_copy & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) != 0U) { +		return -1; +	} + +	cluster_id = (mpidr_copy >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; +	cpu_id = (mpidr_copy >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK; + +	if (cluster_id >= PLATFORM_CLUSTER_COUNT) { +		return -1; +	} + +	/* +	 * Validate cpu_id by checking whether it represents a CPU in one +	 * of the two clusters present on the platform. +	 */ +	if (cpu_id >= PLATFORM_CORE_COUNT) { +		return -1; +	} + +	return (int)cpu_id; +} diff --git a/tools/stm32image/Makefile b/tools/stm32image/Makefile new file mode 100644 index 00000000..80dfbecf --- /dev/null +++ b/tools/stm32image/Makefile @@ -0,0 +1,49 @@ +# +# Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +MAKE_HELPERS_DIRECTORY := ../../make_helpers/ +include ${MAKE_HELPERS_DIRECTORY}build_macros.mk +include ${MAKE_HELPERS_DIRECTORY}build_env.mk + +PROJECT := stm32image${BIN_EXT} +OBJECTS := stm32image.o +V := 0 + +override CPPFLAGS += -D_GNU_SOURCE +CFLAGS := -Wall -Werror -pedantic -std=c99 +ifeq (${DEBUG},1) +  CFLAGS += -g -O0 -DDEBUG +else +  CFLAGS += -O2 +endif + +ifeq (${V},0) +  Q := @ +else +  Q := +endif + +CC := gcc + +.PHONY: all clean distclean + +all: ${PROJECT} + +${PROJECT}: ${OBJECTS} Makefile +	@echo "  LD      $@" +	${Q}${CC} ${OBJECTS} -o $@ +	@${ECHO_BLANK_LINE} +	@echo "Built $@ successfully" +	@${ECHO_BLANK_LINE} + +%.o: %.c %.h Makefile +	@echo "  CC      $<" +	${Q}${CC} -c ${CFLAGS} $< -o $@ + +clean: +	$(call SHELL_DELETE_ALL, ${PROJECT} ${OBJECTS}) + +distclean: clean diff --git a/tools/stm32image/stm32image.c b/tools/stm32image/stm32image.c new file mode 100644 index 00000000..26079284 --- /dev/null +++ b/tools/stm32image/stm32image.c @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <asm/byteorder.h> +#include <errno.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +/* Magic = 'S' 'T' 'M' 0x32 */ +#define HEADER_MAGIC		__be32_to_cpu(0x53544D32) +#define VER_MAJOR		2 +#define VER_MINOR		1 +#define VER_VARIANT		0 +#define HEADER_VERSION_V1	0x1 +#define TF_BINARY_TYPE		0x0 + +/* Default option : bit0 => no signature */ +#define HEADER_DEFAULT_OPTION	(__cpu_to_le32(0x00000001)) + +struct stm32_header { +	uint32_t magic_number; +	uint8_t image_signature[64]; +	uint32_t image_checksum; +	uint8_t  header_version[4]; +	uint32_t image_length; +	uint32_t image_entry_point; +	uint32_t reserved1; +	uint32_t load_address; +	uint32_t reserved2; +	uint32_t version_number; +	uint32_t option_flags; +	uint32_t ecdsa_algorithm; +	uint8_t ecdsa_public_key[64]; +	uint8_t padding[83]; +	uint8_t binary_type; +}; + +static struct stm32_header stm32image_header; + +static void stm32image_default_header(struct stm32_header *ptr) +{ +	if (!ptr) { +		return; +	} + +	ptr->magic_number = HEADER_MAGIC; +	ptr->header_version[VER_MAJOR] = HEADER_VERSION_V1; +	ptr->option_flags = HEADER_DEFAULT_OPTION; +	ptr->ecdsa_algorithm = 1; +	ptr->version_number = 0; +	ptr->binary_type = TF_BINARY_TYPE; +} + +static uint32_t stm32image_checksum(void *start, uint32_t len) +{ +	uint32_t csum = 0; +	uint32_t hdr_len = sizeof(struct stm32_header); +	uint8_t *p; + +	if (len < hdr_len) { +		return 0; +	} + +	p = (unsigned char *)start + hdr_len; +	len -= hdr_len; + +	while (len > 0) { +		csum += *p; +		p++; +		len--; +	} + +	return csum; +} + +static void stm32image_print_header(const void *ptr) +{ +	struct stm32_header *stm32hdr = (struct stm32_header *)ptr; + +	printf("Image Type   : ST Microelectronics STM32 V%d.%d\n", +	       stm32hdr->header_version[VER_MAJOR], +	       stm32hdr->header_version[VER_MINOR]); +	printf("Image Size   : %lu bytes\n", +	       (unsigned long)__le32_to_cpu(stm32hdr->image_length)); +	printf("Image Load   : 0x%08x\n", +	       __le32_to_cpu(stm32hdr->load_address)); +	printf("Entry Point  : 0x%08x\n", +	       __le32_to_cpu(stm32hdr->image_entry_point)); +	printf("Checksum     : 0x%08x\n", +	       __le32_to_cpu(stm32hdr->image_checksum)); +	printf("Option     : 0x%08x\n", +	       __le32_to_cpu(stm32hdr->option_flags)); +	printf("Version	   : 0x%08x\n", +	       __le32_to_cpu(stm32hdr->version_number)); +} + +static void stm32image_set_header(void *ptr, struct stat *sbuf, int ifd, +				  uint32_t loadaddr, uint32_t ep, uint32_t ver) +{ +	struct stm32_header *stm32hdr = (struct stm32_header *)ptr; + +	stm32image_default_header(stm32hdr); + +	stm32hdr->load_address = __cpu_to_le32(loadaddr); +	stm32hdr->image_entry_point = __cpu_to_le32(ep); +	stm32hdr->image_length = __cpu_to_le32((uint32_t)sbuf->st_size - +					     sizeof(struct stm32_header)); +	stm32hdr->image_checksum = stm32image_checksum(ptr, sbuf->st_size); +	stm32hdr->version_number = __cpu_to_le32(ver); +} + +static int stm32image_create_header_file(char *srcname, char *destname, +					 uint32_t loadaddr, uint32_t entry, +					 uint32_t version) +{ +	int src_fd, dest_fd; +	struct stat sbuf; +	unsigned char *ptr; + +	dest_fd = open(destname, O_RDWR | O_CREAT | O_TRUNC | O_APPEND, 0666); +	if (dest_fd == -1) { +		fprintf(stderr, "Can't open %s: %s\n", destname, +			strerror(errno)); +		return -1; +	} + +	src_fd = open(srcname, O_RDONLY); +	if (src_fd == -1) { +		fprintf(stderr, "Can't open %s: %s\n", srcname, +			strerror(errno)); +		return -1; +	} + +	if (fstat(src_fd, &sbuf) < 0) { +		return -1; +	} + +	ptr = mmap(NULL, sbuf.st_size, PROT_READ, MAP_SHARED, src_fd, 0); +	if (ptr == MAP_FAILED) { +		fprintf(stderr, "Can't read %s\n", srcname); +		return -1; +	} + +	memset(&stm32image_header, 0, sizeof(struct stm32_header)); + +	if (write(dest_fd, &stm32image_header, sizeof(struct stm32_header)) != +	    sizeof(struct stm32_header)) { +		fprintf(stderr, "Write error %s: %s\n", destname, +			strerror(errno)); +		return -1; +	} + +	if (write(dest_fd, ptr, sbuf.st_size) != sbuf.st_size) { +		fprintf(stderr, "Write error on %s: %s\n", destname, +			strerror(errno)); +		return -1; +	} + +	munmap((void *)ptr, sbuf.st_size); +	close(src_fd); + +	if (fstat(dest_fd, &sbuf) < 0) { +		return -1; +	} + +	ptr = mmap(0, sbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, +		   dest_fd, 0); + +	if (ptr == MAP_FAILED) { +		fprintf(stderr, "Can't read %s\n", srcname); +		return -1; +	} + +	stm32image_set_header(ptr, &sbuf, dest_fd, loadaddr, entry, version); + +	stm32image_print_header(ptr); + +	munmap((void *)ptr, sbuf.st_size); +	close(dest_fd); +	return 0; +} + +int main(int argc, char *argv[]) +{ +	int opt, loadaddr = -1, entry = -1, err = 0, version = 0; +	char *dest = NULL, *src = NULL; + +	while ((opt = getopt(argc, argv, ":s:d:l:e:v:")) != -1) { +		switch (opt) { +		case 's': +			src = optarg; +			break; +		case 'd': +			dest = optarg; +			break; +		case 'l': +			loadaddr = strtol(optarg, NULL, 16); +			break; +		case 'e': +			entry = strtol(optarg, NULL, 16); +			break; +		case 'v': +			version = strtol(optarg, NULL, 10); +			break; +		default: +			fprintf(stderr, +				"Usage : %s [-s srcfile] [-d destfile] [-l loadaddr] [-e entry_point]\n", +					argv[0]); +			return -1; +		} +	} + +	if (!src) { +		fprintf(stderr, "Missing -s option\n"); +		return -1; +	} + +	if (!dest) { +		fprintf(stderr, "Missing -d option\n"); +		return -1; +	} + +	if (loadaddr == -1) { +		fprintf(stderr, "Missing -l option\n"); +		return -1; +	} + +	if (entry == -1) { +		fprintf(stderr, "Missing -e option\n"); +		return -1; +	} + +	err = stm32image_create_header_file(src, dest, loadaddr, +					    entry, version); + +	return err; +} | 
