Angel Pons | 8a3453f | 2020-04-02 23:48:19 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
Aaron Durbin | 6f11559 | 2016-08-11 18:24:54 -0500 | [diff] [blame] | 2 | |
Aaron Durbin | 6f11559 | 2016-08-11 18:24:54 -0500 | [diff] [blame] | 3 | #include <boot_device.h> |
| 4 | #include <spi_flash.h> |
Furquan Shaikh | c28984d | 2016-11-20 21:04:00 -0800 | [diff] [blame] | 5 | #include <spi-generic.h> |
Furquan Shaikh | 30221b4 | 2017-05-15 14:35:15 -0700 | [diff] [blame] | 6 | #include <stdint.h> |
Aaron Durbin | 6f11559 | 2016-08-11 18:24:54 -0500 | [diff] [blame] | 7 | |
Arthur Heymans | d20b0a8 | 2019-11-20 22:00:57 +0100 | [diff] [blame] | 8 | static struct spi_flash sfg; |
| 9 | static bool sfg_init_done; |
Aaron Durbin | 6f11559 | 2016-08-11 18:24:54 -0500 | [diff] [blame] | 10 | |
| 11 | static ssize_t spi_readat(const struct region_device *rd, void *b, |
| 12 | size_t offset, size_t size) |
| 13 | { |
Arthur Heymans | d20b0a8 | 2019-11-20 22:00:57 +0100 | [diff] [blame] | 14 | if (spi_flash_read(&sfg, offset, size, b)) |
Aaron Durbin | 6f11559 | 2016-08-11 18:24:54 -0500 | [diff] [blame] | 15 | return -1; |
| 16 | |
| 17 | return size; |
| 18 | } |
| 19 | |
| 20 | static ssize_t spi_writeat(const struct region_device *rd, const void *b, |
| 21 | size_t offset, size_t size) |
| 22 | { |
Arthur Heymans | d20b0a8 | 2019-11-20 22:00:57 +0100 | [diff] [blame] | 23 | if (spi_flash_write(&sfg, offset, size, b)) |
Aaron Durbin | 6f11559 | 2016-08-11 18:24:54 -0500 | [diff] [blame] | 24 | return -1; |
| 25 | |
| 26 | return size; |
| 27 | } |
| 28 | |
| 29 | static ssize_t spi_eraseat(const struct region_device *rd, |
| 30 | size_t offset, size_t size) |
| 31 | { |
Arthur Heymans | d20b0a8 | 2019-11-20 22:00:57 +0100 | [diff] [blame] | 32 | if (spi_flash_erase(&sfg, offset, size)) |
Aaron Durbin | 6f11559 | 2016-08-11 18:24:54 -0500 | [diff] [blame] | 33 | return -1; |
| 34 | |
| 35 | return size; |
| 36 | } |
| 37 | |
| 38 | static const struct region_device_ops spi_ops = { |
| 39 | .readat = spi_readat, |
| 40 | .writeat = spi_writeat, |
| 41 | .eraseat = spi_eraseat, |
| 42 | }; |
| 43 | |
| 44 | static const struct region_device spi_rw = |
| 45 | REGION_DEV_INIT(&spi_ops, 0, CONFIG_ROM_SIZE); |
| 46 | |
Aaron Durbin | 67e4df8 | 2016-08-23 08:45:55 -0500 | [diff] [blame] | 47 | static void boot_device_rw_init(void) |
Aaron Durbin | 6f11559 | 2016-08-11 18:24:54 -0500 | [diff] [blame] | 48 | { |
| 49 | const int bus = CONFIG_BOOT_DEVICE_SPI_FLASH_BUS; |
| 50 | const int cs = 0; |
| 51 | |
Arthur Heymans | d20b0a8 | 2019-11-20 22:00:57 +0100 | [diff] [blame] | 52 | if (sfg_init_done == true) |
Aaron Durbin | 6f11559 | 2016-08-11 18:24:54 -0500 | [diff] [blame] | 53 | return; |
| 54 | |
Aaron Durbin | df76f89 | 2016-08-22 17:41:13 -0500 | [diff] [blame] | 55 | /* Ensure any necessary setup is performed by the drivers. */ |
| 56 | spi_init(); |
| 57 | |
Arthur Heymans | d20b0a8 | 2019-11-20 22:00:57 +0100 | [diff] [blame] | 58 | if (!spi_flash_probe(bus, cs, &sfg)) |
| 59 | sfg_init_done = true; |
Aaron Durbin | 6f11559 | 2016-08-11 18:24:54 -0500 | [diff] [blame] | 60 | } |
| 61 | |
| 62 | const struct region_device *boot_device_rw(void) |
| 63 | { |
Aaron Durbin | 67e4df8 | 2016-08-23 08:45:55 -0500 | [diff] [blame] | 64 | /* Probe for the SPI flash device if not already done. */ |
| 65 | boot_device_rw_init(); |
| 66 | |
Arthur Heymans | d20b0a8 | 2019-11-20 22:00:57 +0100 | [diff] [blame] | 67 | if (sfg_init_done != true) |
Aaron Durbin | 6f11559 | 2016-08-11 18:24:54 -0500 | [diff] [blame] | 68 | return NULL; |
| 69 | |
| 70 | return &spi_rw; |
| 71 | } |
Aaron Durbin | 305c0ca | 2016-12-03 17:04:06 -0600 | [diff] [blame] | 72 | |
| 73 | const struct spi_flash *boot_device_spi_flash(void) |
| 74 | { |
| 75 | boot_device_rw_init(); |
Furquan Shaikh | 30221b4 | 2017-05-15 14:35:15 -0700 | [diff] [blame] | 76 | |
Arthur Heymans | d20b0a8 | 2019-11-20 22:00:57 +0100 | [diff] [blame] | 77 | if (sfg_init_done != true) |
Furquan Shaikh | 30221b4 | 2017-05-15 14:35:15 -0700 | [diff] [blame] | 78 | return NULL; |
| 79 | |
Arthur Heymans | d20b0a8 | 2019-11-20 22:00:57 +0100 | [diff] [blame] | 80 | return &sfg; |
Aaron Durbin | 305c0ca | 2016-12-03 17:04:06 -0600 | [diff] [blame] | 81 | } |
Rizwan Qureshi | 6d4c1f5 | 2018-10-26 16:54:42 +0530 | [diff] [blame] | 82 | |
Patrick Rudolph | 2be0b50 | 2019-05-09 13:43:49 +0200 | [diff] [blame] | 83 | int boot_device_wp_region(const struct region_device *rd, |
Rizwan Qureshi | 6d4c1f5 | 2018-10-26 16:54:42 +0530 | [diff] [blame] | 84 | const enum bootdev_prot_type type) |
| 85 | { |
| 86 | uint32_t ctrlr_pr; |
| 87 | |
| 88 | /* Ensure boot device has been initialized at least once. */ |
| 89 | boot_device_init(); |
| 90 | |
| 91 | const struct spi_flash *boot_dev = boot_device_spi_flash(); |
| 92 | |
| 93 | if (boot_dev == NULL) |
| 94 | return -1; |
| 95 | |
| 96 | if (type == MEDIA_WP) { |
| 97 | if (spi_flash_is_write_protected(boot_dev, |
Arthur Heymans | d20b0a8 | 2019-11-20 22:00:57 +0100 | [diff] [blame] | 98 | region_device_region(rd)) != 1) { |
Daniel Gröber | 16dbbeb | 2020-05-26 22:18:44 +0200 | [diff] [blame] | 99 | enum spi_flash_status_reg_lockdown lock = |
| 100 | SPI_WRITE_PROTECTION_REBOOT; |
| 101 | if (CONFIG(BOOTMEDIA_SPI_LOCK_REBOOT)) |
| 102 | lock = SPI_WRITE_PROTECTION_REBOOT; |
| 103 | else if (CONFIG(BOOTMEDIA_SPI_LOCK_PIN)) |
| 104 | lock = SPI_WRITE_PROTECTION_PIN; |
| 105 | else if (CONFIG(BOOTMEDIA_SPI_LOCK_PERMANENT)) |
| 106 | lock = SPI_WRITE_PROTECTION_PERMANENT; |
| 107 | |
Rizwan Qureshi | 6d4c1f5 | 2018-10-26 16:54:42 +0530 | [diff] [blame] | 108 | return spi_flash_set_write_protected(boot_dev, |
Daniel Gröber | 16dbbeb | 2020-05-26 22:18:44 +0200 | [diff] [blame] | 109 | region_device_region(rd), lock); |
Rizwan Qureshi | 6d4c1f5 | 2018-10-26 16:54:42 +0530 | [diff] [blame] | 110 | } |
| 111 | |
| 112 | /* Already write protected */ |
| 113 | return 0; |
| 114 | } |
| 115 | |
| 116 | switch (type) { |
| 117 | case CTRLR_WP: |
| 118 | ctrlr_pr = WRITE_PROTECT; |
| 119 | break; |
| 120 | case CTRLR_RP: |
| 121 | ctrlr_pr = READ_PROTECT; |
| 122 | break; |
| 123 | case CTRLR_RWP: |
| 124 | ctrlr_pr = READ_WRITE_PROTECT; |
| 125 | break; |
| 126 | default: |
| 127 | return -1; |
| 128 | } |
| 129 | |
| 130 | return spi_flash_ctrlr_protect_region(boot_dev, |
| 131 | region_device_region(rd), ctrlr_pr); |
| 132 | } |