blob: f8de4a726d36cfb28e4d4bf1c2fa3aab81e6eaf7 [file] [log] [blame]
Carl-Daniel Hailfinger702218d2009-05-08 17:43:22 +00001/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2009 Carl-Daniel Hailfinger
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Carl-Daniel Hailfinger702218d2009-05-08 17:43:22 +000015 */
16
Carl-Daniel Hailfinger1c6d2ff2012-08-27 00:44:42 +000017#include <strings.h>
Carl-Daniel Hailfinger702218d2009-05-08 17:43:22 +000018#include <string.h>
Felix Singerb8db74a2022-08-19 00:19:26 +020019#include <stdbool.h>
Carl-Daniel Hailfinger702218d2009-05-08 17:43:22 +000020#include <stdlib.h>
Carl-Daniel Hailfinger702218d2009-05-08 17:43:22 +000021#include "flash.h"
Carl-Daniel Hailfinger5b997c32010-07-27 22:41:39 +000022#include "programmer.h"
Thomas Heijligen74b4aa02021-12-14 17:52:30 +010023#include "hwaccess_physmap.h"
Thomas Heijligend96c97c2021-11-02 21:03:00 +010024#include "platform/pci.h"
Carl-Daniel Hailfinger702218d2009-05-08 17:43:22 +000025
Peter Marheinedf3672d2022-01-19 17:11:09 +110026#if defined(__i386__) || defined(__x86_64__)
27#include "hwaccess_x86_io.h"
28#endif
29
Felix Singerb8db74a2022-08-19 00:19:26 +020030bool force_boardenable = false;
31bool force_boardmismatch = false;
Carl-Daniel Hailfinger14e100c2009-12-22 23:42:04 +000032
Thomas Heijligen4b918a12021-09-26 13:42:39 +020033#if defined(__i386__) || defined(__x86_64__)
Carl-Daniel Hailfinger14e100c2009-12-22 23:42:04 +000034void probe_superio(void)
35{
Carl-Daniel Hailfingerf5e62cb2012-05-06 22:48:01 +000036 probe_superio_winbond();
37 /* ITE probe causes SMSC LPC47N217 to power off the serial UART.
38 * Always probe for SMSC first, and if a SMSC Super I/O is detected
39 * at a given I/O port, do _not_ probe that port with the ITE probe.
40 * This means SMSC probing must be done before ITE probing.
41 */
42 //probe_superio_smsc();
Carl-Daniel Hailfingerbfecef62011-04-27 14:34:08 +000043 probe_superio_ite();
Carl-Daniel Hailfinger14e100c2009-12-22 23:42:04 +000044}
Carl-Daniel Hailfingerbfecef62011-04-27 14:34:08 +000045
46int superio_count = 0;
47#define SUPERIO_MAX_COUNT 3
48
49struct superio superios[SUPERIO_MAX_COUNT];
50
51int register_superio(struct superio s)
52{
53 if (superio_count == SUPERIO_MAX_COUNT)
54 return 1;
55 superios[superio_count++] = s;
56 return 0;
57}
58
Carl-Daniel Hailfingercceafa22010-05-26 01:45:41 +000059#endif
Carl-Daniel Hailfinger14e100c2009-12-22 23:42:04 +000060
Carl-Daniel Hailfingercceafa22010-05-26 01:45:41 +000061int is_laptop = 0;
Felix Singerd1ab7d22022-08-19 03:03:47 +020062bool laptop_ok = false;
Michael Karcher8c1df282010-02-26 09:51:20 +000063
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +000064static void internal_chip_writeb(const struct flashctx *flash, uint8_t val,
65 chipaddr addr);
66static void internal_chip_writew(const struct flashctx *flash, uint16_t val,
67 chipaddr addr);
68static void internal_chip_writel(const struct flashctx *flash, uint32_t val,
69 chipaddr addr);
70static uint8_t internal_chip_readb(const struct flashctx *flash,
71 const chipaddr addr);
72static uint16_t internal_chip_readw(const struct flashctx *flash,
73 const chipaddr addr);
74static uint32_t internal_chip_readl(const struct flashctx *flash,
75 const chipaddr addr);
76static void internal_chip_readn(const struct flashctx *flash, uint8_t *buf,
77 const chipaddr addr, size_t len);
Carl-Daniel Hailfingera5bcbce2014-07-19 22:03:29 +000078static const struct par_master par_master_internal = {
Thomas Heijligen43040f22022-06-23 14:38:35 +020079 .chip_readb = internal_chip_readb,
80 .chip_readw = internal_chip_readw,
81 .chip_readl = internal_chip_readl,
82 .chip_readn = internal_chip_readn,
83 .chip_writeb = internal_chip_writeb,
84 .chip_writew = internal_chip_writew,
85 .chip_writel = internal_chip_writel,
86 .chip_writen = fallback_chip_writen,
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +000087};
88
89enum chipbustype internal_buses_supported = BUS_NONE;
90
Felix Singerb8db74a2022-08-19 00:19:26 +020091static int get_params(bool *boardenable, bool *boardmismatch,
92 bool *force_laptop, bool *not_a_laptop,
Edward O'Callaghand91ee2c2022-02-03 11:55:13 +110093 char **board_vendor, char **board_model)
Uwe Hermanna0869322009-05-14 20:41:57 +000094{
Carl-Daniel Hailfinger27023762010-04-28 15:22:14 +000095 char *arg;
Uwe Hermanna0869322009-05-14 20:41:57 +000096
Edward O'Callaghand91ee2c2022-02-03 11:55:13 +110097 /* default values. */
Felix Singerb8db74a2022-08-19 00:19:26 +020098 *force_laptop = false;
99 *not_a_laptop = false;
Edward O'Callaghand91ee2c2022-02-03 11:55:13 +1100100 *board_vendor = NULL;
101 *board_model = NULL;
102
Carl-Daniel Hailfinger2b6dcb32010-07-08 10:13:37 +0000103 arg = extract_programmer_param("boardenable");
Carl-Daniel Hailfinger27023762010-04-28 15:22:14 +0000104 if (arg && !strcmp(arg,"force")) {
Felix Singerb8db74a2022-08-19 00:19:26 +0200105 *boardenable = true;
Carl-Daniel Hailfinger27023762010-04-28 15:22:14 +0000106 } else if (arg && !strlen(arg)) {
107 msg_perr("Missing argument for boardenable.\n");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000108 free(arg);
109 return 1;
Carl-Daniel Hailfinger27023762010-04-28 15:22:14 +0000110 } else if (arg) {
111 msg_perr("Unknown argument for boardenable: %s\n", arg);
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000112 free(arg);
113 return 1;
Michael Karcher0bdc0922010-02-28 01:33:48 +0000114 }
Carl-Daniel Hailfinger27023762010-04-28 15:22:14 +0000115 free(arg);
Michael Karcher0bdc0922010-02-28 01:33:48 +0000116
Carl-Daniel Hailfinger2b6dcb32010-07-08 10:13:37 +0000117 arg = extract_programmer_param("boardmismatch");
Carl-Daniel Hailfinger27023762010-04-28 15:22:14 +0000118 if (arg && !strcmp(arg,"force")) {
Felix Singerb8db74a2022-08-19 00:19:26 +0200119 *boardmismatch = true;
Carl-Daniel Hailfinger27023762010-04-28 15:22:14 +0000120 } else if (arg && !strlen(arg)) {
121 msg_perr("Missing argument for boardmismatch.\n");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000122 free(arg);
123 return 1;
Carl-Daniel Hailfinger27023762010-04-28 15:22:14 +0000124 } else if (arg) {
125 msg_perr("Unknown argument for boardmismatch: %s\n", arg);
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000126 free(arg);
127 return 1;
Michael Karcher0bdc0922010-02-28 01:33:48 +0000128 }
Carl-Daniel Hailfinger27023762010-04-28 15:22:14 +0000129 free(arg);
130
Carl-Daniel Hailfinger2b6dcb32010-07-08 10:13:37 +0000131 arg = extract_programmer_param("laptop");
Stefan Taunera28087f2011-09-13 23:14:25 +0000132 if (arg && !strcmp(arg, "force_I_want_a_brick"))
Felix Singerb8db74a2022-08-19 00:19:26 +0200133 *force_laptop = true;
Stefan Taunera28087f2011-09-13 23:14:25 +0000134 else if (arg && !strcmp(arg, "this_is_not_a_laptop"))
Felix Singerb8db74a2022-08-19 00:19:26 +0200135 *not_a_laptop = true;
Stefan Taunera28087f2011-09-13 23:14:25 +0000136 else if (arg && !strlen(arg)) {
Carl-Daniel Hailfinger27023762010-04-28 15:22:14 +0000137 msg_perr("Missing argument for laptop.\n");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000138 free(arg);
139 return 1;
Carl-Daniel Hailfinger27023762010-04-28 15:22:14 +0000140 } else if (arg) {
141 msg_perr("Unknown argument for laptop: %s\n", arg);
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000142 free(arg);
143 return 1;
Carl-Daniel Hailfinger27023762010-04-28 15:22:14 +0000144 }
145 free(arg);
146
Carl-Daniel Hailfinger2d927fb2012-01-04 00:48:27 +0000147 arg = extract_programmer_param("mainboard");
148 if (arg && strlen(arg)) {
Edward O'Callaghand91ee2c2022-02-03 11:55:13 +1100149 if (board_parse_parameter(arg, board_vendor, board_model)) {
Stefan Taunerb4e06bd2012-08-20 00:24:22 +0000150 free(arg);
151 return 1;
152 }
Carl-Daniel Hailfinger2d927fb2012-01-04 00:48:27 +0000153 } else if (arg && !strlen(arg)) {
154 msg_perr("Missing argument for mainboard.\n");
155 free(arg);
156 return 1;
157 }
158 free(arg);
159
Edward O'Callaghand91ee2c2022-02-03 11:55:13 +1100160 return 0;
161}
162
163static int internal_init(void)
164{
165 int ret = 0;
Felix Singerb8db74a2022-08-19 00:19:26 +0200166 bool force_laptop;
167 bool not_a_laptop;
Edward O'Callaghand91ee2c2022-02-03 11:55:13 +1100168 char *board_vendor;
169 char *board_model;
170#if defined(__i386__) || defined(__x86_64__)
171 const char *cb_vendor = NULL;
172 const char *cb_model = NULL;
173#endif
174
175 ret = get_params(&force_boardenable, &force_boardmismatch,
176 &force_laptop, &not_a_laptop,
177 &board_vendor, &board_model);
178 if (ret)
179 return ret;
Carl-Daniel Hailfinger702218d2009-05-08 17:43:22 +0000180
Edward O'Callaghanbd275812022-11-28 11:20:44 +1100181 /* Unconditionally reset global state from previous operation. */
182 laptop_ok = false;
183
Michael Karcherb9dbe482011-05-11 17:07:07 +0000184 /* Default to Parallel/LPC/FWH flash devices. If a known host controller
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000185 * is found, the host controller init routine sets the
186 * internal_buses_supported bitfield.
Michael Karcherb9dbe482011-05-11 17:07:07 +0000187 */
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000188 internal_buses_supported = BUS_NONSPI;
Michael Karcherb9dbe482011-05-11 17:07:07 +0000189
Jacob Garber1c091d12019-08-12 11:14:14 -0600190 if (try_mtd() == 0) {
191 ret = 0;
192 goto internal_init_exit;
193 }
David Hendricksf9a30552015-05-23 20:30:30 -0700194
Carl-Daniel Hailfinger702218d2009-05-08 17:43:22 +0000195 /* Initialize PCI access for flash enables */
Jacob Garber1c091d12019-08-12 11:14:14 -0600196 if (pci_init_common() != 0) {
197 ret = 1;
198 goto internal_init_exit;
199 }
Carl-Daniel Hailfinger702218d2009-05-08 17:43:22 +0000200
Carl-Daniel Hailfingerb5b161b2010-06-04 19:05:39 +0000201 if (processor_flash_enable()) {
202 msg_perr("Processor detection/init failed.\n"
203 "Aborting.\n");
Jacob Garber1c091d12019-08-12 11:14:14 -0600204 ret = 1;
205 goto internal_init_exit;
Carl-Daniel Hailfingerb5b161b2010-06-04 19:05:39 +0000206 }
207
Thomas Heijligen4b918a12021-09-26 13:42:39 +0200208#if defined(__i386__) || defined(__x86_64__)
Peter Marheinedf3672d2022-01-19 17:11:09 +1100209 if (rget_io_perms()) {
210 ret = 1;
211 goto internal_init_exit;
212 }
213
Stefan Taunerfa9fa712012-09-24 21:29:29 +0000214 if ((cb_parse_table(&cb_vendor, &cb_model) == 0) && (board_vendor != NULL) && (board_model != NULL)) {
215 if (strcasecmp(board_vendor, cb_vendor) || strcasecmp(board_model, cb_model)) {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000216 msg_pwarn("Warning: The mainboard IDs set by -p internal:mainboard (%s:%s) do not\n"
Stefan Taunerb4e06bd2012-08-20 00:24:22 +0000217 " match the current coreboot IDs of the mainboard (%s:%s).\n",
218 board_vendor, board_model, cb_vendor, cb_model);
Jacob Garber1c091d12019-08-12 11:14:14 -0600219 if (!force_boardmismatch) {
220 ret = 1;
221 goto internal_init_exit;
222 }
Stefan Taunerb4e06bd2012-08-20 00:24:22 +0000223 msg_pinfo("Continuing anyway.\n");
224 }
225 }
Carl-Daniel Hailfingercceafa22010-05-26 01:45:41 +0000226
Nico Huber2e50cdc2018-09-23 20:20:26 +0200227 is_laptop = 2; /* Assume that we don't know by default. */
228
Michael Karcher6701ee82010-01-20 14:14:11 +0000229 dmi_init();
Carl-Daniel Hailfinger702218d2009-05-08 17:43:22 +0000230
Carl-Daniel Hailfinger580d29a2011-05-05 07:12:40 +0000231 /* In case Super I/O probing would cause pretty explosions. */
232 board_handle_before_superio();
233
Uwe Hermann43959702010-03-13 17:28:29 +0000234 /* Probe for the Super I/O chip and fill global struct superio. */
Carl-Daniel Hailfinger14e100c2009-12-22 23:42:04 +0000235 probe_superio();
Carl-Daniel Hailfingerb5b161b2010-06-04 19:05:39 +0000236#else
237 /* FIXME: Enable cbtable searching on all non-x86 platforms supported
238 * by coreboot.
239 * FIXME: Find a replacement for DMI on non-x86.
240 * FIXME: Enable Super I/O probing once port I/O is possible.
241 */
Carl-Daniel Hailfingercceafa22010-05-26 01:45:41 +0000242#endif
Carl-Daniel Hailfinger14e100c2009-12-22 23:42:04 +0000243
Carl-Daniel Hailfinger580d29a2011-05-05 07:12:40 +0000244 /* Check laptop whitelist. */
245 board_handle_before_laptop();
246
Nico Huber2e50cdc2018-09-23 20:20:26 +0200247 /*
248 * Disable all internal buses by default if we are not sure
249 * this isn't a laptop. Board-enables may override this,
250 * non-legacy buses (SPI and opaque atm) are probed anyway.
251 */
252 if (is_laptop && !(laptop_ok || force_laptop || (not_a_laptop && is_laptop == 2)))
253 internal_buses_supported = BUS_NONE;
Michael Karcher8c1df282010-02-26 09:51:20 +0000254
Carl-Daniel Hailfinger702218d2009-05-08 17:43:22 +0000255 /* try to enable it. Failure IS an option, since not all motherboards
256 * really need this to be done, etc., etc.
257 */
258 ret = chipset_flash_enable();
259 if (ret == -2) {
Carl-Daniel Hailfinger27023762010-04-28 15:22:14 +0000260 msg_perr("WARNING: No chipset found. Flash detection "
261 "will most likely fail.\n");
Jacob Garber1c091d12019-08-12 11:14:14 -0600262 } else if (ret == ERROR_FATAL) {
263 goto internal_init_exit;
264 }
Carl-Daniel Hailfinger702218d2009-05-08 17:43:22 +0000265
Thomas Heijligen4b918a12021-09-26 13:42:39 +0200266#if defined(__i386__) || defined(__x86_64__)
Vadim Girlin4dd0f902013-08-24 12:18:17 +0000267 /* Probe unconditionally for ITE Super I/O chips. This enables LPC->SPI translation on IT87* and
268 * parallel writes on IT8705F. Also, this handles the manual chip select for Gigabyte's DualBIOS. */
Carl-Daniel Hailfinger76d4b372010-07-10 16:56:32 +0000269 init_superio_ite();
Carl-Daniel Hailfinger01f3ef42010-03-25 02:50:40 +0000270
Stefan Taunerfa9fa712012-09-24 21:29:29 +0000271 if (board_flash_enable(board_vendor, board_model, cb_vendor, cb_model)) {
Stefan Taunerb4e06bd2012-08-20 00:24:22 +0000272 msg_perr("Aborting to be safe.\n");
Jacob Garber1c091d12019-08-12 11:14:14 -0600273 ret = 1;
274 goto internal_init_exit;
Stefan Taunerb4e06bd2012-08-20 00:24:22 +0000275 }
Stefan Taunerb0eee9b2015-01-10 09:32:50 +0000276#endif
Carl-Daniel Hailfinger702218d2009-05-08 17:43:22 +0000277
Nico Huber2e50cdc2018-09-23 20:20:26 +0200278 if (internal_buses_supported & BUS_NONSPI)
Anastasia Klimchukb91a2032021-05-21 09:40:58 +1000279 register_par_master(&par_master_internal, internal_buses_supported, NULL);
Nico Huber2e50cdc2018-09-23 20:20:26 +0200280
281 /* Report if a non-whitelisted laptop is detected that likely uses a legacy bus. */
282 if (is_laptop && !laptop_ok) {
283 msg_pinfo("========================================================================\n");
284 if (is_laptop == 1) {
Nico Huberc3b02dc2023-08-12 01:13:45 +0200285 msg_pinfo("You seem to be running flashprog on an unknown laptop. Some\n"
Nico Huber2e50cdc2018-09-23 20:20:26 +0200286 "internal buses have been disabled for safety reasons.\n\n");
287 } else {
Nico Huberc3b02dc2023-08-12 01:13:45 +0200288 msg_pinfo("You may be running flashprog on an unknown laptop. We could not\n"
Nico Huber2e50cdc2018-09-23 20:20:26 +0200289 "detect this for sure because your vendor has not set up the SMBIOS\n"
290 "tables correctly. Some internal buses have been disabled for\n"
291 "safety reasons. You can enforce using all buses by adding\n"
292 " -p internal:laptop=this_is_not_a_laptop\n"
293 "to the command line, but please read the following warning if you\n"
294 "are not sure.\n\n");
295 }
296 msg_perr("Laptops, notebooks and netbooks are difficult to support and we\n"
297 "recommend to use the vendor flashing utility. The embedded controller\n"
298 "(EC) in these machines often interacts badly with flashing.\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200299 "See the manpage and https://flashprog.org/Laptops for details.\n\n"
Nico Huber2e50cdc2018-09-23 20:20:26 +0200300 "If flash is shared with the EC, erase is guaranteed to brick your laptop\n"
301 "and write may brick your laptop.\n"
302 "Read and probe may irritate your EC and cause fan failure, backlight\n"
303 "failure and sudden poweroff.\n"
304 "You have been warned.\n"
305 "========================================================================\n");
306 }
307
Jacob Garber1c091d12019-08-12 11:14:14 -0600308 ret = 0;
309
310internal_init_exit:
311 free(board_vendor);
312 free(board_model);
313
314 return ret;
Carl-Daniel Hailfinger702218d2009-05-08 17:43:22 +0000315}
Carl-Daniel Hailfinger702218d2009-05-08 17:43:22 +0000316
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000317static void internal_chip_writeb(const struct flashctx *flash, uint8_t val,
318 chipaddr addr)
Carl-Daniel Hailfinger702218d2009-05-08 17:43:22 +0000319{
Carl-Daniel Hailfinger78185dc2009-05-17 15:49:24 +0000320 mmio_writeb(val, (void *) addr);
Carl-Daniel Hailfinger702218d2009-05-08 17:43:22 +0000321}
322
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000323static void internal_chip_writew(const struct flashctx *flash, uint16_t val,
324 chipaddr addr)
Carl-Daniel Hailfinger702218d2009-05-08 17:43:22 +0000325{
Carl-Daniel Hailfinger78185dc2009-05-17 15:49:24 +0000326 mmio_writew(val, (void *) addr);
Carl-Daniel Hailfinger702218d2009-05-08 17:43:22 +0000327}
328
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000329static void internal_chip_writel(const struct flashctx *flash, uint32_t val,
330 chipaddr addr)
Carl-Daniel Hailfinger702218d2009-05-08 17:43:22 +0000331{
Carl-Daniel Hailfinger78185dc2009-05-17 15:49:24 +0000332 mmio_writel(val, (void *) addr);
Carl-Daniel Hailfinger702218d2009-05-08 17:43:22 +0000333}
334
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000335static uint8_t internal_chip_readb(const struct flashctx *flash,
336 const chipaddr addr)
Carl-Daniel Hailfinger702218d2009-05-08 17:43:22 +0000337{
Carl-Daniel Hailfinger78185dc2009-05-17 15:49:24 +0000338 return mmio_readb((void *) addr);
Carl-Daniel Hailfinger702218d2009-05-08 17:43:22 +0000339}
340
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000341static uint16_t internal_chip_readw(const struct flashctx *flash,
342 const chipaddr addr)
Carl-Daniel Hailfinger702218d2009-05-08 17:43:22 +0000343{
Carl-Daniel Hailfinger78185dc2009-05-17 15:49:24 +0000344 return mmio_readw((void *) addr);
Carl-Daniel Hailfinger702218d2009-05-08 17:43:22 +0000345}
346
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000347static uint32_t internal_chip_readl(const struct flashctx *flash,
348 const chipaddr addr)
Carl-Daniel Hailfinger702218d2009-05-08 17:43:22 +0000349{
Carl-Daniel Hailfinger78185dc2009-05-17 15:49:24 +0000350 return mmio_readl((void *) addr);
351}
352
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000353static void internal_chip_readn(const struct flashctx *flash, uint8_t *buf,
354 const chipaddr addr, size_t len)
Carl-Daniel Hailfinger0bd2a2b2009-06-05 18:32:07 +0000355{
Carl-Daniel Hailfingerccd71c22012-03-01 22:38:27 +0000356 mmio_readn((void *)addr, buf, len);
Carl-Daniel Hailfinger0bd2a2b2009-06-05 18:32:07 +0000357 return;
358}
Thomas Heijligencc853d82021-05-04 15:32:17 +0200359
360const struct programmer_entry programmer_internal = {
361 .name = "internal",
362 .type = OTHER,
363 .devs.note = NULL,
364 .init = internal_init,
365 .map_flash_region = physmap,
366 .unmap_flash_region = physunmap,
Thomas Heijligencc853d82021-05-04 15:32:17 +0200367};