@@ -245,6 +245,110 @@ int sfdp_parse_headers(Callback<int(bd_addr_t, sfdp_cmd_addr_size_t, uint8_t, ui
245
245
return 0 ;
246
246
}
247
247
248
+ static constexpr size_t min_descriptor_size = 8 ; // two DWORDs
249
+
250
+ static inline bool is_last_descriptor (const uint8_t *descriptor)
251
+ {
252
+ // Last descriptor of the current type (detection command/sector map)
253
+ MBED_ASSERT (nullptr != descriptor);
254
+ return descriptor[0 ] & 0x01 ;
255
+ }
256
+
257
+ static inline bool is_sector_map_descriptor (const uint8_t *descriptor)
258
+ {
259
+ // true - sector map descriptor
260
+ // false - configuration detection command descriptor
261
+ MBED_ASSERT (nullptr != descriptor);
262
+ return descriptor[0 ] & 0x02 ;
263
+ }
264
+
265
+ static int sfdp_detect_sector_map_configuration (
266
+ Callback<int (bd_addr_t , sfdp_cmd_addr_size_t , uint8_t , uint8_t , void *, bd_size_t )> sfdp_reader,
267
+ sfdp_hdr_info &sfdp_info,
268
+ uint8_t *&descriptor,
269
+ const uint8_t *table_end,
270
+ uint8_t &config)
271
+ {
272
+ config = 0 ;
273
+
274
+ // If the table starts with a sector map descriptor instead of a configuration
275
+ // detection command descriptor, this device has only one configuration (i.e. is
276
+ // not configurable) with ID equal to 0.
277
+ if (is_sector_map_descriptor (descriptor)) {
278
+ return 0 ;
279
+ }
280
+
281
+ // Loop through all configuration detection descriptors and run detection commands
282
+ while (!is_sector_map_descriptor (descriptor) && (descriptor + min_descriptor_size <= table_end)) {
283
+ uint8_t instruction = descriptor[1 ];
284
+ uint8_t dummy_cycles = descriptor[2 ] & 0x0F ;
285
+ auto addr_size = static_cast <sfdp_cmd_addr_size_t >(descriptor[2 ] >> 6 );
286
+ uint8_t mask = descriptor[3 ];
287
+ uint32_t cmd_addr;
288
+ memcpy (&cmd_addr, &descriptor[4 ], sizeof (cmd_addr)); // last 32 bits of the descriptor
289
+
290
+ uint8_t rx;
291
+ int status = sfdp_reader (cmd_addr, addr_size, instruction, dummy_cycles, &rx, sizeof (rx));
292
+ if (status < 0 ) {
293
+ tr_error (" Sector Map: Configuration detection command failed" );
294
+ return -1 ;
295
+ }
296
+
297
+ // Shift existing bits to the left, so we can add the newly detected bit
298
+ config <<= 1 ;
299
+
300
+ // The mask may apply to any bit of rx, so we can't directly combine
301
+ // (rx & mask) with config. Instead, treat (rx & mask) as a boolean.
302
+ if (rx & mask) {
303
+ config |= 0x01 ;
304
+ }
305
+
306
+ if (is_last_descriptor (descriptor)) {
307
+ // We've processed the last configuration detection command descriptor
308
+ descriptor += min_descriptor_size; // Increment the descriptor for the caller
309
+ return 0 ;
310
+ }
311
+ descriptor += min_descriptor_size; // next descriptor
312
+ }
313
+
314
+ tr_error (" Sector Map: Incomplete configuration detection command descriptors" );
315
+ return -1 ;
316
+ }
317
+
318
+ static int sfdp_locate_sector_map_by_config (
319
+ const uint8_t config,
320
+ sfdp_hdr_info &sfdp_info,
321
+ uint8_t *&descriptor,
322
+ const uint8_t *table_end)
323
+ {
324
+ // The size of a sector map descriptor depends on the number of regions. Before
325
+ // the number of regions is calculated, use the minimum possible size in the a loop condition.
326
+ while (is_sector_map_descriptor (descriptor) && (descriptor + min_descriptor_size <= table_end)) {
327
+ size_t regions = descriptor[2 ] + 1 ; // Region ID starts at 0
328
+ size_t current_descriptor_size = (1 /* header*/ + regions) * 4 /* DWORD size*/ ;
329
+ if (descriptor + current_descriptor_size > table_end) {
330
+ tr_error (" Sector Map: Incomplete sector map descriptor at the end of the table" );
331
+ return -1 ;
332
+ }
333
+
334
+ if (descriptor[1 ] == config) {
335
+ // matching sector map found
336
+ return 0 ;
337
+ }
338
+
339
+ if (is_last_descriptor (descriptor)) {
340
+ // We've processed the last sector map descriptor
341
+ tr_error (" Sector Map: Failed to find a sector map that matches the current configuration" );
342
+ return -1 ;
343
+ }
344
+
345
+ descriptor += current_descriptor_size; // next descriptor
346
+ }
347
+
348
+ tr_error (" Sector Map: Incomplete sector map descriptors" );
349
+ return -1 ;
350
+ }
351
+
248
352
int sfdp_parse_sector_map_table (Callback<int (bd_addr_t , sfdp_cmd_addr_size_t , uint8_t , uint8_t , void *, bd_size_t )> sfdp_reader, sfdp_hdr_info &sfdp_info)
249
353
{
250
354
uint32_t tmp_region_size = 0 ;
@@ -268,7 +372,7 @@ int sfdp_parse_sector_map_table(Callback<int(bd_addr_t, sfdp_cmd_addr_size_t, ui
268
372
* - sector map configuration detection commands
269
373
* - configurations
270
374
* - regions in each configuration
271
- * is variable -> the size of this table is variable
375
+ * are variable -> the size of this table is variable
272
376
*/
273
377
auto smptbl_buff = std::unique_ptr<uint8_t []>(new (std::nothrow) uint8_t [sfdp_info.smptbl .size ]);
274
378
if (!smptbl_buff) {
@@ -291,27 +395,40 @@ int sfdp_parse_sector_map_table(Callback<int(bd_addr_t, sfdp_cmd_addr_size_t, ui
291
395
return -1 ;
292
396
}
293
397
294
- // Currently we support only Single Map Descriptor
295
- if (!((smptbl_buff[0 ] & 0x3 ) == 0x03 ) && (smptbl_buff[1 ] == 0x0 )) {
296
- tr_error (" Sector Map: Supporting Only Single Map Descriptor (not map commands)" );
297
- return -1 ;
398
+ uint8_t *table = smptbl_buff.get ();
399
+ uint8_t *descriptor = table;
400
+
401
+ // Detect which configuration is in use
402
+ uint8_t active_config_id = 0x00 ;
403
+ status = sfdp_detect_sector_map_configuration (sfdp_reader, sfdp_info, descriptor, table + sfdp_info.smptbl .size , active_config_id);
404
+ if (status != 0 ) {
405
+ tr_error (" Failed to detect sector map configuration" );
406
+ return status;
298
407
}
299
408
300
- sfdp_info.smptbl .region_cnt = smptbl_buff[2 ] + 1 ;
409
+ // Locate the sector map for the configuration
410
+ status = sfdp_locate_sector_map_by_config (active_config_id, sfdp_info, descriptor, table + sfdp_info.smptbl .size );
411
+ if (status != 0 ) {
412
+ tr_error (" Failed to locate a matching sector map" );
413
+ return status;
414
+ }
415
+
416
+ // Find the number of regions from the sector map
417
+ sfdp_info.smptbl .region_cnt = descriptor[2 ] + 1 ;
301
418
if (sfdp_info.smptbl .region_cnt > SFDP_SECTOR_MAP_MAX_REGIONS) {
302
419
tr_error (" Sector Map: Supporting up to %d regions, current setup to %d regions - fail" ,
303
420
SFDP_SECTOR_MAP_MAX_REGIONS,
304
421
sfdp_info.smptbl .region_cnt );
305
422
return -1 ;
306
423
}
307
424
308
- // Loop through Regions and set for each one: size, supported erase types, high boundary offset
309
- // Calculate minimum Common Erase Type for all Regions
425
+ // Loop through the regions and set for each one: size, supported erase types, high boundary offset
426
+ // Calculate the minimum common erase type for all regions
310
427
for (auto idx = 0 ; idx < sfdp_info.smptbl .region_cnt ; idx++) {
311
- tmp_region_size = ((*((uint32_t *)&smptbl_buff [(idx + 1 ) * 4 ])) >> 8 ) & 0x00FFFFFF ; // bits 9-32
428
+ tmp_region_size = ((*((uint32_t *)&descriptor [(idx + 1 ) * 4 ])) >> 8 ) & 0x00FFFFFF ; // bits 9-32
312
429
sfdp_info.smptbl .region_size [idx] = (tmp_region_size + 1 ) * 256 ; // Region size is 0 based multiple of 256 bytes;
313
430
314
- sfdp_info.smptbl .region_erase_types_bitfld [idx] = smptbl_buff [(idx + 1 ) * 4 ] & 0x0F ; // bits 1-4
431
+ sfdp_info.smptbl .region_erase_types_bitfld [idx] = descriptor [(idx + 1 ) * 4 ] & 0x0F ; // bits 1-4
315
432
316
433
min_common_erase_type_bits &= sfdp_info.smptbl .region_erase_types_bitfld [idx];
317
434
@@ -335,7 +452,6 @@ int sfdp_parse_sector_map_table(Callback<int(bd_addr_t, sfdp_cmd_addr_size_t, ui
335
452
return 0 ;
336
453
}
337
454
338
-
339
455
size_t sfdp_detect_page_size (uint8_t *basic_param_table_ptr, size_t basic_param_table_size)
340
456
{
341
457
constexpr int SFDP_BASIC_PARAM_TABLE_PAGE_SIZE = 40 ;
0 commit comments