mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-29 18:11:05 +00:00
stm32f4: Add OTP support.
Add support for OTP memory: if needed store serial number in first bank. BUG=chromium:746471 BRANCH=none TEST=On sweetberry, check we can write serial number with serialno command. Check serial number survive a firmware update. First, check without write protect, check we can write 0s (but not 1s) serialno Serial number: NNNNNNNNNNNNNNNNNNNNNN > > serial set MMMMMMMMMMMMMMMMMMMMMMMMMMMMM Saving serial number Serial number: LLLLLLLLLLLLLLLLLLLLLL After lock enabled, check we can not overwrite. > serial set AMMMMMMMMMMMMMMMMMMMMMMMMMMMM Saving serial number Serial number: LLLLLLLLLLLLLLLLLLLLLL Access Denied Check that serialno returns "Uninitialized" if it was never set. Change-Id: I9ab08486a7c3e1958e964649640d69b5b70947e3 Signed-off-by: Gwendal Grignou <gwendal@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/580290 Reviewed-by: Nick Sanders <nsanders@chromium.org>
This commit is contained in:
committed by
chrome-bot
parent
1b25735b73
commit
a35218e204
@@ -56,6 +56,7 @@ endif
|
||||
chip-$(CONFIG_ADC)+=adc-$(CHIP_FAMILY).o
|
||||
chip-$(CONFIG_STM32_CHARGER_DETECT)+=charger_detect.o
|
||||
chip-$(CONFIG_DEBUG_PRINTF)+=debug_printf.o
|
||||
chip-$(CONFIG_OTP)+=otp-$(CHIP_FAMILY).o
|
||||
chip-$(CONFIG_PWM)+=pwm.o
|
||||
chip-$(CONFIG_RNG)+=trng.o
|
||||
|
||||
|
||||
@@ -54,5 +54,8 @@
|
||||
#define CONFIG_FLASH_PSTATE
|
||||
#undef CONFIG_FLASH_PSTATE_BANK
|
||||
|
||||
/* Use OTP regions */
|
||||
#define CONFIG_OTP
|
||||
|
||||
/* Number of IRQ vectors on the NVIC */
|
||||
#define CONFIG_IRQ_COUNT 97
|
||||
|
||||
119
chip/stm32/otp-stm32f4.c
Normal file
119
chip/stm32/otp-stm32f4.c
Normal file
@@ -0,0 +1,119 @@
|
||||
/* Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
/* OTP implementation for STM32F411 */
|
||||
|
||||
#include "common.h"
|
||||
#include "console.h"
|
||||
#include "flash.h"
|
||||
#include "otp.h"
|
||||
#include "registers.h"
|
||||
#include "util.h"
|
||||
|
||||
/*
|
||||
* OTP is only used for saving the USB serial number.
|
||||
*/
|
||||
#ifdef CONFIG_SERIALNO_LEN
|
||||
/* Which block to use */
|
||||
#define OTP_SERIAL_BLOCK 0
|
||||
#define OTP_SERIAL_ADDR \
|
||||
REG32_ADDR(STM32_OTP_BLOCK_DATA(OTP_SERIAL_BLOCK, 0))
|
||||
|
||||
/* Number of word used in the block */
|
||||
#define OTP_SERIAL_BLOCK_SIZE (CONFIG_SERIALNO_LEN / sizeof(uint32_t))
|
||||
BUILD_ASSERT(CONFIG_SERIALNO_LEN % sizeof(uint32_t) == 0);
|
||||
BUILD_ASSERT(OTP_SERIAL_BLOCK_SIZE < STM32_OTP_BLOCK_SIZE);
|
||||
|
||||
/*
|
||||
* Write an OTP block
|
||||
*
|
||||
* @param block block to write.
|
||||
* @param size Number of words to write.
|
||||
* @param data Destination buffer for data.
|
||||
*/
|
||||
static int otp_write(uint8_t block, int size, const char *data)
|
||||
{
|
||||
if (block >= STM32_OTP_BLOCK_NB)
|
||||
return EC_ERROR_PARAM1;
|
||||
if (size >= STM32_OTP_BLOCK_SIZE)
|
||||
return EC_ERROR_PARAM2;
|
||||
return flash_physical_write(STM32_OTP_BLOCK_DATA(block, 0) -
|
||||
CONFIG_PROGRAM_MEMORY_BASE,
|
||||
size * sizeof(uint32_t), data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if an OTP block is protected.
|
||||
*
|
||||
* @param block protected block.
|
||||
* @return non-zero if that block is read only.
|
||||
*/
|
||||
static int otp_get_protect(uint8_t block)
|
||||
{
|
||||
uint32_t lock;
|
||||
|
||||
lock = REG32(STM32_OTP_LOCK(block));
|
||||
return ((lock & STM32_OPT_LOCK_MASK(block)) == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set a particular OTP block as read only.
|
||||
*
|
||||
* @param block block to protect.
|
||||
*/
|
||||
static int otp_set_protect(uint8_t block)
|
||||
{
|
||||
int rv;
|
||||
uint32_t lock;
|
||||
|
||||
if (otp_get_protect(block))
|
||||
return EC_SUCCESS;
|
||||
|
||||
lock = REG32(STM32_OTP_LOCK(block));
|
||||
lock &= ~STM32_OPT_LOCK_MASK(block);
|
||||
rv = flash_physical_write(STM32_OTP_LOCK(block) -
|
||||
CONFIG_PROGRAM_MEMORY_BASE,
|
||||
sizeof(uint32_t), (char *)&lock);
|
||||
if (rv)
|
||||
return rv;
|
||||
else
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
const char *otp_read_serial(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < OTP_SERIAL_BLOCK_SIZE; i++) {
|
||||
if (OTP_SERIAL_ADDR[i] != -1)
|
||||
return (char *)OTP_SERIAL_ADDR;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int otp_write_serial(const char *serialno)
|
||||
{
|
||||
int i, ret;
|
||||
char otp_serial[CONFIG_SERIALNO_LEN];
|
||||
|
||||
if (otp_get_protect(OTP_SERIAL_BLOCK))
|
||||
return EC_ERROR_ACCESS_DENIED;
|
||||
|
||||
/* Copy in serialno. */
|
||||
for (i = 0; i < CONFIG_SERIALNO_LEN - 1; i++) {
|
||||
otp_serial[i] = serialno[i];
|
||||
if (serialno[i] == 0)
|
||||
break;
|
||||
}
|
||||
for (; i < CONFIG_SERIALNO_LEN; i++)
|
||||
otp_serial[i] = 0;
|
||||
|
||||
ret = otp_write(OTP_SERIAL_BLOCK, OTP_SERIAL_BLOCK_SIZE, otp_serial);
|
||||
if (ret == EC_SUCCESS)
|
||||
return otp_set_protect(OTP_SERIAL_BLOCK);
|
||||
else
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
@@ -1479,6 +1479,19 @@ typedef volatile struct stm32_spi_regs stm32_spi_regs_t;
|
||||
|
||||
#define STM32_OPTB_COMPL_SHIFT 8
|
||||
|
||||
#define STM32_OTP_BASE 0x1FFF7800
|
||||
#define STM32_OTP_BLOCK_NB 16
|
||||
#define STM32_OTP_BLOCK_SIZE 32
|
||||
#define STM32_OTP_BLOCK_DATA(_block, _offset) \
|
||||
(STM32_OTP_BASE + STM32_OTP_BLOCK_SIZE * (_block) + (_offset) * 4)
|
||||
#define STM32_OTP_UNLOCK_BYTE 0x00
|
||||
#define STM32_OTP_LOCK_BYTE 0xFF
|
||||
#define STM32_OTP_LOCK_BASE \
|
||||
(STM32_OTP_BASE + STM32_OTP_BLOCK_NB * STM32_OTP_BLOCK_SIZE)
|
||||
#define STM32_OTP_LOCK(_block) \
|
||||
(STM32_OTP_LOCK_BASE + ((_block) / 4) * 4)
|
||||
#define STM32_OPT_LOCK_MASK(_block) ((0xFF << ((_block) % 4) * 8))
|
||||
|
||||
#else
|
||||
#error Unsupported chip variant
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user