From patchwork Wed Mar 18 08:24:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Delaunay X-Patchwork-Id: 243784 List-Id: U-Boot discussion From: patrick.delaunay at st.com (Patrick Delaunay) Date: Wed, 18 Mar 2020 09:24:59 +0100 Subject: [PATCH 14/18] stm32mp: stm32prog: add pmic NVM update support In-Reply-To: <20200318082503.8025-1-patrick.delaunay@st.com> References: <20200318082503.8025-1-patrick.delaunay@st.com> Message-ID: <20200318082503.8025-15-patrick.delaunay@st.com> Add a virtual partition to update the pmic non volatile memory. (on ST board, STPMIC1). Signed-off-by: Patrick Delaunay --- .../mach-stm32mp/cmd_stm32prog/stm32prog.c | 95 ++++++++++++++++++- .../mach-stm32mp/cmd_stm32prog/stm32prog.h | 10 ++ .../cmd_stm32prog/stm32prog_usb.c | 11 +++ 3 files changed, 115 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c index cd826dbb9c..d127afefaa 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -1107,7 +1108,7 @@ static int dfu_init_entities(struct stm32prog_data *data) struct dfu_entity *dfu; int alt_nb; - alt_nb = 2; /* number of virtual = CMD, OTP*/ + alt_nb = 3; /* number of virtual = CMD, OTP, PMIC*/ if (data->part_nb == 0) alt_nb++; /* +1 for FlashLayout */ else @@ -1158,6 +1159,9 @@ static int dfu_init_entities(struct stm32prog_data *data) if (!ret) ret = stm32prog_alt_add_virt(dfu, "OTP", PHASE_OTP, 512); + if (!ret && CONFIG_IS_ENABLED(DM_PMIC)) + ret = stm32prog_alt_add_virt(dfu, "PMIC", PHASE_PMIC, 8); + if (ret) stm32prog_err("dfu init failed: %d", ret); puts("done\n"); @@ -1285,6 +1289,93 @@ int stm32prog_otp_start(struct stm32prog_data *data) #endif } +int stm32prog_pmic_write(struct stm32prog_data *data, u32 offset, u8 *buffer, + long *size) +{ + pr_debug("%s: %x %lx\n", __func__, offset, *size); + + if (!offset) + memset(data->pmic_part, 0, PMIC_SIZE); + + if (offset + *size > PMIC_SIZE) + *size = PMIC_SIZE - offset; + + memcpy(&data->pmic_part[offset], buffer, *size); + + return 0; +} + +int stm32prog_pmic_read(struct stm32prog_data *data, u32 offset, u8 *buffer, + long *size) +{ + int result = 0, ret; + struct udevice *dev; + + if (!CONFIG_IS_ENABLED(PMIC_STPMIC1)) { + stm32prog_err("PMIC update not supported"); + + return -EOPNOTSUPP; + } + + pr_debug("%s: %x %lx\n", __func__, offset, *size); + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_GET_DRIVER(stpmic1_nvm), + &dev); + if (ret) + return ret; + + /* alway request PMIC for first packet */ + if (!offset) { + /* init struct with 0 */ + memset(data->pmic_part, 0, PMIC_SIZE); + + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_GET_DRIVER(stpmic1_nvm), + &dev); + if (ret) + return ret; + + ret = misc_read(dev, 0xF8, data->pmic_part, PMIC_SIZE); + if (ret < 0) { + result = ret; + goto end_pmic_read; + } + if (ret != PMIC_SIZE) { + result = -EACCES; + goto end_pmic_read; + } + } + + if (offset + *size > PMIC_SIZE) + *size = PMIC_SIZE - offset; + + memcpy(buffer, &data->pmic_part[offset], *size); + +end_pmic_read: + pr_debug("%s: result %i\n", __func__, result); + return result; +} + +int stm32prog_pmic_start(struct stm32prog_data *data) +{ + int ret; + struct udevice *dev; + + if (!CONFIG_IS_ENABLED(PMIC_STPMIC1)) { + stm32prog_err("PMIC update not supported"); + + return -EOPNOTSUPP; + } + + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_GET_DRIVER(stpmic1_nvm), + &dev); + if (ret) + return ret; + + return misc_write(dev, 0xF8, data->pmic_part, PMIC_SIZE); +} + /* copy FSBL on NAND to improve reliability on NAND */ static int stm32prog_copy_fsbl(struct stm32prog_part_t *part) { @@ -1585,6 +1676,8 @@ void dfu_flush_callback(struct dfu_entity *dfu) if (dfu->dev_type == DFU_DEV_VIRT) { if (dfu->data.virt.dev_num == PHASE_OTP) stm32prog_otp_start(stm32prog_data); + else if (dfu->data.virt.dev_num == PHASE_PMIC) + stm32prog_pmic_start(stm32prog_data); return; } diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h index 6024657433..83b27980f5 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h @@ -12,6 +12,7 @@ #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 @@ -19,6 +20,7 @@ #define DEFAULT_ADDRESS 0xFFFFFFFF #define OTP_SIZE 1024 +#define PMIC_SIZE 8 enum stm32prog_target { STM32PROG_NONE, @@ -120,6 +122,7 @@ struct stm32prog_data { char error[255]; struct stm32prog_part_t *cur_part; u32 *otp_part; + u8 pmic_part[PMIC_SIZE]; /* STM32 header information */ struct raw_header_s *header_data; @@ -135,6 +138,13 @@ 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*/ u8 stm32prog_header_check(struct raw_header_s *raw_header, struct image_header_s *header); diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c index 4a4b4d326b..34f27c074f 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c @@ -134,6 +134,10 @@ int stm32prog_write_medium_virt(struct dfu_entity *dfu, u64 offset, 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; @@ -152,6 +156,10 @@ int stm32prog_read_medium_virt(struct dfu_entity *dfu, u64 offset, 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; @@ -173,6 +181,9 @@ int stm32prog_get_medium_size_virt(struct dfu_entity *dfu, u64 *size) case PHASE_OTP: *size = OTP_SIZE; break; + case PHASE_PMIC: + *size = PMIC_SIZE; + break; } return 0;