blob: 04634456866dc2c0a33044f5aa30b218af390489 [file] [log] [blame]
Mike Frysinger71b2ef72022-09-12 18:54:361/* Copyright 2018 The ChromiumOS Authors
Vincent Palatin730491d2018-01-30 16:01:502 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 */
5/* Flash memory module for STM32H7 family */
6
Vincent Palatin730491d2018-01-30 16:01:507#include "clock.h"
Jeremy Bettis88684b22022-11-23 22:28:018#include "common.h"
Nicolas Boichat63f9c772018-07-12 07:51:459#include "cpu.h"
Josie Nordrum05748182020-12-06 19:32:1410#include "flash-regs.h"
Jeremy Bettis88684b22022-11-23 22:28:0111#include "flash.h"
Vincent Palatin730491d2018-01-30 16:01:5012#include "hooks.h"
Vincent Palatin730491d2018-01-30 16:01:5013#include "panic.h"
Jeremy Bettis88684b22022-11-23 22:28:0114#include "registers.h"
Vincent Palatin730491d2018-01-30 16:01:5015#include "system.h"
16#include "task.h"
17#include "timer.h"
18#include "util.h"
19#include "watchdog.h"
20
21/*
22 * Approximate number of CPU cycles per iteration of the loop when polling
23 * the flash status
24 */
25#define CYCLE_PER_FLASH_LOOP 2
26
27/* Flash 256-bit word programming timeout. */
28#define FLASH_TIMEOUT_US 600
29
30/*
31 * Flash 128-KB block erase timeout.
32 * Datasheet says maximum is about 4 seconds in x8.
33 * Real delay seems to be: < 1 second in x64, < 2 seconds in x8.
34 */
35#define FLASH_ERASE_TIMEOUT_US (4200 * MSEC)
36
37/*
38 * Option bytes programming timeout.
39 * No specification, real delay seems to be around 300ms.
40 */
41#define FLASH_OPT_PRG_TIMEOUT_US (1000 * MSEC)
42
43/*
44 * All variants have 2 banks (as in parallel hardware / controllers)
45 * not what is called 'bank' in the common code (ie Write-Protect sectors)
46 * both have the same number of 128KB blocks.
47 */
Jack Rosenthal195d11b2022-06-27 20:28:5848#define HWBANK_SIZE (CONFIG_FLASH_SIZE_BYTES / 2)
Vincent Palatin730491d2018-01-30 16:01:5049#define BLOCKS_PER_HWBANK (HWBANK_SIZE / CONFIG_FLASH_ERASE_SIZE)
Gwendal Grignouac771402019-03-11 23:07:5550#define BLOCKS_HWBANK_MASK (BIT(BLOCKS_PER_HWBANK) - 1)
Vincent Palatin730491d2018-01-30 16:01:5051
52/*
53 * We can tune the power consumption vs erase/write speed
54 * by default, go fast (and consume current)
55 */
56#define DEFAULT_PSIZE FLASH_CR_PSIZE_DWORD
57
58/* Can no longer write/erase flash until next reboot */
59static int access_disabled;
60/* Can no longer modify write-protection in option bytes until next reboot */
61static int option_disabled;
62/* Is physical flash stuck protected? (avoid reboot loop) */
63static int stuck_locked;
64
Craig Hesling58bd6e32020-01-07 20:52:3065#define FLASH_SYSJUMP_TAG 0x5750 /* "WP" - Write Protect */
66#define FLASH_HOOK_VERSION 1
67
68/* The previous write protect state before sys jump */
69struct flash_wp_state {
70 int access_disabled;
71 int option_disabled;
72 int stuck_locked;
73};
74
Vincent Palatin730491d2018-01-30 16:01:5075static inline int calculate_flash_timeout(void)
76{
Jack Rosenthal195d11b2022-06-27 20:28:5877 return (FLASH_TIMEOUT_US * (clock_get_freq() / SECOND) /
78 CYCLE_PER_FLASH_LOOP);
Vincent Palatin730491d2018-01-30 16:01:5079}
80
81static int unlock(int bank)
82{
83 /* unlock CR only if needed */
84 if (STM32_FLASH_CR(bank) & FLASH_CR_LOCK) {
85 /*
86 * We may have already locked the flash module and get a bus
87 * fault in the attempt to unlock. Need to disable bus fault
88 * handler now.
89 */
90 ignore_bus_fault(1);
91
92 STM32_FLASH_KEYR(bank) = FLASH_KEYR_KEY1;
93 STM32_FLASH_KEYR(bank) = FLASH_KEYR_KEY2;
Vincent Palatin730491d2018-01-30 16:01:5094 ignore_bus_fault(0);
95 }
96
Jack Rosenthal195d11b2022-06-27 20:28:5897 return (STM32_FLASH_CR(bank) & FLASH_CR_LOCK) ? EC_ERROR_UNKNOWN :
98 EC_SUCCESS;
Vincent Palatin730491d2018-01-30 16:01:5099}
100
101static void lock(int bank)
102{
103 STM32_FLASH_CR(bank) |= FLASH_CR_LOCK;
104}
105
106static int unlock_optb(void)
107{
108 if (option_disabled)
109 return EC_ERROR_ACCESS_DENIED;
110
111 if (unlock(0))
112 return EC_ERROR_UNKNOWN;
113
Josie Nordrum05748182020-12-06 19:32:14114 if (flash_option_bytes_locked()) {
Vincent Palatin730491d2018-01-30 16:01:50115 /*
116 * We may have already locked the flash module and get a bus
117 * fault in the attempt to unlock. Need to disable bus fault
118 * handler now.
119 */
120 ignore_bus_fault(1);
121
Josie Nordrum05748182020-12-06 19:32:14122 unlock_flash_option_bytes();
Vincent Palatin730491d2018-01-30 16:01:50123 ignore_bus_fault(0);
124 }
125
Jack Rosenthal195d11b2022-06-27 20:28:58126 return flash_option_bytes_locked() ? EC_ERROR_UNKNOWN : EC_SUCCESS;
Vincent Palatin730491d2018-01-30 16:01:50127}
128
129static int commit_optb(void)
130{
131 /* might use this before timer_init, cannot use get_time/usleep */
Jack Rosenthal195d11b2022-06-27 20:28:58132 int timeout = (FLASH_OPT_PRG_TIMEOUT_US * (clock_get_freq() / SECOND) /
133 CYCLE_PER_FLASH_LOOP);
Vincent Palatin730491d2018-01-30 16:01:50134
135 STM32_FLASH_OPTCR(0) |= FLASH_OPTCR_OPTSTART;
136
137 while (STM32_FLASH_OPTSR_CUR(0) & FLASH_OPTSR_BUSY && timeout-- > 0)
138 ;
139
Josie Nordrum05748182020-12-06 19:32:14140 lock_flash_option_bytes();
Vincent Palatin730491d2018-01-30 16:01:50141 lock(0);
142
143 return (timeout > 0) ? EC_SUCCESS : EC_ERROR_TIMEOUT;
144}
145
146static void protect_blocks(uint32_t blocks)
147{
148 if (unlock_optb())
149 return;
Nicolas Boichatb69b0992018-07-06 04:53:48150 STM32_FLASH_WPSN_PRG(0) &= ~(blocks & BLOCKS_HWBANK_MASK);
Jack Rosenthal195d11b2022-06-27 20:28:58151 STM32_FLASH_WPSN_PRG(1) &=
152 ~((blocks >> BLOCKS_PER_HWBANK) & BLOCKS_HWBANK_MASK);
Vincent Palatin730491d2018-01-30 16:01:50153 commit_optb();
154}
155
Josie Nordrum05748182020-12-06 19:32:14156/*
157 * Helper function definitions for consistency with F4 to enable flash
158 * physical unitesting
159 */
160void unlock_flash_control_register(void)
161{
162 unlock(0);
163 unlock(1);
164}
165
166void unlock_flash_option_bytes(void)
167{
168 /*
169 * Always use bank 0 flash controller as there is only one option bytes
170 * set for both banks. See http://b/181130245
171 *
172 * Consecutively program values. Ref: RM0433:4.9.2
173 */
174 STM32_FLASH_OPTKEYR(0) = FLASH_OPTKEYR_KEY1;
175 STM32_FLASH_OPTKEYR(0) = FLASH_OPTKEYR_KEY2;
176}
177
178void disable_flash_option_bytes(void)
179{
180 ignore_bus_fault(1);
181 /*
182 * Always use bank 0 flash controller as there is only one option bytes
183 * set for both banks. See http://b/181130245
184 *
185 * Writing anything other than the pre-defined keys to the option key
186 * register results in a bus fault and the register being locked until
187 * reboot (even with a further correct key write).
188 */
189 STM32_FLASH_OPTKEYR(0) = 0xffffffff;
190 ignore_bus_fault(0);
191}
192
193void disable_flash_control_register(void)
194{
195 ignore_bus_fault(1);
196 /*
197 * Writing anything other than the pre-defined keys to a key
198 * register results in a bus fault and the register being locked until
199 * reboot (even with a further correct key write).
200 */
201 STM32_FLASH_KEYR(0) = 0xffffffff;
202 STM32_FLASH_KEYR(1) = 0xffffffff;
203 ignore_bus_fault(0);
204}
205
206void lock_flash_control_register(void)
207{
208 lock(0);
209 lock(1);
210}
211
212void lock_flash_option_bytes(void)
213{
214 /*
215 * Always use bank 0 flash controller as there is only one option bytes
216 * set for both banks. See http://b/181130245
217 */
218 STM32_FLASH_OPTCR(0) |= FLASH_OPTCR_OPTLOCK;
219}
220
221bool flash_option_bytes_locked(void)
222{
223 /*
224 * Always use bank 0 flash controller as there is only one option bytes
225 * set for both banks. See http://b/181130245
226 */
Jack Rosenthal195d11b2022-06-27 20:28:58227 return !!(STM32_FLASH_OPTCR(0) & FLASH_OPTCR_OPTLOCK);
Josie Nordrum05748182020-12-06 19:32:14228}
229
230bool flash_control_register_locked(void)
231{
232 return !!(STM32_FLASH_CR(0) & FLASH_CR_LOCK) &&
233 !!(STM32_FLASH_CR(1) & FLASH_CR_LOCK);
234}
235
Nicolas Boichatc98ea9a2018-09-12 21:39:39236/*
237 * If RDP as PSTATE option is defined, use that as 'Write Protect enabled' flag:
238 * it makes no sense to be able to unlock RO, as that'd allow flashing
239 * arbitrary RO that could read back all flash.
240 *
241 * crbug.com/888109: Do not copy this code over to other STM32 chips without
242 * understanding the full implications.
243 *
244 * If RDP is not defined, use the option bytes RSS1 bit.
245 * TODO(crbug.com/888104): Validate that using RSS1 for this purpose is safe.
246 */
Tom Hughes220d0bf2019-07-09 21:19:20247#ifndef CONFIG_FLASH_READOUT_PROTECTION_AS_PSTATE
248#error "crbug.com/888104: Using RSS1 for write protect PSTATE may not be safe."
249#endif
Vincent Palatin730491d2018-01-30 16:01:50250static int is_wp_enabled(void)
251{
Nicolas Boichatc98ea9a2018-09-12 21:39:39252#ifdef CONFIG_FLASH_READOUT_PROTECTION_AS_PSTATE
Jack Rosenthal195d11b2022-06-27 20:28:58253 return (STM32_FLASH_OPTSR_CUR(0) & FLASH_OPTSR_RDP_MASK) !=
254 FLASH_OPTSR_RDP_LEVEL_0;
Nicolas Boichatc98ea9a2018-09-12 21:39:39255#else
Vincent Palatin730491d2018-01-30 16:01:50256 return !!(STM32_FLASH_OPTSR_CUR(0) & FLASH_OPTSR_RSS1);
Nicolas Boichatc98ea9a2018-09-12 21:39:39257#endif
Vincent Palatin730491d2018-01-30 16:01:50258}
259
260static int set_wp(int enabled)
261{
262 int rv;
263
264 rv = unlock_optb();
265 if (rv)
266 return rv;
Nicolas Boichatc98ea9a2018-09-12 21:39:39267
268#ifdef CONFIG_FLASH_READOUT_PROTECTION_AS_PSTATE
269 if (enabled) {
270 /* Enable RDP level 1. */
271 STM32_FLASH_OPTSR_PRG(0) =
272 (STM32_FLASH_OPTSR_PRG(0) & ~FLASH_OPTSR_RDP_MASK) |
273 FLASH_OPTSR_RDP_LEVEL_1;
274 }
275#else
Vincent Palatin730491d2018-01-30 16:01:50276 if (enabled)
277 STM32_FLASH_OPTSR_PRG(0) |= FLASH_OPTSR_RSS1;
278 else
279 STM32_FLASH_OPTSR_PRG(0) &= ~FLASH_OPTSR_RSS1;
Nicolas Boichatc98ea9a2018-09-12 21:39:39280#endif
Vincent Palatin730491d2018-01-30 16:01:50281
282 return commit_optb();
283}
284
285/*****************************************************************************/
286/* Physical layer APIs */
287
Tim Lin670bd7e2021-06-04 06:11:25288int crec_flash_physical_write(int offset, int size, const char *data)
Vincent Palatin730491d2018-01-30 16:01:50289{
290 int res = EC_SUCCESS;
291 int bank = offset / HWBANK_SIZE;
292 uint32_t *address = (void *)(CONFIG_PROGRAM_MEMORY_BASE + offset);
293 int timeout = calculate_flash_timeout();
294 int i;
295 int unaligned = (uint32_t)data & (CONFIG_FLASH_WRITE_SIZE - 1);
296 uint32_t *data32 = (void *)data;
297
298 if (access_disabled)
299 return EC_ERROR_ACCESS_DENIED;
300
301 /* work on a single hardware bank at a time */
Nicolas Boichat71fa0292018-07-06 06:30:17302 if ((offset + size - 1) / HWBANK_SIZE != bank)
Vincent Palatin730491d2018-01-30 16:01:50303 return EC_ERROR_INVAL;
304
305 if (unlock(bank) != EC_SUCCESS)
306 return EC_ERROR_UNKNOWN;
307
308 /* Clear previous error status */
309 STM32_FLASH_CCR(bank) = FLASH_CCR_ERR_MASK;
310
311 /* select write parallelism */
Jack Rosenthal195d11b2022-06-27 20:28:58312 STM32_FLASH_CR(bank) = (STM32_FLASH_CR(bank) & ~FLASH_CR_PSIZE_MASK) |
313 DEFAULT_PSIZE;
Vincent Palatin730491d2018-01-30 16:01:50314
315 /* set PG bit */
316 STM32_FLASH_CR(bank) |= FLASH_CR_PG;
317
318 for (; size > 0; size -= CONFIG_FLASH_WRITE_SIZE) {
319 /*
320 * Reload the watchdog timer to avoid watchdog reset when doing
321 * long writing.
322 */
323 watchdog_reload();
324
325 /* write a 256-bit flash word */
326 if (unaligned) {
Jack Rosenthal195d11b2022-06-27 20:28:58327 for (i = 0; i < CONFIG_FLASH_WRITE_SIZE / 4;
328 i++, data += 4)
329 *address++ = (uint32_t)data[0] |
330 (data[1] << 8) | (data[2] << 16) |
331 (data[3] << 24);
Vincent Palatin730491d2018-01-30 16:01:50332 } else {
333 for (i = 0; i < CONFIG_FLASH_WRITE_SIZE / 4; i++)
334 *address++ = *data32++;
335 }
336
337 /* Wait for writes to complete */
Jack Rosenthal195d11b2022-06-27 20:28:58338 for (i = 0;
339 (STM32_FLASH_SR(bank) & (FLASH_SR_WBNE | FLASH_SR_QW)) &&
340 (i < timeout);
341 i++)
Vincent Palatin730491d2018-01-30 16:01:50342 ;
343
344 if (STM32_FLASH_SR(bank) & (FLASH_SR_WBNE | FLASH_SR_QW)) {
345 res = EC_ERROR_TIMEOUT;
346 goto exit_wr;
347 }
348
349 if (STM32_FLASH_SR(bank) & FLASH_CCR_ERR_MASK) {
350 res = EC_ERROR_UNKNOWN;
351 goto exit_wr;
352 }
353 }
354
355exit_wr:
356 /* Disable PG bit */
357 STM32_FLASH_CR(bank) &= ~FLASH_CR_PG;
358
359 lock(bank);
360
Nicolas Boichat63f9c772018-07-12 07:51:45361#ifdef CONFIG_ARMV7M_CACHE
362 /* Invalidate D-cache, to make sure we do not read back stale data. */
363 cpu_clean_invalidate_dcache();
364#endif
365
Vincent Palatin730491d2018-01-30 16:01:50366 return res;
367}
368
Tim Lin670bd7e2021-06-04 06:11:25369int crec_flash_physical_erase(int offset, int size)
Vincent Palatin730491d2018-01-30 16:01:50370{
371 int res = EC_SUCCESS;
372 int bank = offset / HWBANK_SIZE;
373 int last = (offset + size) / CONFIG_FLASH_ERASE_SIZE;
374 int sect;
375
376 if (access_disabled)
377 return EC_ERROR_ACCESS_DENIED;
378
379 /* work on a single hardware bank at a time */
Nicolas Boichat71fa0292018-07-06 06:30:17380 if ((offset + size - 1) / HWBANK_SIZE != bank)
Vincent Palatin730491d2018-01-30 16:01:50381 return EC_ERROR_INVAL;
382
383 if (unlock(bank) != EC_SUCCESS)
384 return EC_ERROR_UNKNOWN;
385
386 /* Clear previous error status */
387 STM32_FLASH_CCR(bank) = FLASH_CCR_ERR_MASK;
388
389 /* select erase parallelism */
Jack Rosenthal195d11b2022-06-27 20:28:58390 STM32_FLASH_CR(bank) = (STM32_FLASH_CR(bank) & ~FLASH_CR_PSIZE_MASK) |
391 DEFAULT_PSIZE;
Vincent Palatin730491d2018-01-30 16:01:50392
393 for (sect = offset / CONFIG_FLASH_ERASE_SIZE; sect < last; sect++) {
394 timestamp_t deadline;
395
396 /* select page to erase and PER bit */
Jack Rosenthal195d11b2022-06-27 20:28:58397 STM32_FLASH_CR(bank) =
398 (STM32_FLASH_CR(bank) & ~FLASH_CR_SNB_MASK) |
399 FLASH_CR_SER | FLASH_CR_SNB(sect);
Vincent Palatin730491d2018-01-30 16:01:50400
401 /* set STRT bit : start erase */
402 STM32_FLASH_CR(bank) |= FLASH_CR_STRT;
403
404 /*
405 * Reload the watchdog timer to avoid watchdog reset during a
406 * long erase operation.
407 */
408 watchdog_reload();
409
410 deadline.val = get_time().val + FLASH_ERASE_TIMEOUT_US;
411 /* Wait for erase to complete */
412 while ((STM32_FLASH_SR(bank) & FLASH_SR_BUSY) &&
413 (get_time().val < deadline.val)) {
Patryk Dudaa31e6542021-05-31 18:22:32414 /*
415 * Interrupts may not be enabled, so we are using
Patryk Duda85d75982024-04-10 13:10:59416 * udelay() instead of crec_usleep() which can trigger
Patryk Dudaa31e6542021-05-31 18:22:32417 * Forced Hard Fault (see b/180761547).
418 */
419 udelay(5000);
Vincent Palatin730491d2018-01-30 16:01:50420 }
421 if (STM32_FLASH_SR(bank) & FLASH_SR_BUSY) {
422 res = EC_ERROR_TIMEOUT;
423 goto exit_er;
424 }
425
426 /*
427 * Check for error conditions - erase failed, voltage error,
428 * protection error
429 */
430 if (STM32_FLASH_SR(bank) & FLASH_CCR_ERR_MASK) {
431 res = EC_ERROR_UNKNOWN;
432 goto exit_er;
433 }
434 }
435
436exit_er:
437 /* reset SER bit */
438 STM32_FLASH_CR(bank) &= ~(FLASH_CR_SER | FLASH_CR_SNB_MASK);
439
440 lock(bank);
441
Nicolas Boichat63f9c772018-07-12 07:51:45442#ifdef CONFIG_ARMV7M_CACHE
443 /* Invalidate D-cache, to make sure we do not read back stale data. */
444 cpu_clean_invalidate_dcache();
445#endif
446
Vincent Palatin730491d2018-01-30 16:01:50447 return res;
448}
449
Tim Lin670bd7e2021-06-04 06:11:25450int crec_flash_physical_get_protect(int block)
Vincent Palatin730491d2018-01-30 16:01:50451{
452 int bank = block / BLOCKS_PER_HWBANK;
453 int index = block % BLOCKS_PER_HWBANK;
454
Gwendal Grignouac771402019-03-11 23:07:55455 return !(STM32_FLASH_WPSN_CUR(bank) & BIT(index));
Vincent Palatin730491d2018-01-30 16:01:50456}
457
458/*
459 * Note: This does not need to update _NOW flags, as flash_get_protect
460 * in common code already does so.
461 */
Tim Lin670bd7e2021-06-04 06:11:25462uint32_t crec_flash_physical_get_protect_flags(void)
Vincent Palatin730491d2018-01-30 16:01:50463{
464 uint32_t flags = 0;
465
466 if (access_disabled)
467 flags |= EC_FLASH_PROTECT_ALL_NOW;
468
469 if (is_wp_enabled())
470 flags |= EC_FLASH_PROTECT_RO_AT_BOOT;
471
472 /* Check if blocks were stuck locked at pre-init */
473 if (stuck_locked)
474 flags |= EC_FLASH_PROTECT_ERROR_STUCK;
475
476 return flags;
477}
478
479#define WP_RANGE(start, count) (((1 << (count)) - 1) << (start))
480#define RO_WP_RANGE WP_RANGE(WP_BANK_OFFSET, WP_BANK_COUNT)
481
Wai-Hong Tam3bbdefd2025-06-10 20:30:48482int crec_flash_physical_protect_now(bool all)
Vincent Palatin730491d2018-01-30 16:01:50483{
484 protect_blocks(RO_WP_RANGE);
485
486 /*
487 * Lock the option bytes or the full access by writing a wrong
488 * key to FLASH_*KEYR. This triggers a bus fault, so we need to
489 * disable bus fault handler while doing this.
490 *
491 * This incorrect key fault causes the flash to become
492 * permanently locked until reset, a correct keyring write
493 * will not unlock it.
494 */
Vincent Palatin730491d2018-01-30 16:01:50495
496 if (all) {
497 /* cannot do any write/erase access until next reboot */
Josie Nordrum05748182020-12-06 19:32:14498 disable_flash_control_register();
Vincent Palatin730491d2018-01-30 16:01:50499 access_disabled = 1;
500 }
501 /* cannot modify the WP bits in the option bytes until reboot */
Josie Nordrum05748182020-12-06 19:32:14502 disable_flash_option_bytes();
Vincent Palatin730491d2018-01-30 16:01:50503 option_disabled = 1;
Vincent Palatin730491d2018-01-30 16:01:50504
505 return EC_SUCCESS;
506}
507
Tim Lin670bd7e2021-06-04 06:11:25508int crec_flash_physical_protect_at_boot(uint32_t new_flags)
Vincent Palatin730491d2018-01-30 16:01:50509{
510 int new_wp_enable = !!(new_flags & EC_FLASH_PROTECT_RO_AT_BOOT);
511
512 if (is_wp_enabled() != new_wp_enable)
513 return set_wp(new_wp_enable);
514
515 return EC_SUCCESS;
516}
517
Tim Lin670bd7e2021-06-04 06:11:25518uint32_t crec_flash_physical_get_valid_flags(void)
Vincent Palatin730491d2018-01-30 16:01:50519{
Jack Rosenthal195d11b2022-06-27 20:28:58520 return EC_FLASH_PROTECT_RO_AT_BOOT | EC_FLASH_PROTECT_RO_NOW |
Vincent Palatin730491d2018-01-30 16:01:50521 EC_FLASH_PROTECT_ALL_NOW;
522}
523
Tim Lin670bd7e2021-06-04 06:11:25524uint32_t crec_flash_physical_get_writable_flags(uint32_t cur_flags)
Vincent Palatin730491d2018-01-30 16:01:50525{
526 uint32_t ret = 0;
527
528 /* If RO protection isn't enabled, its at-boot state can be changed. */
529 if (!(cur_flags & EC_FLASH_PROTECT_RO_NOW))
530 ret |= EC_FLASH_PROTECT_RO_AT_BOOT;
531
532 /*
533 * If entire flash isn't protected at this boot, it can be enabled if
534 * the WP GPIO is asserted.
535 */
536 if (!(cur_flags & EC_FLASH_PROTECT_ALL_NOW) &&
537 (cur_flags & EC_FLASH_PROTECT_GPIO_ASSERTED))
538 ret |= EC_FLASH_PROTECT_ALL_NOW;
539
540 return ret;
541}
542
Tim Lin670bd7e2021-06-04 06:11:25543int crec_flash_physical_restore_state(void)
Craig Hesling58bd6e32020-01-07 20:52:30544{
545 uint32_t reset_flags = system_get_reset_flags();
546 int version, size;
547 const struct flash_wp_state *prev;
548
549 /*
550 * If we have already jumped between images, an earlier image could
551 * have applied write protection. We simply need to represent these
Jack Rosenthal195d11b2022-06-27 20:28:58552 * irreversible flags to other components.
Craig Hesling58bd6e32020-01-07 20:52:30553 */
554 if (reset_flags & EC_RESET_FLAG_SYSJUMP) {
555 prev = (const struct flash_wp_state *)system_get_jump_tag(
Jack Rosenthal195d11b2022-06-27 20:28:58556 FLASH_SYSJUMP_TAG, &version, &size);
Craig Hesling58bd6e32020-01-07 20:52:30557 if (prev && version == FLASH_HOOK_VERSION &&
558 size == sizeof(*prev)) {
559 access_disabled = prev->access_disabled;
560 option_disabled = prev->option_disabled;
561 stuck_locked = prev->stuck_locked;
562 }
563 return 1;
564 }
565
566 return 0;
567}
568
Tim Lin670bd7e2021-06-04 06:11:25569int crec_flash_pre_init(void)
Vincent Palatin730491d2018-01-30 16:01:50570{
571 uint32_t reset_flags = system_get_reset_flags();
Tim Lin670bd7e2021-06-04 06:11:25572 uint32_t prot_flags = crec_flash_get_protect();
Vincent Palatin730491d2018-01-30 16:01:50573 uint32_t unwanted_prot_flags = EC_FLASH_PROTECT_ALL_NOW |
Jack Rosenthal195d11b2022-06-27 20:28:58574 EC_FLASH_PROTECT_ERROR_INCONSISTENT;
Vincent Palatin730491d2018-01-30 16:01:50575
Tim Lin670bd7e2021-06-04 06:11:25576 if (crec_flash_physical_restore_state())
Craig Hesling58bd6e32020-01-07 20:52:30577 return EC_SUCCESS;
578
Vincent Palatin730491d2018-01-30 16:01:50579 /*
580 * If we have already jumped between images, an earlier image could
581 * have applied write protection. Nothing additional needs to be done.
582 */
You-Cheng Syu555a4472019-04-09 05:04:34583 if (reset_flags & EC_RESET_FLAG_SYSJUMP)
Vincent Palatin730491d2018-01-30 16:01:50584 return EC_SUCCESS;
585
586 if (prot_flags & EC_FLASH_PROTECT_GPIO_ASSERTED) {
587 /*
588 * Write protect is asserted. If we want RO flash protected,
589 * protect it now.
590 */
591 if ((prot_flags & EC_FLASH_PROTECT_RO_AT_BOOT) &&
592 !(prot_flags & EC_FLASH_PROTECT_RO_NOW)) {
Nicolas Boichatc98ea9a2018-09-12 21:39:39593 int rv;
594
Tim Lin670bd7e2021-06-04 06:11:25595 rv = crec_flash_set_protect(EC_FLASH_PROTECT_RO_NOW,
596 EC_FLASH_PROTECT_RO_NOW);
Vincent Palatin730491d2018-01-30 16:01:50597 if (rv)
598 return rv;
599
600 /* Re-read flags */
Tim Lin670bd7e2021-06-04 06:11:25601 prot_flags = crec_flash_get_protect();
Vincent Palatin730491d2018-01-30 16:01:50602 }
603 } else {
604 /* Don't want RO flash protected */
605 unwanted_prot_flags |= EC_FLASH_PROTECT_RO_NOW;
606 }
607
608 /* If there are no unwanted flags, done */
609 if (!(prot_flags & unwanted_prot_flags))
610 return EC_SUCCESS;
611
612 /*
613 * If the last reboot was a power-on reset, it should have cleared
614 * write-protect. If it didn't, then the flash write protect registers
615 * have been permanently committed and we can't fix that.
616 */
You-Cheng Syu555a4472019-04-09 05:04:34617 if (reset_flags & EC_RESET_FLAG_POWER_ON) {
Vincent Palatin730491d2018-01-30 16:01:50618 stuck_locked = 1;
619 return EC_ERROR_ACCESS_DENIED;
620 }
621
622 /* Otherwise, do a hard boot to clear the flash protection registers */
623 system_reset(SYSTEM_RESET_HARD | SYSTEM_RESET_PRESERVE_FLAGS);
624
625 /* That doesn't return, so if we're still here that's an error */
626 return EC_ERROR_UNKNOWN;
627}
Craig Hesling58bd6e32020-01-07 20:52:30628
629/*****************************************************************************/
630/* Hooks */
631
632static void flash_preserve_state(void)
633{
634 const struct flash_wp_state state = {
635 .access_disabled = access_disabled,
636 .option_disabled = option_disabled,
637 .stuck_locked = stuck_locked,
638 };
639
640 system_add_jump_tag(FLASH_SYSJUMP_TAG, FLASH_HOOK_VERSION,
641 sizeof(state), &state);
642}
643DECLARE_HOOK(HOOK_SYSJUMP, flash_preserve_state, HOOK_PRIO_DEFAULT);