[uboot] create uboot from github:
repo: https://github.com/u-boot/u-boot commit: d80bb749fab53da72c4a0e09b8c2d2aaa3103c91 Change-Id: Ie6434426e1ec15bc08bb1832798e371f3fd5fb29
This commit is contained in:
34
u-boot-2021.10/arch/arm/mach-stm32mp/cmd_stm32prog/Kconfig
Normal file
34
u-boot-2021.10/arch/arm/mach-stm32mp/cmd_stm32prog/Kconfig
Normal file
@ -0,0 +1,34 @@
|
||||
|
||||
config CMD_STM32PROG
|
||||
bool "command stm32prog for STM32CudeProgrammer"
|
||||
select DFU
|
||||
select DFU_RAM
|
||||
select DFU_VIRT
|
||||
select PARTITION_TYPE_GUID
|
||||
imply CMD_GPT if MMC
|
||||
imply CMD_MTD if MTD
|
||||
imply DFU_MMC if MMC
|
||||
imply DFU_MTD if MTD
|
||||
help
|
||||
activate a specific command stm32prog for STM32MP soc family
|
||||
witch update the device with the tools STM32CubeProgrammer
|
||||
NB: access to not volatile memory (NOR/NAND/SD/eMMC) is based
|
||||
on U-Boot DFU framework
|
||||
|
||||
config CMD_STM32PROG_USB
|
||||
bool "support stm32prog over USB"
|
||||
depends on CMD_STM32PROG
|
||||
default y
|
||||
help
|
||||
activate the command "stm32prog usb" for STM32MP soc family
|
||||
witch update the device with the tools STM32CubeProgrammer,
|
||||
using USB with DFU protocol
|
||||
|
||||
config CMD_STM32PROG_SERIAL
|
||||
bool "support stm32prog over UART"
|
||||
depends on CMD_STM32PROG
|
||||
default y
|
||||
help
|
||||
activate the command "stm32prog serial" for STM32MP soc family
|
||||
with the tools STM32CubeProgrammer using U-Boot serial device
|
||||
and UART protocol.
|
||||
@ -0,0 +1,9 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Copyright (C) 2020, STMicroelectronics - All Rights Reserved
|
||||
#
|
||||
|
||||
obj-$(CONFIG_CMD_STM32PROG) += cmd_stm32prog.o
|
||||
obj-$(CONFIG_CMD_STM32PROG) += stm32prog.o
|
||||
obj-$(CONFIG_CMD_STM32PROG_SERIAL) += stm32prog_serial.o
|
||||
obj-$(CONFIG_CMD_STM32PROG_USB) += stm32prog_usb.o
|
||||
@ -0,0 +1,204 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2020, STMicroelectronics - All Rights Reserved
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <dfu.h>
|
||||
#include <image.h>
|
||||
#include <asm/arch/stm32prog.h>
|
||||
#include "stm32prog.h"
|
||||
|
||||
struct stm32prog_data *stm32prog_data;
|
||||
|
||||
static void enable_vidconsole(void)
|
||||
{
|
||||
char *stdname;
|
||||
char buf[64];
|
||||
|
||||
stdname = env_get("stdout");
|
||||
if (!stdname || !strstr(stdname, "vidconsole")) {
|
||||
if (!stdname)
|
||||
snprintf(buf, sizeof(buf), "serial,vidconsole");
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "%s,vidconsole", stdname);
|
||||
env_set("stdout", buf);
|
||||
}
|
||||
|
||||
stdname = env_get("stderr");
|
||||
if (!stdname || !strstr(stdname, "vidconsole")) {
|
||||
if (!stdname)
|
||||
snprintf(buf, sizeof(buf), "serial,vidconsole");
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "%s,vidconsole", stdname);
|
||||
env_set("stderr", buf);
|
||||
}
|
||||
}
|
||||
|
||||
static int do_stm32prog(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
ulong addr, size;
|
||||
int dev, ret;
|
||||
enum stm32prog_link_t link = LINK_UNDEFINED;
|
||||
bool reset = false;
|
||||
struct image_header_s header;
|
||||
struct stm32prog_data *data;
|
||||
|
||||
if (argc < 3 || argc > 5)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
if (IS_ENABLED(CONFIG_CMD_STM32PROG_USB) && !strcmp(argv[1], "usb"))
|
||||
link = LINK_USB;
|
||||
else if (IS_ENABLED(CONFIG_CMD_STM32PROG_SERIAL) && !strcmp(argv[1], "serial"))
|
||||
link = LINK_SERIAL;
|
||||
|
||||
if (link == LINK_UNDEFINED) {
|
||||
log_err("not supported link=%s\n", argv[1]);
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
dev = (int)dectoul(argv[2], NULL);
|
||||
|
||||
addr = STM32_DDR_BASE;
|
||||
size = 0;
|
||||
if (argc > 3) {
|
||||
addr = hextoul(argv[3], NULL);
|
||||
if (!addr)
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
if (argc > 4)
|
||||
size = hextoul(argv[4], NULL);
|
||||
|
||||
/* check STM32IMAGE presence */
|
||||
if (size == 0) {
|
||||
stm32prog_header_check((struct raw_header_s *)addr, &header);
|
||||
if (header.type == HEADER_STM32IMAGE) {
|
||||
size = header.image_length + BL_HEADER_SIZE;
|
||||
|
||||
#if defined(CONFIG_LEGACY_IMAGE_FORMAT)
|
||||
/* uImage detected in STM32IMAGE, execute the script */
|
||||
if (IMAGE_FORMAT_LEGACY ==
|
||||
genimg_get_format((void *)(addr + BL_HEADER_SIZE)))
|
||||
return image_source_script(addr + BL_HEADER_SIZE, "script@1");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_DM_VIDEO))
|
||||
enable_vidconsole();
|
||||
|
||||
data = (struct stm32prog_data *)malloc(sizeof(*data));
|
||||
|
||||
if (!data) {
|
||||
log_err("Alloc failed.");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
stm32prog_data = data;
|
||||
|
||||
ret = stm32prog_init(data, addr, size);
|
||||
if (ret)
|
||||
log_debug("Invalid or missing layout file at 0x%lx.\n", addr);
|
||||
|
||||
/* prepare DFU for device read/write */
|
||||
ret = stm32prog_dfu_init(data);
|
||||
if (ret)
|
||||
goto cleanup;
|
||||
|
||||
switch (link) {
|
||||
case LINK_SERIAL:
|
||||
ret = stm32prog_serial_init(data, dev);
|
||||
if (ret)
|
||||
goto cleanup;
|
||||
reset = stm32prog_serial_loop(data);
|
||||
break;
|
||||
case LINK_USB:
|
||||
reset = stm32prog_usb_loop(data, dev);
|
||||
break;
|
||||
default:
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
stm32prog_clean(data);
|
||||
free(stm32prog_data);
|
||||
stm32prog_data = NULL;
|
||||
|
||||
puts("Download done\n");
|
||||
|
||||
if (data->uimage) {
|
||||
char boot_addr_start[20];
|
||||
char dtb_addr[20];
|
||||
char initrd_addr[40];
|
||||
char *bootm_argv[5] = {
|
||||
"bootm", boot_addr_start, "-", dtb_addr, NULL
|
||||
};
|
||||
u32 uimage = data->uimage;
|
||||
u32 dtb = data->dtb;
|
||||
u32 initrd = data->initrd;
|
||||
|
||||
if (!dtb)
|
||||
bootm_argv[3] = env_get("fdtcontroladdr");
|
||||
else
|
||||
snprintf(dtb_addr, sizeof(dtb_addr) - 1,
|
||||
"0x%x", dtb);
|
||||
|
||||
snprintf(boot_addr_start, sizeof(boot_addr_start) - 1,
|
||||
"0x%x", uimage);
|
||||
|
||||
if (initrd) {
|
||||
snprintf(initrd_addr, sizeof(initrd_addr) - 1, "0x%x:0x%x",
|
||||
initrd, data->initrd_size);
|
||||
bootm_argv[2] = initrd_addr;
|
||||
}
|
||||
|
||||
printf("Booting kernel at %s %s %s...\n\n\n",
|
||||
boot_addr_start, bootm_argv[2], bootm_argv[3]);
|
||||
/* Try bootm for legacy and FIT format image */
|
||||
if (genimg_get_format((void *)uimage) != IMAGE_FORMAT_INVALID)
|
||||
do_bootm(cmdtp, 0, 4, bootm_argv);
|
||||
else if (CONFIG_IS_ENABLED(CMD_BOOTZ))
|
||||
do_bootz(cmdtp, 0, 4, bootm_argv);
|
||||
}
|
||||
|
||||
if (reset) {
|
||||
puts("Reset...\n");
|
||||
run_command("reset", 0);
|
||||
}
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
|
||||
cleanup:
|
||||
stm32prog_clean(data);
|
||||
free(stm32prog_data);
|
||||
stm32prog_data = NULL;
|
||||
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(stm32prog, 5, 0, do_stm32prog,
|
||||
"start communication with tools STM32Cubeprogrammer",
|
||||
"<link> <dev> [<addr>] [<size>]\n"
|
||||
" <link> = serial|usb\n"
|
||||
" <dev> = device instance\n"
|
||||
" <addr> = address of flashlayout\n"
|
||||
" <size> = size of flashlayout (optional for image with STM32 header)\n"
|
||||
);
|
||||
|
||||
#ifdef CONFIG_STM32MP15x_STM32IMAGE
|
||||
bool stm32prog_get_tee_partitions(void)
|
||||
{
|
||||
if (stm32prog_data)
|
||||
return stm32prog_data->tee_detected;
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool stm32prog_get_fsbl_nor(void)
|
||||
{
|
||||
if (stm32prog_data)
|
||||
return stm32prog_data->fsbl_nor_detected;
|
||||
|
||||
return false;
|
||||
}
|
||||
1803
u-boot-2021.10/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
Normal file
1803
u-boot-2021.10/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
Normal file
File diff suppressed because it is too large
Load Diff
212
u-boot-2021.10/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
Normal file
212
u-boot-2021.10/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
Normal file
@ -0,0 +1,212 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2020, STMicroelectronics - All Rights Reserved
|
||||
*/
|
||||
|
||||
#ifndef _STM32PROG_H_
|
||||
#define _STM32PROG_H_
|
||||
|
||||
/* - phase defines ------------------------------------------------*/
|
||||
#define PHASE_FLASHLAYOUT 0x00
|
||||
#define PHASE_FIRST_USER 0x10
|
||||
#define PHASE_LAST_USER 0xF0
|
||||
#define PHASE_CMD 0xF1
|
||||
#define PHASE_OTP 0xF2
|
||||
#define PHASE_PMIC 0xF4
|
||||
#define PHASE_END 0xFE
|
||||
#define PHASE_RESET 0xFF
|
||||
#define PHASE_DO_RESET 0x1FF
|
||||
|
||||
#define DEFAULT_ADDRESS 0xFFFFFFFF
|
||||
|
||||
#define CMD_SIZE 512
|
||||
#define OTP_SIZE 1024
|
||||
#define PMIC_SIZE 8
|
||||
|
||||
enum stm32prog_target {
|
||||
STM32PROG_NONE,
|
||||
STM32PROG_MMC,
|
||||
STM32PROG_NAND,
|
||||
STM32PROG_NOR,
|
||||
STM32PROG_SPI_NAND,
|
||||
STM32PROG_RAM
|
||||
};
|
||||
|
||||
enum stm32prog_link_t {
|
||||
LINK_SERIAL,
|
||||
LINK_USB,
|
||||
LINK_UNDEFINED,
|
||||
};
|
||||
|
||||
enum stm32prog_header_t {
|
||||
HEADER_NONE,
|
||||
HEADER_STM32IMAGE,
|
||||
HEADER_FIP,
|
||||
};
|
||||
|
||||
struct image_header_s {
|
||||
enum stm32prog_header_t type;
|
||||
u32 image_checksum;
|
||||
u32 image_length;
|
||||
};
|
||||
|
||||
struct raw_header_s {
|
||||
u32 magic_number;
|
||||
u32 image_signature[64 / 4];
|
||||
u32 image_checksum;
|
||||
u32 header_version;
|
||||
u32 image_length;
|
||||
u32 image_entry_point;
|
||||
u32 reserved1;
|
||||
u32 load_address;
|
||||
u32 reserved2;
|
||||
u32 version_number;
|
||||
u32 option_flags;
|
||||
u32 ecdsa_algorithm;
|
||||
u32 ecdsa_public_key[64 / 4];
|
||||
u32 padding[83 / 4];
|
||||
u32 binary_type;
|
||||
};
|
||||
|
||||
#define BL_HEADER_SIZE sizeof(struct raw_header_s)
|
||||
|
||||
/* partition type in flashlayout file */
|
||||
enum stm32prog_part_type {
|
||||
PART_BINARY,
|
||||
PART_SYSTEM,
|
||||
PART_FILESYSTEM,
|
||||
RAW_IMAGE
|
||||
};
|
||||
|
||||
/* device information */
|
||||
struct stm32prog_dev_t {
|
||||
enum stm32prog_target target;
|
||||
char dev_id;
|
||||
u32 erase_size;
|
||||
struct mmc *mmc;
|
||||
struct mtd_info *mtd;
|
||||
/* list of partition for this device / ordered in offset */
|
||||
struct list_head part_list;
|
||||
bool full_update;
|
||||
};
|
||||
|
||||
/* partition information build from FlashLayout and device */
|
||||
struct stm32prog_part_t {
|
||||
/* FlashLayout information */
|
||||
int option;
|
||||
int id;
|
||||
enum stm32prog_part_type part_type;
|
||||
enum stm32prog_target target;
|
||||
char dev_id;
|
||||
|
||||
/* partition name
|
||||
* (16 char in gpt, + 1 for null terminated string
|
||||
*/
|
||||
char name[16 + 1];
|
||||
u64 addr;
|
||||
u64 size;
|
||||
enum stm32prog_part_type bin_nb; /* SSBL repeatition */
|
||||
|
||||
/* information on associated device */
|
||||
struct stm32prog_dev_t *dev; /* pointer to device */
|
||||
s16 part_id; /* partition id in device */
|
||||
int alt_id; /* alt id in usb/dfu */
|
||||
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
#define STM32PROG_MAX_DEV 5
|
||||
struct stm32prog_data {
|
||||
/* Layout information */
|
||||
int dev_nb; /* device number*/
|
||||
struct stm32prog_dev_t dev[STM32PROG_MAX_DEV]; /* array of device */
|
||||
int part_nb; /* nb of partition */
|
||||
struct stm32prog_part_t *part_array; /* array of partition */
|
||||
#ifdef CONFIG_STM32MP15x_STM32IMAGE
|
||||
bool tee_detected;
|
||||
#endif
|
||||
bool fsbl_nor_detected;
|
||||
|
||||
/* command internal information */
|
||||
unsigned int phase;
|
||||
u32 offset;
|
||||
char error[255];
|
||||
struct stm32prog_part_t *cur_part;
|
||||
u32 *otp_part;
|
||||
u8 pmic_part[PMIC_SIZE];
|
||||
|
||||
/* SERIAL information */
|
||||
u32 cursor;
|
||||
u32 packet_number;
|
||||
u8 *buffer; /* size = USART_RAM_BUFFER_SIZE*/
|
||||
int dfu_seq;
|
||||
u8 read_phase;
|
||||
|
||||
/* bootm information */
|
||||
u32 uimage;
|
||||
u32 dtb;
|
||||
u32 initrd;
|
||||
u32 initrd_size;
|
||||
};
|
||||
|
||||
extern struct stm32prog_data *stm32prog_data;
|
||||
|
||||
/* OTP access */
|
||||
int stm32prog_otp_write(struct stm32prog_data *data, u32 offset,
|
||||
u8 *buffer, long *size);
|
||||
int stm32prog_otp_read(struct stm32prog_data *data, u32 offset,
|
||||
u8 *buffer, long *size);
|
||||
int stm32prog_otp_start(struct stm32prog_data *data);
|
||||
|
||||
/* PMIC access */
|
||||
int stm32prog_pmic_write(struct stm32prog_data *data, u32 offset,
|
||||
u8 *buffer, long *size);
|
||||
int stm32prog_pmic_read(struct stm32prog_data *data, u32 offset,
|
||||
u8 *buffer, long *size);
|
||||
int stm32prog_pmic_start(struct stm32prog_data *data);
|
||||
|
||||
/* generic part*/
|
||||
void stm32prog_header_check(struct raw_header_s *raw_header,
|
||||
struct image_header_s *header);
|
||||
int stm32prog_dfu_init(struct stm32prog_data *data);
|
||||
void stm32prog_next_phase(struct stm32prog_data *data);
|
||||
void stm32prog_do_reset(struct stm32prog_data *data);
|
||||
|
||||
char *stm32prog_get_error(struct stm32prog_data *data);
|
||||
|
||||
#define stm32prog_err(args...) {\
|
||||
if (data->phase != PHASE_RESET) { \
|
||||
sprintf(data->error, args); \
|
||||
data->phase = PHASE_RESET; \
|
||||
log_err("Error: %s\n", data->error); } \
|
||||
}
|
||||
|
||||
/* Main function */
|
||||
int stm32prog_init(struct stm32prog_data *data, ulong addr, ulong size);
|
||||
void stm32prog_clean(struct stm32prog_data *data);
|
||||
|
||||
#ifdef CONFIG_CMD_STM32PROG_SERIAL
|
||||
int stm32prog_serial_init(struct stm32prog_data *data, int link_dev);
|
||||
bool stm32prog_serial_loop(struct stm32prog_data *data);
|
||||
#else
|
||||
static inline int stm32prog_serial_init(struct stm32prog_data *data, int link_dev)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline bool stm32prog_serial_loop(struct stm32prog_data *data)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CMD_STM32PROG_USB
|
||||
bool stm32prog_usb_loop(struct stm32prog_data *data, int dev);
|
||||
#else
|
||||
static inline bool stm32prog_usb_loop(struct stm32prog_data *data, int dev)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,866 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2020, STMicroelectronics - All Rights Reserved
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <console.h>
|
||||
#include <dm.h>
|
||||
#include <dfu.h>
|
||||
#include <malloc.h>
|
||||
#include <serial.h>
|
||||
#include <watchdog.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
#include <dm/lists.h>
|
||||
#include <dm/device-internal.h>
|
||||
#include <linux/delay.h>
|
||||
#include <asm/global_data.h>
|
||||
#include "stm32prog.h"
|
||||
|
||||
/* - configuration part -----------------------------*/
|
||||
#define USART_BL_VERSION 0x40 /* USART bootloader version V4.0*/
|
||||
#define UBOOT_BL_VERSION 0x03 /* bootloader version V0.3*/
|
||||
|
||||
#define USART_RAM_BUFFER_SIZE 256 /* Size of USART_RAM_Buf buffer*/
|
||||
|
||||
/* - Commands -----------------------------*/
|
||||
#define GET_CMD_COMMAND 0x00 /* Get CMD command*/
|
||||
#define GET_VER_COMMAND 0x01 /* Get Version command*/
|
||||
#define GET_ID_COMMAND 0x02 /* Get ID command*/
|
||||
#define GET_PHASE_COMMAND 0x03 /* Get Phase command*/
|
||||
#define RM_COMMAND 0x11 /* Read Memory command*/
|
||||
#define READ_PART_COMMAND 0x12 /* Read Partition command*/
|
||||
#define START_COMMAND 0x21 /* START command (Go)*/
|
||||
#define DOWNLOAD_COMMAND 0x31 /* Download command*/
|
||||
/* existing command for other STM32 but not used */
|
||||
/* ERASE 0x43 */
|
||||
/* EXTENDED_ERASE 0x44 */
|
||||
/* WRITE_UNPROTECTED 0x73 */
|
||||
/* READOUT_PROTECT 0x82 */
|
||||
/* READOUT_UNPROTECT 0x92 */
|
||||
|
||||
/* - miscellaneous defines ----------------------------------------*/
|
||||
#define INIT_BYTE 0x7F /*Init Byte ID*/
|
||||
#define ACK_BYTE 0x79 /*Acknowlede Byte ID*/
|
||||
#define NACK_BYTE 0x1F /*No Acknowlede Byte ID*/
|
||||
#define ABORT_BYTE 0x5F /*ABORT*/
|
||||
|
||||
struct udevice *down_serial_dev;
|
||||
|
||||
const u8 cmd_id[] = {
|
||||
GET_CMD_COMMAND,
|
||||
GET_VER_COMMAND,
|
||||
GET_ID_COMMAND,
|
||||
GET_PHASE_COMMAND,
|
||||
RM_COMMAND,
|
||||
READ_PART_COMMAND,
|
||||
START_COMMAND,
|
||||
DOWNLOAD_COMMAND
|
||||
};
|
||||
|
||||
#define NB_CMD sizeof(cmd_id)
|
||||
|
||||
/* with 115200 bauds, 20 ms allow to receive the 256 bytes buffer */
|
||||
#define TIMEOUT_SERIAL_BUFFER 30
|
||||
|
||||
/* DFU support for serial *********************************************/
|
||||
static struct dfu_entity *stm32prog_get_entity(struct stm32prog_data *data)
|
||||
{
|
||||
int alt_id;
|
||||
|
||||
if (!data->cur_part)
|
||||
if (data->phase == PHASE_FLASHLAYOUT)
|
||||
alt_id = 0;
|
||||
else
|
||||
return NULL;
|
||||
else
|
||||
alt_id = data->cur_part->alt_id;
|
||||
|
||||
return dfu_get_entity(alt_id);
|
||||
}
|
||||
|
||||
static int stm32prog_write(struct stm32prog_data *data, u8 *buffer,
|
||||
u32 buffer_size)
|
||||
{
|
||||
struct dfu_entity *dfu_entity;
|
||||
u8 ret = 0;
|
||||
|
||||
dfu_entity = stm32prog_get_entity(data);
|
||||
if (!dfu_entity)
|
||||
return -ENODEV;
|
||||
|
||||
ret = dfu_write(dfu_entity,
|
||||
buffer,
|
||||
buffer_size,
|
||||
data->dfu_seq);
|
||||
|
||||
if (ret) {
|
||||
stm32prog_err("DFU write failed [%d] cnt: %d",
|
||||
ret, data->dfu_seq);
|
||||
}
|
||||
data->dfu_seq++;
|
||||
/* handle rollover as in driver/dfu/dfu.c */
|
||||
data->dfu_seq &= 0xffff;
|
||||
if (buffer_size == 0)
|
||||
data->dfu_seq = 0; /* flush done */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stm32prog_read(struct stm32prog_data *data, u8 phase, u32 offset,
|
||||
u8 *buffer, u32 buffer_size)
|
||||
{
|
||||
struct dfu_entity *dfu_entity;
|
||||
struct stm32prog_part_t *part;
|
||||
u32 size;
|
||||
int ret, i;
|
||||
|
||||
if (data->dfu_seq) {
|
||||
stm32prog_err("DFU write pending for phase %d, seq %d",
|
||||
data->phase, data->dfu_seq);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (phase == PHASE_FLASHLAYOUT || phase > PHASE_LAST_USER) {
|
||||
stm32prog_err("read failed : phase %d is invalid", phase);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (data->read_phase <= PHASE_LAST_USER &&
|
||||
phase != data->read_phase) {
|
||||
/* clear previous read session */
|
||||
dfu_entity = dfu_get_entity(data->read_phase - 1);
|
||||
if (dfu_entity)
|
||||
dfu_transaction_cleanup(dfu_entity);
|
||||
}
|
||||
|
||||
dfu_entity = NULL;
|
||||
/* found partition for the expected phase */
|
||||
for (i = 0; i < data->part_nb; i++) {
|
||||
part = &data->part_array[i];
|
||||
if (part->id == phase)
|
||||
dfu_entity = dfu_get_entity(part->alt_id);
|
||||
}
|
||||
if (!dfu_entity) {
|
||||
stm32prog_err("read failed : phase %d is unknown", phase);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* clear pending read before to force offset */
|
||||
if (dfu_entity->inited &&
|
||||
(data->read_phase != phase || data->offset != offset))
|
||||
dfu_transaction_cleanup(dfu_entity);
|
||||
|
||||
/* initiate before to force offset */
|
||||
if (!dfu_entity->inited) {
|
||||
ret = dfu_transaction_initiate(dfu_entity, true);
|
||||
if (ret < 0) {
|
||||
stm32prog_err("DFU read init failed [%d] phase = %d offset = 0x%08x",
|
||||
ret, phase, offset);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
/* force new offset */
|
||||
if (dfu_entity->offset != offset)
|
||||
dfu_entity->offset = offset;
|
||||
data->offset = offset;
|
||||
data->read_phase = phase;
|
||||
log_debug("\nSTM32 download read %s offset=0x%x\n",
|
||||
dfu_entity->name, offset);
|
||||
ret = dfu_read(dfu_entity, buffer, buffer_size,
|
||||
dfu_entity->i_blk_seq_num);
|
||||
if (ret < 0) {
|
||||
stm32prog_err("DFU read failed [%d] phase = %d offset = 0x%08x",
|
||||
ret, phase, offset);
|
||||
return ret;
|
||||
}
|
||||
|
||||
size = ret;
|
||||
|
||||
if (size < buffer_size) {
|
||||
data->offset = 0;
|
||||
data->read_phase = PHASE_END;
|
||||
memset(buffer + size, 0, buffer_size - size);
|
||||
} else {
|
||||
data->offset += size;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* UART access ***************************************************/
|
||||
int stm32prog_serial_init(struct stm32prog_data *data, int link_dev)
|
||||
{
|
||||
struct udevice *dev = NULL;
|
||||
struct dm_serial_ops *ops;
|
||||
/* no parity, 8 bits, 1 stop */
|
||||
u32 serial_config = SERIAL_DEFAULT_CONFIG;
|
||||
|
||||
down_serial_dev = NULL;
|
||||
|
||||
if (uclass_get_device_by_seq(UCLASS_SERIAL, link_dev, &dev)) {
|
||||
log_err("serial %d device not found\n", link_dev);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
down_serial_dev = dev;
|
||||
|
||||
/* force silent console on uart only when used */
|
||||
if (gd->cur_serial_dev == down_serial_dev)
|
||||
gd->flags |= GD_FLG_DISABLE_CONSOLE | GD_FLG_SILENT;
|
||||
else
|
||||
gd->flags &= ~(GD_FLG_DISABLE_CONSOLE | GD_FLG_SILENT);
|
||||
|
||||
ops = serial_get_ops(down_serial_dev);
|
||||
|
||||
if (!ops) {
|
||||
log_err("serial %d = %s missing ops\n", link_dev, dev->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
if (!ops->setconfig) {
|
||||
log_err("serial %d = %s missing setconfig\n", link_dev, dev->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
clrsetbits_le32(&serial_config, SERIAL_PAR_MASK, SERIAL_PAR_EVEN);
|
||||
|
||||
data->buffer = memalign(CONFIG_SYS_CACHELINE_SIZE,
|
||||
USART_RAM_BUFFER_SIZE);
|
||||
|
||||
return ops->setconfig(down_serial_dev, serial_config);
|
||||
}
|
||||
|
||||
static void stm32prog_serial_flush(void)
|
||||
{
|
||||
struct dm_serial_ops *ops = serial_get_ops(down_serial_dev);
|
||||
int err;
|
||||
|
||||
do {
|
||||
err = ops->getc(down_serial_dev);
|
||||
} while (err != -EAGAIN);
|
||||
}
|
||||
|
||||
static int stm32prog_serial_getc_err(void)
|
||||
{
|
||||
struct dm_serial_ops *ops = serial_get_ops(down_serial_dev);
|
||||
int err;
|
||||
|
||||
do {
|
||||
err = ops->getc(down_serial_dev);
|
||||
if (err == -EAGAIN) {
|
||||
ctrlc();
|
||||
WATCHDOG_RESET();
|
||||
}
|
||||
} while ((err == -EAGAIN) && (!had_ctrlc()));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static u8 stm32prog_serial_getc(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = stm32prog_serial_getc_err();
|
||||
|
||||
return err >= 0 ? err : 0;
|
||||
}
|
||||
|
||||
static bool stm32prog_serial_get_buffer(u8 *buffer, u32 *count)
|
||||
{
|
||||
struct dm_serial_ops *ops = serial_get_ops(down_serial_dev);
|
||||
int err;
|
||||
ulong start = get_timer(0);
|
||||
|
||||
do {
|
||||
err = ops->getc(down_serial_dev);
|
||||
if (err >= 0) {
|
||||
*buffer++ = err;
|
||||
*count -= 1;
|
||||
} else if (err == -EAGAIN) {
|
||||
ctrlc();
|
||||
WATCHDOG_RESET();
|
||||
if (get_timer(start) > TIMEOUT_SERIAL_BUFFER) {
|
||||
err = -ETIMEDOUT;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} while (*count && !had_ctrlc());
|
||||
|
||||
return !!(err < 0);
|
||||
}
|
||||
|
||||
static void stm32prog_serial_putc(u8 w_byte)
|
||||
{
|
||||
struct dm_serial_ops *ops = serial_get_ops(down_serial_dev);
|
||||
int err;
|
||||
|
||||
do {
|
||||
err = ops->putc(down_serial_dev, w_byte);
|
||||
} while (err == -EAGAIN);
|
||||
}
|
||||
|
||||
/* Helper function ************************************************/
|
||||
static u8 stm32prog_start(struct stm32prog_data *data, u32 address)
|
||||
{
|
||||
u8 ret = 0;
|
||||
struct dfu_entity *dfu_entity;
|
||||
|
||||
if (address < 0x100) {
|
||||
if (address == PHASE_OTP)
|
||||
return stm32prog_otp_start(data);
|
||||
|
||||
if (address == PHASE_PMIC)
|
||||
return stm32prog_pmic_start(data);
|
||||
|
||||
if (address == PHASE_RESET || address == PHASE_END) {
|
||||
data->cur_part = NULL;
|
||||
data->dfu_seq = 0;
|
||||
data->phase = address;
|
||||
return 0;
|
||||
}
|
||||
if (address != data->phase) {
|
||||
stm32prog_err("invalid received phase id %d, current phase is %d",
|
||||
(u8)address, (u8)data->phase);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
/* check the last loaded partition */
|
||||
if (address == DEFAULT_ADDRESS || address == data->phase) {
|
||||
switch (data->phase) {
|
||||
case PHASE_END:
|
||||
case PHASE_RESET:
|
||||
case PHASE_DO_RESET:
|
||||
data->cur_part = NULL;
|
||||
data->phase = PHASE_DO_RESET;
|
||||
return 0;
|
||||
}
|
||||
dfu_entity = stm32prog_get_entity(data);
|
||||
if (!dfu_entity)
|
||||
return -ENODEV;
|
||||
|
||||
ret = dfu_flush(dfu_entity, NULL, 0, data->dfu_seq);
|
||||
if (ret) {
|
||||
stm32prog_err("DFU flush failed [%d]", ret);
|
||||
return ret;
|
||||
}
|
||||
data->dfu_seq = 0;
|
||||
|
||||
printf("\n received length = 0x%x\n", data->cursor);
|
||||
|
||||
/* update DFU with received flashlayout */
|
||||
if (data->phase == PHASE_FLASHLAYOUT)
|
||||
stm32prog_dfu_init(data);
|
||||
} else {
|
||||
void (*entry)(void) = (void *)address;
|
||||
|
||||
printf("## Starting application at 0x%x ...\n", address);
|
||||
(*entry)();
|
||||
printf("## Application terminated\n");
|
||||
ret = -ENOEXEC;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_address() - Get address if it is valid
|
||||
*
|
||||
* @tmp_xor: Current xor value to update
|
||||
* @return The address area
|
||||
*/
|
||||
static u32 get_address(u8 *tmp_xor)
|
||||
{
|
||||
u32 address = 0x0;
|
||||
u8 data;
|
||||
|
||||
data = stm32prog_serial_getc();
|
||||
*tmp_xor ^= data;
|
||||
address |= ((u32)data) << 24;
|
||||
|
||||
data = stm32prog_serial_getc();
|
||||
address |= ((u32)data) << 16;
|
||||
*tmp_xor ^= data;
|
||||
|
||||
data = stm32prog_serial_getc();
|
||||
address |= ((u32)data) << 8;
|
||||
*tmp_xor ^= data;
|
||||
|
||||
data = stm32prog_serial_getc();
|
||||
address |= ((u32)data);
|
||||
*tmp_xor ^= data;
|
||||
|
||||
return address;
|
||||
}
|
||||
|
||||
static void stm32prog_serial_result(u8 result)
|
||||
{
|
||||
/* always flush fifo before to send result */
|
||||
stm32prog_serial_flush();
|
||||
stm32prog_serial_putc(result);
|
||||
}
|
||||
|
||||
/* Command -----------------------------------------------*/
|
||||
/**
|
||||
* get_cmd_command() - Respond to Get command
|
||||
*
|
||||
* @data: Current command context
|
||||
*/
|
||||
static void get_cmd_command(struct stm32prog_data *data)
|
||||
{
|
||||
u32 counter = 0x0;
|
||||
|
||||
stm32prog_serial_putc(NB_CMD);
|
||||
stm32prog_serial_putc(USART_BL_VERSION);
|
||||
|
||||
for (counter = 0; counter < NB_CMD; counter++)
|
||||
stm32prog_serial_putc(cmd_id[counter]);
|
||||
|
||||
stm32prog_serial_result(ACK_BYTE);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_version_command() - Respond to Get Version command
|
||||
*
|
||||
* @data: Current command context
|
||||
*/
|
||||
static void get_version_command(struct stm32prog_data *data)
|
||||
{
|
||||
stm32prog_serial_putc(UBOOT_BL_VERSION);
|
||||
stm32prog_serial_result(ACK_BYTE);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_id_command() - Respond to Get ID command
|
||||
*
|
||||
* @data: Current command context
|
||||
*/
|
||||
static void get_id_command(struct stm32prog_data *data)
|
||||
{
|
||||
u32 cpu = get_cpu_dev();
|
||||
|
||||
/* Send Device IDCode */
|
||||
stm32prog_serial_putc(0x1);
|
||||
stm32prog_serial_putc((cpu >> 8) & 0xFF);
|
||||
stm32prog_serial_putc(cpu & 0xFF);
|
||||
stm32prog_serial_result(ACK_BYTE);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_phase_command() - Respond to Get phase
|
||||
*
|
||||
* @data: Current command context
|
||||
*/
|
||||
static void get_phase_command(struct stm32prog_data *data)
|
||||
{
|
||||
char *err_msg = NULL;
|
||||
u8 i, length = 0;
|
||||
u32 destination = DEFAULT_ADDRESS; /* destination address */
|
||||
int phase = data->phase;
|
||||
|
||||
if (phase == PHASE_RESET || phase == PHASE_DO_RESET) {
|
||||
err_msg = stm32prog_get_error(data);
|
||||
length = strlen(err_msg);
|
||||
}
|
||||
if (phase == PHASE_FLASHLAYOUT)
|
||||
destination = STM32_DDR_BASE;
|
||||
|
||||
stm32prog_serial_putc(length + 5); /* Total length */
|
||||
stm32prog_serial_putc(phase & 0xFF); /* partition ID */
|
||||
stm32prog_serial_putc(destination); /* byte 1 of address */
|
||||
stm32prog_serial_putc(destination >> 8); /* byte 2 of address */
|
||||
stm32prog_serial_putc(destination >> 16); /* byte 3 of address */
|
||||
stm32prog_serial_putc(destination >> 24); /* byte 4 of address */
|
||||
|
||||
stm32prog_serial_putc(length); /* Information length */
|
||||
for (i = 0; i < length; i++)
|
||||
stm32prog_serial_putc(err_msg[i]);
|
||||
stm32prog_serial_result(ACK_BYTE);
|
||||
|
||||
if (phase == PHASE_RESET)
|
||||
stm32prog_do_reset(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* read_memory_command() - Read data from memory
|
||||
*
|
||||
* @data: Current command context
|
||||
*/
|
||||
static void read_memory_command(struct stm32prog_data *data)
|
||||
{
|
||||
u32 address = 0x0;
|
||||
u8 rcv_data = 0x0, tmp_xor = 0x0;
|
||||
u32 counter = 0x0;
|
||||
|
||||
/* Read memory address */
|
||||
address = get_address(&tmp_xor);
|
||||
|
||||
/* If address memory is not received correctly */
|
||||
rcv_data = stm32prog_serial_getc();
|
||||
if (rcv_data != tmp_xor) {
|
||||
stm32prog_serial_result(NACK_BYTE);
|
||||
return;
|
||||
}
|
||||
|
||||
stm32prog_serial_result(ACK_BYTE);
|
||||
|
||||
/* Read the number of bytes to be received:
|
||||
* Max NbrOfData = Data + 1 = 256
|
||||
*/
|
||||
rcv_data = stm32prog_serial_getc();
|
||||
tmp_xor = ~rcv_data;
|
||||
if (stm32prog_serial_getc() != tmp_xor) {
|
||||
stm32prog_serial_result(NACK_BYTE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If checksum is correct send ACK */
|
||||
stm32prog_serial_result(ACK_BYTE);
|
||||
|
||||
/* Send data to the host:
|
||||
* Number of data to read = data + 1
|
||||
*/
|
||||
for (counter = (rcv_data + 1); counter != 0; counter--)
|
||||
stm32prog_serial_putc(*(u8 *)(address++));
|
||||
}
|
||||
|
||||
/**
|
||||
* start_command() - Respond to start command
|
||||
*
|
||||
* Jump to user application in RAM or partition check
|
||||
*
|
||||
* @data: Current command context
|
||||
*/
|
||||
static void start_command(struct stm32prog_data *data)
|
||||
{
|
||||
u32 address = 0;
|
||||
u8 tmp_xor = 0x0;
|
||||
u8 ret, rcv_data;
|
||||
|
||||
/* Read memory address */
|
||||
address = get_address(&tmp_xor);
|
||||
|
||||
/* If address memory is not received correctly */
|
||||
rcv_data = stm32prog_serial_getc();
|
||||
if (rcv_data != tmp_xor) {
|
||||
stm32prog_serial_result(NACK_BYTE);
|
||||
return;
|
||||
}
|
||||
/* validate partition */
|
||||
ret = stm32prog_start(data,
|
||||
address);
|
||||
|
||||
if (ret)
|
||||
stm32prog_serial_result(ABORT_BYTE);
|
||||
else
|
||||
stm32prog_serial_result(ACK_BYTE);
|
||||
}
|
||||
|
||||
/**
|
||||
* download_command() - Respond to download command
|
||||
*
|
||||
* Write data to not volatile memory, Flash
|
||||
*
|
||||
* @data: Current command context
|
||||
*/
|
||||
static void download_command(struct stm32prog_data *data)
|
||||
{
|
||||
u32 address = 0x0;
|
||||
u8 my_xor = 0x0;
|
||||
u8 rcv_xor;
|
||||
u32 counter = 0x0, codesize = 0x0;
|
||||
u8 *ramaddress = 0;
|
||||
u8 rcv_data = 0x0;
|
||||
u32 cursor = data->cursor;
|
||||
long size = 0;
|
||||
u8 operation;
|
||||
u32 packet_number;
|
||||
u32 result = ACK_BYTE;
|
||||
u8 ret;
|
||||
bool error;
|
||||
int rcv;
|
||||
|
||||
address = get_address(&my_xor);
|
||||
|
||||
/* If address memory is not received correctly */
|
||||
rcv_xor = stm32prog_serial_getc();
|
||||
if (rcv_xor != my_xor) {
|
||||
result = NACK_BYTE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* If address valid send ACK */
|
||||
stm32prog_serial_result(ACK_BYTE);
|
||||
|
||||
/* get packet number and operation type */
|
||||
operation = (u8)((u32)address >> 24);
|
||||
packet_number = ((u32)(((u32)address << 8))) >> 8;
|
||||
|
||||
switch (operation) {
|
||||
/* supported operation */
|
||||
case PHASE_FLASHLAYOUT:
|
||||
case PHASE_OTP:
|
||||
case PHASE_PMIC:
|
||||
break;
|
||||
default:
|
||||
result = NACK_BYTE;
|
||||
goto end;
|
||||
}
|
||||
/* check the packet number */
|
||||
if (packet_number == 0) {
|
||||
/* erase: re-initialize the image_header struct */
|
||||
data->packet_number = 0;
|
||||
cursor = 0;
|
||||
data->cursor = 0;
|
||||
/*idx = cursor;*/
|
||||
} else {
|
||||
data->packet_number++;
|
||||
}
|
||||
|
||||
/* Check with the number of current packet if the device receive
|
||||
* the true packet
|
||||
*/
|
||||
if (packet_number != data->packet_number) {
|
||||
data->packet_number--;
|
||||
result = NACK_BYTE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/*-- Read number of bytes to be written and data -----------*/
|
||||
|
||||
/* Read the number of bytes to be written:
|
||||
* Max NbrOfData = data + 1 <= 256
|
||||
*/
|
||||
rcv_data = stm32prog_serial_getc();
|
||||
|
||||
/* NbrOfData to write = data + 1 */
|
||||
codesize = rcv_data + 0x01;
|
||||
|
||||
if (codesize > USART_RAM_BUFFER_SIZE) {
|
||||
result = NACK_BYTE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Checksum Initialization */
|
||||
my_xor = rcv_data;
|
||||
|
||||
/* UART receive data and send to Buffer */
|
||||
counter = codesize;
|
||||
error = stm32prog_serial_get_buffer(data->buffer, &counter);
|
||||
|
||||
/* read checksum */
|
||||
if (!error) {
|
||||
rcv = stm32prog_serial_getc_err();
|
||||
error = !!(rcv < 0);
|
||||
rcv_xor = rcv;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
printf("transmission error on packet %d, byte %d\n",
|
||||
packet_number, codesize - counter);
|
||||
/* waiting end of packet before flush & NACK */
|
||||
mdelay(TIMEOUT_SERIAL_BUFFER);
|
||||
data->packet_number--;
|
||||
result = NACK_BYTE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Compute Checksum */
|
||||
ramaddress = data->buffer;
|
||||
for (counter = codesize; counter != 0; counter--)
|
||||
my_xor ^= *(ramaddress++);
|
||||
|
||||
/* If Checksum is incorrect */
|
||||
if (rcv_xor != my_xor) {
|
||||
printf("checksum error on packet %d\n",
|
||||
packet_number);
|
||||
/* wait to be sure that all data are received
|
||||
* in the FIFO before flush
|
||||
*/
|
||||
mdelay(TIMEOUT_SERIAL_BUFFER);
|
||||
data->packet_number--;
|
||||
result = NACK_BYTE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
switch (operation) {
|
||||
case PHASE_OTP:
|
||||
size = codesize;
|
||||
ret = stm32prog_otp_write(data, cursor, data->buffer, &size);
|
||||
break;
|
||||
|
||||
case PHASE_PMIC:
|
||||
size = codesize;
|
||||
ret = stm32prog_pmic_write(data, cursor, data->buffer, &size);
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = stm32prog_write(data, data->buffer, codesize);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
result = ABORT_BYTE;
|
||||
else
|
||||
/* Update current position in buffer */
|
||||
data->cursor += codesize;
|
||||
|
||||
end:
|
||||
stm32prog_serial_result(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* read_partition() - Respond to read command
|
||||
*
|
||||
* Read data from not volatile memory, Flash
|
||||
*
|
||||
* @data: Current command context
|
||||
*/
|
||||
static void read_partition_command(struct stm32prog_data *data)
|
||||
{
|
||||
u32 i, part_id, codesize, offset = 0, rcv_data;
|
||||
long size;
|
||||
u8 tmp_xor;
|
||||
int res;
|
||||
u8 buffer[256];
|
||||
|
||||
part_id = stm32prog_serial_getc();
|
||||
tmp_xor = part_id;
|
||||
|
||||
offset = get_address(&tmp_xor);
|
||||
|
||||
rcv_data = stm32prog_serial_getc();
|
||||
if (rcv_data != tmp_xor) {
|
||||
log_debug("1st checksum received = %x, computed %x\n",
|
||||
rcv_data, tmp_xor);
|
||||
goto error;
|
||||
}
|
||||
stm32prog_serial_putc(ACK_BYTE);
|
||||
|
||||
/* NbrOfData to read = data + 1 */
|
||||
rcv_data = stm32prog_serial_getc();
|
||||
codesize = rcv_data + 0x01;
|
||||
tmp_xor = rcv_data;
|
||||
|
||||
rcv_data = stm32prog_serial_getc();
|
||||
if ((rcv_data ^ tmp_xor) != 0xFF) {
|
||||
log_debug("2nd checksum received = %x, computed %x\n",
|
||||
rcv_data, tmp_xor);
|
||||
goto error;
|
||||
}
|
||||
|
||||
log_debug("%s : %x\n", __func__, part_id);
|
||||
rcv_data = 0;
|
||||
switch (part_id) {
|
||||
case PHASE_OTP:
|
||||
size = codesize;
|
||||
if (!stm32prog_otp_read(data, offset, buffer, &size))
|
||||
rcv_data = size;
|
||||
break;
|
||||
case PHASE_PMIC:
|
||||
size = codesize;
|
||||
if (!stm32prog_pmic_read(data, offset, buffer, &size))
|
||||
rcv_data = size;
|
||||
break;
|
||||
default:
|
||||
res = stm32prog_read(data, part_id, offset,
|
||||
buffer, codesize);
|
||||
if (res > 0)
|
||||
rcv_data = res;
|
||||
break;
|
||||
}
|
||||
if (rcv_data > 0) {
|
||||
stm32prog_serial_putc(ACK_BYTE);
|
||||
/*----------- Send data to the host -----------*/
|
||||
for (i = 0; i < rcv_data; i++)
|
||||
stm32prog_serial_putc(buffer[i]);
|
||||
/*----------- Send filler to the host -----------*/
|
||||
for (; i < codesize; i++)
|
||||
stm32prog_serial_putc(0x0);
|
||||
return;
|
||||
}
|
||||
stm32prog_serial_result(ABORT_BYTE);
|
||||
return;
|
||||
|
||||
error:
|
||||
stm32prog_serial_result(NACK_BYTE);
|
||||
}
|
||||
|
||||
/* MAIN function = SERIAL LOOP ***********************************************/
|
||||
|
||||
/**
|
||||
* stm32prog_serial_loop() - USART bootloader Loop routine
|
||||
*
|
||||
* @data: Current command context
|
||||
* @return true if reset is needed after loop
|
||||
*/
|
||||
bool stm32prog_serial_loop(struct stm32prog_data *data)
|
||||
{
|
||||
u32 counter = 0x0;
|
||||
u8 command = 0x0;
|
||||
u8 found;
|
||||
int phase = data->phase;
|
||||
|
||||
/* element of cmd_func need to aligned with cmd_id[]*/
|
||||
void (*cmd_func[NB_CMD])(struct stm32prog_data *) = {
|
||||
/* GET_CMD_COMMAND */ get_cmd_command,
|
||||
/* GET_VER_COMMAND */ get_version_command,
|
||||
/* GET_ID_COMMAND */ get_id_command,
|
||||
/* GET_PHASE_COMMAND */ get_phase_command,
|
||||
/* RM_COMMAND */ read_memory_command,
|
||||
/* READ_PART_COMMAND */ read_partition_command,
|
||||
/* START_COMMAND */ start_command,
|
||||
/* DOWNLOAD_COMMAND */ download_command
|
||||
};
|
||||
|
||||
/* flush and NACK pending command received during u-boot init
|
||||
* request command reemit
|
||||
*/
|
||||
stm32prog_serial_result(NACK_BYTE);
|
||||
|
||||
clear_ctrlc(); /* forget any previous Control C */
|
||||
while (!had_ctrlc()) {
|
||||
phase = data->phase;
|
||||
|
||||
if (phase == PHASE_DO_RESET)
|
||||
return true;
|
||||
|
||||
/* Get the user command: read first byte */
|
||||
command = stm32prog_serial_getc();
|
||||
|
||||
if (command == INIT_BYTE) {
|
||||
puts("\nConnected\n");
|
||||
stm32prog_serial_result(ACK_BYTE);
|
||||
continue;
|
||||
}
|
||||
|
||||
found = 0;
|
||||
for (counter = 0; counter < NB_CMD; counter++)
|
||||
if (cmd_id[counter] == command) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
if (found)
|
||||
if ((command ^ stm32prog_serial_getc()) != 0xFF)
|
||||
found = 0;
|
||||
if (!found) {
|
||||
/* wait to be sure that all data are received
|
||||
* in the FIFO before flush (CMD and XOR)
|
||||
*/
|
||||
mdelay(3);
|
||||
stm32prog_serial_result(NACK_BYTE);
|
||||
} else {
|
||||
stm32prog_serial_result(ACK_BYTE);
|
||||
cmd_func[counter](data);
|
||||
}
|
||||
WATCHDOG_RESET();
|
||||
}
|
||||
|
||||
/* clean device */
|
||||
if (gd->cur_serial_dev == down_serial_dev) {
|
||||
/* restore console on uart */
|
||||
gd->flags &= ~(GD_FLG_DISABLE_CONSOLE | GD_FLG_SILENT);
|
||||
}
|
||||
down_serial_dev = NULL;
|
||||
|
||||
return false; /* no reset after ctrlc */
|
||||
}
|
||||
@ -0,0 +1,229 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2020, STMicroelectronics - All Rights Reserved
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dfu.h>
|
||||
#include <g_dnl.h>
|
||||
#include <usb.h>
|
||||
#include <asm/arch/stm32prog.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
#include "stm32prog.h"
|
||||
|
||||
static int stm32prog_set_phase(struct stm32prog_data *data, u8 phase,
|
||||
u32 offset)
|
||||
{
|
||||
struct stm32prog_part_t *part;
|
||||
int i;
|
||||
|
||||
if (phase == data->phase) {
|
||||
data->offset = offset;
|
||||
data->dfu_seq = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* found partition for phase */
|
||||
for (i = 0; i < data->part_nb; i++) {
|
||||
part = &data->part_array[i];
|
||||
if (part->id == phase) {
|
||||
data->cur_part = part;
|
||||
data->phase = phase;
|
||||
data->offset = offset;
|
||||
data->dfu_seq = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int stm32prog_cmd_write(u64 offset, void *buf, long *len)
|
||||
{
|
||||
u8 phase;
|
||||
u32 address;
|
||||
u8 *pt = buf;
|
||||
void (*entry)(void);
|
||||
int ret;
|
||||
|
||||
if (*len < 5) {
|
||||
log_err("size not allowed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (offset) {
|
||||
log_err("invalid offset\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
phase = pt[0];
|
||||
address = (pt[1] << 24) | (pt[2] << 16) | (pt[3] << 8) | pt[4];
|
||||
if (phase == PHASE_RESET) {
|
||||
entry = (void *)address;
|
||||
printf("## Starting application at 0x%x ...\n", address);
|
||||
(*entry)();
|
||||
printf("## Application terminated\n");
|
||||
return 0;
|
||||
}
|
||||
/* set phase and offset */
|
||||
ret = stm32prog_set_phase(stm32prog_data, phase, address);
|
||||
if (ret)
|
||||
log_err("failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define PHASE_MIN_SIZE 9
|
||||
static int stm32prog_cmd_read(u64 offset, void *buf, long *len)
|
||||
{
|
||||
u32 destination = DEFAULT_ADDRESS; /* destination address */
|
||||
u32 dfu_offset;
|
||||
u8 *pt_buf = buf;
|
||||
int phase;
|
||||
char *err_msg;
|
||||
int length;
|
||||
|
||||
if (*len < PHASE_MIN_SIZE) {
|
||||
log_err("request exceeds allowed area\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (offset) {
|
||||
*len = 0; /* EOF for second request */
|
||||
return 0;
|
||||
}
|
||||
phase = stm32prog_data->phase;
|
||||
if (phase == PHASE_FLASHLAYOUT)
|
||||
destination = STM32_DDR_BASE;
|
||||
dfu_offset = stm32prog_data->offset;
|
||||
|
||||
/* mandatory header, size = PHASE_MIN_SIZE */
|
||||
*pt_buf++ = (u8)(phase & 0xFF);
|
||||
*pt_buf++ = (u8)(destination);
|
||||
*pt_buf++ = (u8)(destination >> 8);
|
||||
*pt_buf++ = (u8)(destination >> 16);
|
||||
*pt_buf++ = (u8)(destination >> 24);
|
||||
*pt_buf++ = (u8)(dfu_offset);
|
||||
*pt_buf++ = (u8)(dfu_offset >> 8);
|
||||
*pt_buf++ = (u8)(dfu_offset >> 16);
|
||||
*pt_buf++ = (u8)(dfu_offset >> 24);
|
||||
|
||||
if (phase == PHASE_RESET || phase == PHASE_DO_RESET) {
|
||||
err_msg = stm32prog_get_error(stm32prog_data);
|
||||
length = strlen(err_msg);
|
||||
if (length + PHASE_MIN_SIZE > *len)
|
||||
length = *len - PHASE_MIN_SIZE;
|
||||
|
||||
memcpy(pt_buf, err_msg, length);
|
||||
*len = PHASE_MIN_SIZE + length;
|
||||
stm32prog_do_reset(stm32prog_data);
|
||||
} else if (phase == PHASE_FLASHLAYOUT) {
|
||||
*pt_buf++ = stm32prog_data->part_nb ? 1 : 0;
|
||||
*len = PHASE_MIN_SIZE + 1;
|
||||
} else {
|
||||
*len = PHASE_MIN_SIZE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stm32prog_write_medium_virt(struct dfu_entity *dfu, u64 offset,
|
||||
void *buf, long *len)
|
||||
{
|
||||
if (dfu->dev_type != DFU_DEV_VIRT)
|
||||
return -EINVAL;
|
||||
|
||||
switch (dfu->data.virt.dev_num) {
|
||||
case PHASE_CMD:
|
||||
return stm32prog_cmd_write(offset, buf, len);
|
||||
|
||||
case PHASE_OTP:
|
||||
return stm32prog_otp_write(stm32prog_data, (u32)offset,
|
||||
buf, len);
|
||||
|
||||
case PHASE_PMIC:
|
||||
return stm32prog_pmic_write(stm32prog_data, (u32)offset,
|
||||
buf, len);
|
||||
}
|
||||
*len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stm32prog_read_medium_virt(struct dfu_entity *dfu, u64 offset,
|
||||
void *buf, long *len)
|
||||
{
|
||||
if (dfu->dev_type != DFU_DEV_VIRT)
|
||||
return -EINVAL;
|
||||
|
||||
switch (dfu->data.virt.dev_num) {
|
||||
case PHASE_CMD:
|
||||
return stm32prog_cmd_read(offset, buf, len);
|
||||
|
||||
case PHASE_OTP:
|
||||
return stm32prog_otp_read(stm32prog_data, (u32)offset,
|
||||
buf, len);
|
||||
|
||||
case PHASE_PMIC:
|
||||
return stm32prog_pmic_read(stm32prog_data, (u32)offset,
|
||||
buf, len);
|
||||
}
|
||||
*len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stm32prog_get_medium_size_virt(struct dfu_entity *dfu, u64 *size)
|
||||
{
|
||||
if (dfu->dev_type != DFU_DEV_VIRT) {
|
||||
*size = 0;
|
||||
log_debug("%s, invalid dev_type = %d\n",
|
||||
__func__, dfu->dev_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (dfu->data.virt.dev_num) {
|
||||
case PHASE_CMD:
|
||||
*size = CMD_SIZE;
|
||||
break;
|
||||
case PHASE_OTP:
|
||||
*size = OTP_SIZE;
|
||||
break;
|
||||
case PHASE_PMIC:
|
||||
*size = PMIC_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool stm32prog_usb_loop(struct stm32prog_data *data, int dev)
|
||||
{
|
||||
int ret;
|
||||
bool result;
|
||||
/* USB download gadget for STM32 Programmer */
|
||||
char product[128];
|
||||
char name[SOC_NAME_SIZE];
|
||||
|
||||
get_soc_name(name);
|
||||
snprintf(product, sizeof(product),
|
||||
"USB download gadget@Device ID /0x%03X, @Revision ID /0x%04X, @Name /%s,",
|
||||
get_cpu_dev(), get_cpu_rev(), name);
|
||||
g_dnl_set_product(product);
|
||||
|
||||
if (stm32prog_data->phase == PHASE_FLASHLAYOUT) {
|
||||
ret = run_usb_dnl_gadget(dev, "usb_dnl_dfu");
|
||||
if (ret || stm32prog_data->phase != PHASE_FLASHLAYOUT)
|
||||
return ret;
|
||||
/* prepare the second enumeration with the FlashLayout */
|
||||
stm32prog_dfu_init(data);
|
||||
}
|
||||
|
||||
ret = run_usb_dnl_gadget(dev, "usb_dnl_dfu");
|
||||
|
||||
result = !!(ret) || (stm32prog_data->phase == PHASE_DO_RESET);
|
||||
|
||||
g_dnl_set_product(NULL);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int g_dnl_get_board_bcd_device_number(int gcnum)
|
||||
{
|
||||
log_debug("%s\n", __func__);
|
||||
return 0x200;
|
||||
}
|
||||
Reference in New Issue
Block a user