Message ID | 20200318082503.8025-15-patrick.delaunay@st.com |
---|---|
State | Accepted |
Commit | 6ce1f4ad8d300272e7584a514d9be0c334754ff7 |
Delegated to: | Patrick Delaunay |
Headers | show |
Series | stm32mp1: add command stm32prog | expand |
Hi On 3/18/20 9:24 AM, Patrick Delaunay wrote: > Add a virtual partition to update the pmic non volatile memory. > (on ST board, STPMIC1). > > Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com> > --- > > .../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 <console.h> > #include <dfu.h> > #include <malloc.h> > +#include <misc.h> > #include <mmc.h> > #include <part.h> > #include <asm/arch/stm32mp1_smc.h> > @@ -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; Reviewed-by: Patrice Chotard <patrice.chotard@st.com> Thanks Patrice
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 <console.h> #include <dfu.h> #include <malloc.h> +#include <misc.h> #include <mmc.h> #include <part.h> #include <asm/arch/stm32mp1_smc.h> @@ -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;
Add a virtual partition to update the pmic non volatile memory. (on ST board, STPMIC1). Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com> --- .../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(-)