summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/boards/stm32mp.rst71
-rw-r--r--arch/arm/Kconfig2
-rw-r--r--arch/arm/dts/stm32mp157c.dtsi2
-rw-r--r--arch/arm/mach-stm32mp/Kconfig8
-rw-r--r--common/filetype.c9
-rw-r--r--drivers/reset/Kconfig5
-rw-r--r--drivers/reset/Makefile1
-rw-r--r--drivers/reset/reset-stm32.c109
-rw-r--r--images/Makefile.stm32mp15
-rw-r--r--include/filetype.h1
-rw-r--r--include/gpio.h4
-rw-r--r--scripts/Makefile1
-rw-r--r--scripts/Makefile.lib3
-rw-r--r--scripts/stm32image.c281
14 files changed, 506 insertions, 6 deletions
diff --git a/Documentation/boards/stm32mp.rst b/Documentation/boards/stm32mp.rst
new file mode 100644
index 0000000000..24cf8859db
--- /dev/null
+++ b/Documentation/boards/stm32mp.rst
@@ -0,0 +1,71 @@
+STMicroelectronics STM32MP
+==========================
+
+.. note::
+
+ Support for the STM32MP architecure in barebox is still in progress.
+ Bootstrapping an OS from mainline barebox is not yet supported.
+
+The STM32MP is a line of 32-bit ARM SoCs. They reuse peripherals of the
+STM32 line of microcontrollers and can have a STM32 MCU embedded as co-processor
+as well.
+
+The boot process of the STM32MP SoC is a two step process.
+The first stage boot loader (FSBL) is loaded by the ROM code into the built-in
+SYSRAM and executed. The FSBL sets up the SDRAM, install a secure monitor and
+then the second stage boot loader (SSBL) is loaded into DRAM.
+
+When building barebox, the resulting ``barebox-${board}.img`` file has the STM32
+header preprended, so it can be loaded directly as SSBL by the ARM TF-A
+(https://github.com/ARM-software/arm-trusted-firmware). Each entry point has a
+header-less image ending in ``*.pblb`` as well.
+
+Use of barebox as FSBL is not supported.
+
+Building barebox
+----------------
+
+With multi-image and device trees, it's expected to have ``stm32mp_defconfig``
+as sole defconfig for all STM32MP boards::
+
+ make ARCH=arm stm32mp_defconfig
+
+The resulting images will be placed under ``images/``:
+
+::
+
+ barebox-stm32mp157c-dk2.img
+
+
+Flashing barebox
+----------------
+
+An appropriate image for the boot media can be generated with following
+``genimage(1)`` config::
+
+ image @STM32MP_BOARD@.img {
+ hdimage {
+ align = 1M
+ gpt = "true"
+ }
+ partition fsbl1 {
+ image = "tf-a-@STM32MP_BOARD@.stm32"
+ size = 256K
+ }
+ partition fsbl2 {
+ image = "tf-a-@STM32MP_BOARD@.stm32"
+ size = 256K
+ }
+ partition ssbl {
+ image = "barebox-@STM32MP_BOARD@.img"
+ size = 1M
+ }
+ }
+
+Image can then be flashed on e.g. a SD-Card.
+
+TODO
+----
+
+* Extend barebox MMCI support to support the SDMMC2
+* Extend barebox DesignWare MAC support to support the stmmac
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 0f5190b417..de45bcf82a 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -208,7 +208,7 @@ config ARCH_S3C64xx
select GENERIC_GPIO
config ARCH_STM32MP
- bool "ST stm32mp1xx"
+ bool "STMicroelectronics STM32MP"
select CPU_V7
select HAVE_PBL_MULTI_IMAGES
select CLKDEV_LOOKUP
diff --git a/arch/arm/dts/stm32mp157c.dtsi b/arch/arm/dts/stm32mp157c.dtsi
index b97622c8d4..8d9c84a047 100644
--- a/arch/arm/dts/stm32mp157c.dtsi
+++ b/arch/arm/dts/stm32mp157c.dtsi
@@ -17,6 +17,6 @@
gpio8 = &gpioi;
gpio9 = &gpioj;
gpio10 = &gpiok;
- gpio11 = &gpioz;
+ gpio25 = &gpioz;
};
};
diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig
index be16294f5a..6bf950b23f 100644
--- a/arch/arm/mach-stm32mp/Kconfig
+++ b/arch/arm/mach-stm32mp/Kconfig
@@ -1,10 +1,14 @@
if ARCH_STM32MP
-config ARCH_STM32MP1157
+config ARCH_NR_GPIO
+ int
+ default 416
+
+config ARCH_STM32MP157
bool
config MACH_STM32MP157C_DK2
- select ARCH_STM32MP1157
+ select ARCH_STM32MP157
select ARM_USE_COMPRESSED_DTB
bool "STM32MP157C-DK2 board"
diff --git a/common/filetype.c b/common/filetype.c
index 329f5144bf..825bf25ad1 100644
--- a/common/filetype.c
+++ b/common/filetype.c
@@ -79,6 +79,7 @@ static const struct filetype_str filetype_str[] = {
[filetype_layerscape_qspi_image] = { "Layerscape QSPI image", "layerscape-qspi-PBL" },
[filetype_ubootvar] = { "U-Boot environmemnt variable data",
"ubootvar" },
+ [filetype_stm32_image_v1] = { "STM32 image (v1)", "stm32-image-v1" },
};
const char *file_type_to_string(enum filetype f)
@@ -355,6 +356,14 @@ enum filetype file_detect_type(const void *_buf, size_t bufsize)
if (buf8[0] == 'M' && buf8[1] == 'Z')
return filetype_exe;
+ if (bufsize < 256)
+ return filetype_unknown;
+
+ if (strncmp(buf8, "STM\x32", 4) == 0) {
+ if (buf8[74] == 0x01)
+ return filetype_stm32_image_v1;
+ }
+
if (bufsize < 512)
return filetype_unknown;
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index caf1dc9acb..048f2081f8 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -21,4 +21,9 @@ config RESET_IMX7
help
This enables the reset controller driver for i.MX7 SoCs.
+config RESET_STM32
+ bool "STM32 Reset Driver"
+ help
+ This enables the reset controller driver for STM32MP and STM32 MCUs.
+
endif
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 0b55caa204..8460c4b154 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -1,3 +1,4 @@
obj-$(CONFIG_RESET_CONTROLLER) += core.o
obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
obj-$(CONFIG_RESET_IMX7) += reset-imx7.o
+obj-$(CONFIG_RESET_STM32) += reset-stm32.o
diff --git a/drivers/reset/reset-stm32.c b/drivers/reset/reset-stm32.c
new file mode 100644
index 0000000000..5689dfd488
--- /dev/null
+++ b/drivers/reset/reset-stm32.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
+ * Copyright (C) 2019, Ahmad Fatoum, Pengutronix
+ * Author(s): Patrice Chotard, <patrice.chotard@st.com> for STMicroelectronics.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <linux/err.h>
+#include <linux/reset-controller.h>
+#include <asm/io.h>
+
+#define RCC_CL 0x4
+
+struct stm32_reset {
+ void __iomem *base;
+ struct reset_controller_dev rcdev;
+ void (*reset)(void __iomem *reg, unsigned offset, bool assert);
+};
+
+static struct stm32_reset *to_stm32_reset(struct reset_controller_dev *rcdev)
+{
+ return container_of(rcdev, struct stm32_reset, rcdev);
+}
+
+static void stm32mp_reset(void __iomem *reg, unsigned offset, bool assert)
+{
+ if (!assert)
+ reg += RCC_CL;
+
+ writel(BIT(offset), reg);
+}
+
+static void stm32mcu_reset(void __iomem *reg, unsigned offset, bool assert)
+{
+ if (assert)
+ setbits_le32(reg, BIT(offset));
+ else
+ clrbits_le32(reg, BIT(offset));
+}
+
+static void stm32_reset(struct stm32_reset *priv, unsigned long id, bool assert)
+{
+ int bank = (id / BITS_PER_LONG) * 4;
+ int offset = id % BITS_PER_LONG;
+
+ priv->reset(priv->base + bank, offset, assert);
+}
+
+static int stm32_reset_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ stm32_reset(to_stm32_reset(rcdev), id, true);
+ return 0;
+}
+
+static int stm32_reset_deassert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ stm32_reset(to_stm32_reset(rcdev), id, false);
+ return 0;
+}
+
+static const struct reset_control_ops stm32_reset_ops = {
+ .assert = stm32_reset_assert,
+ .deassert = stm32_reset_deassert,
+};
+
+static int stm32_reset_probe(struct device_d *dev)
+{
+ struct stm32_reset *priv;
+ struct resource *iores;
+ int ret;
+
+ priv = xzalloc(sizeof(*priv));
+ ret = dev_get_drvdata(dev, (const void **)&priv->reset);
+ if (ret)
+ return ret;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+
+ priv->base = IOMEM(iores->start);
+ priv->rcdev.nr_resets = (iores->end - iores->start) * BITS_PER_BYTE;
+ priv->rcdev.ops = &stm32_reset_ops;
+ priv->rcdev.of_node = dev->device_node;
+
+ return reset_controller_register(&priv->rcdev);
+}
+
+static const struct of_device_id stm32_rcc_reset_dt_ids[] = {
+ { .compatible = "st,stm32mp1-rcc", .data = stm32mp_reset },
+ { .compatible = "st,stm32-rcc", .data = stm32mcu_reset },
+ { /* sentinel */ },
+};
+
+static struct driver_d stm32_rcc_reset_driver = {
+ .name = "stm32_rcc_reset",
+ .probe = stm32_reset_probe,
+ .of_compatible = DRV_OF_COMPAT(stm32_rcc_reset_dt_ids),
+};
+
+static int stm32_rcc_reset_init(void)
+{
+ return platform_driver_register(&stm32_rcc_reset_driver);
+}
+postcore_initcall(stm32_rcc_reset_init);
diff --git a/images/Makefile.stm32mp b/images/Makefile.stm32mp
index c49b1d72b7..910e029a5b 100644
--- a/images/Makefile.stm32mp
+++ b/images/Makefile.stm32mp
@@ -1,8 +1,19 @@
# SPDX-License-Identifier: GPL-2.0-or-later
#
-# barebox image generation Makefile for STMicroelectronics MP1
+# barebox image generation Makefile for STMicroelectronics MP
#
+# %.stm32 - convert into STM32MP image
+# --------------------------------------
+
+$(obj)/%.stm32: $(obj)/% FORCE
+ $(call if_changed,stm32_image)
+
+STM32MP1_OPTS = -a 0xc0100000 -e 0xc0100000 -v1
+
+# --------------------------------------
+
pblb-$(CONFIG_MACH_STM32MP157C_DK2) += start_stm32mp157c_dk2
-FILE_barebox-stm32mp157c-dk2.img = start_stm32mp157c_dk2.pblb
+FILE_barebox-stm32mp157c-dk2.img = start_stm32mp157c_dk2.pblb.stm32
+OPTS_start_stm32mp157c_dk2.pblb.stm32 = $(STM32MP1_OPTS)
image-$(CONFIG_MACH_STM32MP157C_DK2) += barebox-stm32mp157c-dk2.img
diff --git a/include/filetype.h b/include/filetype.h
index f1be04e816..90a03de581 100644
--- a/include/filetype.h
+++ b/include/filetype.h
@@ -48,6 +48,7 @@ enum filetype {
filetype_layerscape_image,
filetype_layerscape_qspi_image,
filetype_ubootvar,
+ filetype_stm32_image_v1,
filetype_max,
};
diff --git a/include/gpio.h b/include/gpio.h
index e822fd5347..1926edeca7 100644
--- a/include/gpio.h
+++ b/include/gpio.h
@@ -45,7 +45,11 @@ static inline int gpio_direction_active(unsigned gpio, int value)
}
#endif
+#if defined(CONFIG_ARCH_NR_GPIO) && CONFIG_ARCH_NR_GPIO > 0
+#define ARCH_NR_GPIOS CONFIG_ARCH_NR_GPIO
+#else
#define ARCH_NR_GPIOS 256
+#endif
static inline int gpio_is_valid(int gpio)
{
diff --git a/scripts/Makefile b/scripts/Makefile
index 7d64da6b55..dffab53c73 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -22,6 +22,7 @@ hostprogs-$(CONFIG_ARCH_ZYNQ) += zynq_mkimage
hostprogs-$(CONFIG_ARCH_SOCFPGA) += socfpga_mkimage
hostprogs-$(CONFIG_MXS_HOSTTOOLS)+= mxsimage mxsboot
hostprogs-$(CONFIG_ARCH_LAYERSCAPE) += pblimage
+hostprogs-$(CONFIG_ARCH_STM32MP) += stm32image
HOSTCFLAGS += -I$(srctree)/scripts/include/
HOSTLDLIBS_mxsimage = `pkg-config --libs openssl`
HOSTCFLAGS_omap3-usb-loader.o = `pkg-config --cflags libusb-1.0`
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 75e1734f79..fc5fe3d7e8 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -512,6 +512,9 @@ quiet_cmd_cboot_bct = BCT $@
$(obj)/%.bct: $(obj)/%.bct.cfg
$(call cmd,cboot_bct)
+quiet_cmd_stm32_image = STM32-IMG $@
+ cmd_stm32_image = $(objtree)/scripts/stm32image $(OPTS_$(@F)) -i $< -o $@
+
quiet_cmd_b64dec = B64DEC $@
cmd_b64dec = base64 -d $< > $@
diff --git a/scripts/stm32image.c b/scripts/stm32image.c
new file mode 100644
index 0000000000..c33bcca0d8
--- /dev/null
+++ b/scripts/stm32image.c
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ * Copyright (C) 2019, Pengutronix
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdint.h>
+#include <getopt.h>
+#include "compiler.h"
+
+#ifndef MAP_POPULATE
+#define MAP_POPULATE 0
+#endif
+
+/* magic ='S' 'T' 'M' 0x32 */
+#define HEADER_MAGIC htobe32(0x53544D32)
+#define VER_MAJOR_IDX 2
+#define VER_MINOR_IDX 1
+#define VER_VARIANT_IDX 0
+/* default option : bit0 => no signature */
+#define HEADER_DEFAULT_OPTION htole32(0x00000001)
+/* default binary type for barebox */
+#define HEADER_TYPE_BAREBOX htole32(0x00000000)
+#define HEADER_LENGTH 0x100
+
+#define FSBL_LOADADDR 0x2ffc2400
+#define FSBL_ENTRYPOINT (FSBL_LOADADDR + HEADER_LENGTH)
+#define MAX_FSBL_PAYLOAD_SIZE (247 * 1024)
+
+struct __attribute((packed)) stm32_header {
+ uint32_t magic_number;
+ uint32_t image_signature[64 / 4];
+ 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;
+ uint32_t ecdsa_public_key[64 / 4];
+ uint32_t padding[83 / 4];
+ uint32_t binary_type;
+};
+
+static struct stm32_header stm32image_header;
+
+static const char *infile;
+static const char *outfile;
+static int in_fd;
+static int out_fd;
+static uint32_t loadaddr;
+static uint32_t entrypoint;
+static uint32_t pbl_size;
+static uint32_t version = 0x01;
+
+static void stm32image_print_header(void)
+{
+ printf("Image Type : STMicroelectronics STM32 V%d.%d\n",
+ stm32image_header.header_version[VER_MAJOR_IDX],
+ stm32image_header.header_version[VER_MINOR_IDX]);
+ printf("Image Size : %u bytes\n",
+ le32toh(stm32image_header.image_length));
+ printf("Image Load : 0x%08x\n",
+ le32toh(stm32image_header.load_address));
+ printf("Entry Point : 0x%08x\n",
+ le32toh(stm32image_header.image_entry_point));
+ printf("Checksum : 0x%08x\n",
+ le32toh(stm32image_header.image_checksum));
+ printf("Option : 0x%08x\n",
+ le32toh(stm32image_header.option_flags));
+ printf("BinaryType : 0x%08x\n",
+ le32toh(stm32image_header.binary_type));
+}
+
+static uint32_t stm32image_checksum(void)
+{
+ uint32_t csum = 0;
+ uint32_t len = pbl_size;
+ uint8_t *p;
+
+ p = mmap(NULL, len, PROT_READ, MAP_PRIVATE | MAP_POPULATE, in_fd, 0);
+ if (p == MAP_FAILED) {
+ perror("mmap");
+ exit(EXIT_FAILURE);
+ }
+
+ for (; len > 0; len--)
+ csum += *p++;
+
+ munmap(p, len);
+
+ return csum;
+}
+
+static void stm32image_set_header(void)
+{
+
+ memset(&stm32image_header, 0, sizeof(struct stm32_header));
+
+ /* set default values */
+ stm32image_header.magic_number = HEADER_MAGIC;
+ stm32image_header.header_version[VER_MAJOR_IDX] = version;
+ stm32image_header.option_flags = HEADER_DEFAULT_OPTION;
+ stm32image_header.ecdsa_algorithm = 1;
+ /* used to specify the 2nd-stage barebox address within dram */
+ stm32image_header.load_address = loadaddr;
+ stm32image_header.binary_type = HEADER_TYPE_BAREBOX;
+
+ stm32image_header.image_entry_point = htole32(entrypoint);
+ stm32image_header.image_length = htole32(pbl_size);
+ stm32image_header.image_checksum = stm32image_checksum();
+}
+
+static void stm32image_check_params(void)
+{
+ off_t ret;
+
+ in_fd = open(infile, O_RDONLY);
+ if (in_fd < 0) {
+ fprintf(stderr, "Error: Cannot open %s for reading: %s\n", infile,
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if (!pbl_size) {
+ pbl_size = lseek(in_fd, 0, SEEK_END);
+ if (pbl_size == (uint32_t)-1) {
+ fprintf(stderr, "Cannot seek to end\n");
+ exit(EXIT_FAILURE);
+ }
+
+ ret = lseek(in_fd, 0, SEEK_SET);
+ if (ret == (off_t)-1) {
+ fprintf(stderr, "Cannot seek to start\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ out_fd = creat(outfile, 0644);
+ if (out_fd < 0) {
+ fprintf(stderr, "Cannot open %s for writing: %s\n",
+ outfile, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if (loadaddr < 0xc0000000) {
+ fprintf(stderr, "Error: loadaddr must be within the DDR memory space\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+static void copy_fd(int in, int out)
+{
+ int bs = 4096;
+ void *buf = malloc(bs);
+
+ if (!buf)
+ exit(EXIT_FAILURE);
+
+ while (1) {
+ int now, wr;
+
+ now = read(in, buf, bs);
+ if (now < 0) {
+ fprintf(stderr, "read failed with %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if (!now)
+ break;
+
+ wr = write(out, buf, now);
+ if (wr < 0) {
+ fprintf(stderr, "write failed with %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if (wr != now) {
+ fprintf(stderr, "short write\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ free(buf);
+}
+
+int main(int argc, char *argv[])
+{
+ const char *verbose;
+ int opt, ret;
+ off_t pos;
+ entrypoint = FSBL_ENTRYPOINT;
+
+ while ((opt = getopt(argc, argv, "i:o:a:e:s:v:h")) != -1) {
+ switch (opt) {
+ case 'i':
+ infile = optarg;
+ break;
+ case 'o':
+ outfile = optarg;
+ break;
+ case 'a':
+ loadaddr = strtol(optarg, NULL, 16);
+ break;
+ case 'e':
+ entrypoint = strtol(optarg, NULL, 16);
+ break;
+ case 's':
+ pbl_size = strtol(optarg, NULL, 16);
+ break;
+ case 'v':
+ version = strtol(optarg, NULL, 16);
+ break;
+ case 'h':
+ printf("%s [-i inputfile] [-o outputfile] [-a loadaddr] [-s pblimage size in byte]\n", argv[0]);
+ exit(EXIT_SUCCESS);
+ default:
+ fprintf(stderr, "Unknown option: -%c\n", opt);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (!infile) {
+ fprintf(stderr, "No infile given\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (!outfile) {
+ fprintf(stderr, "No outfile given\n");
+ exit(EXIT_FAILURE);
+ }
+
+ stm32image_check_params();
+ stm32image_set_header();
+
+ ret = write(out_fd, (const void *)&stm32image_header, sizeof(struct stm32_header));
+ if (ret != 0x100) {
+ fprintf(stderr, "Error: write on %s: %s\n", outfile,
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ verbose = getenv("V");
+ if (verbose && !strcmp(verbose, "1"))
+ stm32image_print_header();
+
+ ret = ftruncate(out_fd, HEADER_LENGTH);
+ if (ret) {
+ fprintf(stderr, "Cannot truncate\n");
+ exit(EXIT_FAILURE);
+ }
+
+ pos = lseek(out_fd, HEADER_LENGTH, SEEK_SET);
+ if (pos == (off_t)-1) {
+ fprintf(stderr, "Cannot lseek 1\n");
+ exit(EXIT_FAILURE);
+ }
+
+ pos = lseek(in_fd, 0, SEEK_SET);
+ if (pos == (off_t)-1) {
+ fprintf(stderr, "Cannot lseek 2\n");
+ exit(EXIT_FAILURE);
+ }
+
+ copy_fd(in_fd, out_fd);
+
+ close(in_fd);
+ close(out_fd);
+
+ exit(EXIT_SUCCESS);
+}