Unverified Commit d87d524e authored by danh-arm's avatar danh-arm Committed by GitHub
Browse files

Merge pull request #1466 from Yann-lms/stm32mp1

Add STMicroelectronics STM32MP1 platform support
Showing with 6427 additions and 0 deletions
+6427 -0
......@@ -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
......
......@@ -16,5 +16,7 @@ NXP Semiconductors
Marvell International Ltd.
STMicroelectronics
Individuals
-----------
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.
This diff is collapsed.
/*
* 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);
}
This diff is collapsed.
/*
* 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);
}
/*
* 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();
}
/*
* 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));
}
This diff is collapsed.
/*
* 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;
}
This diff is collapsed.
/*
* 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) {
;
}
}
/*
* 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
// 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";
};
};
};
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
// 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";
};
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment