blob: ff6280ed2080f11c3701aefef5c2d60c6f14b2a8 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
/* Copyright 2017 The ChromiumOS Authors
* 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 crec_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 = crec_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
|