stpmic1: add NVM update support in fuse command
Add functions to read/update the non volatile memory of STPMIC1 (8 bytes-register at 0xF8 address) and allow access with fuse command (bank=1, word > 0xF8). For example: STM32MP> fuse read 1 0xf8 8 Reading bank 1: Word 0x000000f8: 000000ee 00000092 000000c0 00000002 Word 0x000000fc: 000000f2 00000080 00000002 00000033 Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
This commit is contained in:
parent
c8a6668cbd
commit
31e45a1a9e
@ -9,8 +9,10 @@
|
||||
#include <errno.h>
|
||||
#include <dm/device.h>
|
||||
#include <dm/uclass.h>
|
||||
#include <power/stpmic1.h>
|
||||
|
||||
#define STM32MP_OTP_BANK 0
|
||||
#define STM32MP_NVM_BANK 1
|
||||
|
||||
/*
|
||||
* The 'fuse' command API
|
||||
@ -34,6 +36,13 @@ int fuse_read(u32 bank, u32 word, u32 *val)
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_PMIC_STPMIC1
|
||||
case STM32MP_NVM_BANK:
|
||||
*val = 0;
|
||||
ret = stpmic1_shadow_read_byte(word, (u8 *)val);
|
||||
break;
|
||||
#endif /* CONFIG_PMIC_STPMIC1 */
|
||||
|
||||
default:
|
||||
printf("stm32mp %s: wrong value for bank %i\n", __func__, bank);
|
||||
ret = -EINVAL;
|
||||
@ -62,6 +71,12 @@ int fuse_prog(u32 bank, u32 word, u32 val)
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_PMIC_STPMIC1
|
||||
case STM32MP_NVM_BANK:
|
||||
ret = stpmic1_nvm_write_byte(word, (u8 *)&val);
|
||||
break;
|
||||
#endif /* CONFIG_PMIC_STPMIC1 */
|
||||
|
||||
default:
|
||||
printf("stm32mp %s: wrong value for bank %i\n", __func__, bank);
|
||||
ret = -EINVAL;
|
||||
@ -89,6 +104,13 @@ int fuse_sense(u32 bank, u32 word, u32 *val)
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_PMIC_STPMIC1
|
||||
case STM32MP_NVM_BANK:
|
||||
*val = 0;
|
||||
ret = stpmic1_nvm_read_byte(word, (u8 *)val);
|
||||
break;
|
||||
#endif /* CONFIG_PMIC_STPMIC1 */
|
||||
|
||||
default:
|
||||
printf("stm32mp %s: wrong value for bank %i\n", __func__, bank);
|
||||
ret = -EINVAL;
|
||||
@ -117,6 +139,12 @@ int fuse_override(u32 bank, u32 word, u32 val)
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_PMIC_STPMIC1
|
||||
case STM32MP_NVM_BANK:
|
||||
ret = stpmic1_shadow_write_byte(word, (u8 *)&val);
|
||||
break;
|
||||
#endif /* CONFIG_PMIC_STPMIC1 */
|
||||
|
||||
default:
|
||||
printf("stm32mp %s: wrong value for bank %i\n",
|
||||
__func__, bank);
|
||||
|
@ -15,6 +15,17 @@
|
||||
|
||||
#define STPMIC1_NUM_OF_REGS 0x100
|
||||
|
||||
#define STPMIC1_NVM_SIZE 8
|
||||
#define STPMIC1_NVM_POLL_TIMEOUT 100000
|
||||
#define STPMIC1_NVM_START_ADDRESS 0xf8
|
||||
|
||||
enum pmic_nvm_op {
|
||||
SHADOW_READ,
|
||||
SHADOW_WRITE,
|
||||
NVM_READ,
|
||||
NVM_WRITE,
|
||||
};
|
||||
|
||||
#if CONFIG_IS_ENABLED(DM_REGULATOR)
|
||||
static const struct pmic_child_info stpmic1_children_info[] = {
|
||||
{ .prefix = "ldo", .driver = "stpmic1_ldo" },
|
||||
@ -101,6 +112,109 @@ U_BOOT_DRIVER(pmic_stpmic1) = {
|
||||
.ops = &stpmic1_ops,
|
||||
};
|
||||
|
||||
#ifndef CONFIG_SPL_BUILD
|
||||
static int stpmic1_nvm_rw(u8 addr, u8 *buf, int buf_len, enum pmic_nvm_op op)
|
||||
{
|
||||
struct udevice *dev;
|
||||
unsigned long timeout;
|
||||
u8 cmd = STPMIC1_NVM_CMD_READ;
|
||||
int ret;
|
||||
|
||||
ret = uclass_get_device_by_driver(UCLASS_PMIC,
|
||||
DM_GET_DRIVER(pmic_stpmic1), &dev);
|
||||
if (ret)
|
||||
/* No PMIC on power discrete board */
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (addr < STPMIC1_NVM_START_ADDRESS)
|
||||
return -EACCES;
|
||||
|
||||
if (op == SHADOW_READ)
|
||||
return pmic_read(dev, addr, buf, buf_len);
|
||||
|
||||
if (op == SHADOW_WRITE)
|
||||
return pmic_write(dev, addr, buf, buf_len);
|
||||
|
||||
if (op == NVM_WRITE) {
|
||||
cmd = STPMIC1_NVM_CMD_PROGRAM;
|
||||
|
||||
ret = pmic_write(dev, addr, buf, buf_len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = pmic_reg_read(dev, STPMIC1_NVM_CR);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = pmic_reg_write(dev, STPMIC1_NVM_CR, ret | cmd);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
timeout = timer_get_us() + STPMIC1_NVM_POLL_TIMEOUT;
|
||||
for (;;) {
|
||||
ret = pmic_reg_read(dev, STPMIC1_NVM_SR);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (!(ret & STPMIC1_NVM_BUSY))
|
||||
break;
|
||||
|
||||
if (time_after(timer_get_us(), timeout))
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret & STPMIC1_NVM_BUSY)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
if (op == NVM_READ) {
|
||||
ret = pmic_read(dev, addr, buf, buf_len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stpmic1_shadow_read_byte(u8 addr, u8 *buf)
|
||||
{
|
||||
return stpmic1_nvm_rw(addr, buf, 1, SHADOW_READ);
|
||||
}
|
||||
|
||||
int stpmic1_shadow_write_byte(u8 addr, u8 *buf)
|
||||
{
|
||||
return stpmic1_nvm_rw(addr, buf, 1, SHADOW_WRITE);
|
||||
}
|
||||
|
||||
int stpmic1_nvm_read_byte(u8 addr, u8 *buf)
|
||||
{
|
||||
return stpmic1_nvm_rw(addr, buf, 1, NVM_READ);
|
||||
}
|
||||
|
||||
int stpmic1_nvm_write_byte(u8 addr, u8 *buf)
|
||||
{
|
||||
return stpmic1_nvm_rw(addr, buf, 1, NVM_WRITE);
|
||||
}
|
||||
|
||||
int stpmic1_nvm_read_all(u8 *buf, int buf_len)
|
||||
{
|
||||
if (buf_len != STPMIC1_NVM_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
return stpmic1_nvm_rw(STPMIC1_NVM_START_ADDRESS,
|
||||
buf, buf_len, NVM_READ);
|
||||
}
|
||||
|
||||
int stpmic1_nvm_write_all(u8 *buf, int buf_len)
|
||||
{
|
||||
if (buf_len != STPMIC1_NVM_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
return stpmic1_nvm_rw(STPMIC1_NVM_START_ADDRESS,
|
||||
buf, buf_len, NVM_WRITE);
|
||||
}
|
||||
#endif /* CONFIG_SPL_BUILD */
|
||||
|
||||
#ifdef CONFIG_SYSRESET
|
||||
static int stpmic1_sysreset_request(struct udevice *dev, enum sysreset_t type)
|
||||
{
|
||||
|
@ -107,4 +107,11 @@ enum {
|
||||
STPMIC1_PWR_SW2,
|
||||
STPMIC1_MAX_PWR_SW,
|
||||
};
|
||||
|
||||
int stpmic1_shadow_read_byte(u8 addr, u8 *buf);
|
||||
int stpmic1_shadow_write_byte(u8 addr, u8 *buf);
|
||||
int stpmic1_nvm_read_byte(u8 addr, u8 *buf);
|
||||
int stpmic1_nvm_write_byte(u8 addr, u8 *buf);
|
||||
int stpmic1_nvm_read_all(u8 *buf, int buf_len);
|
||||
int stpmic1_nvm_write_all(u8 *buf, int buf_len);
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user