@@ -245,6 +245,110 @@ int sfdp_parse_headers(Callback<int(bd_addr_t, sfdp_cmd_addr_size_t, uint8_t, ui
245245 return 0 ;
246246}
247247
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+
248352int 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)
249353{
250354 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
268372 * - sector map configuration detection commands
269373 * - configurations
270374 * - regions in each configuration
271- * is variable -> the size of this table is variable
375+ * are variable -> the size of this table is variable
272376 */
273377 auto smptbl_buff = std::unique_ptr<uint8_t []>(new (std::nothrow) uint8_t [sfdp_info.smptbl .size ]);
274378 if (!smptbl_buff) {
@@ -291,27 +395,40 @@ int sfdp_parse_sector_map_table(Callback<int(bd_addr_t, sfdp_cmd_addr_size_t, ui
291395 return -1 ;
292396 }
293397
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;
298407 }
299408
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 ;
301418 if (sfdp_info.smptbl .region_cnt > SFDP_SECTOR_MAP_MAX_REGIONS) {
302419 tr_error (" Sector Map: Supporting up to %d regions, current setup to %d regions - fail" ,
303420 SFDP_SECTOR_MAP_MAX_REGIONS,
304421 sfdp_info.smptbl .region_cnt );
305422 return -1 ;
306423 }
307424
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
310427 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
312429 sfdp_info.smptbl .region_size [idx] = (tmp_region_size + 1 ) * 256 ; // Region size is 0 based multiple of 256 bytes;
313430
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
315432
316433 min_common_erase_type_bits &= sfdp_info.smptbl .region_erase_types_bitfld [idx];
317434
@@ -335,7 +452,6 @@ int sfdp_parse_sector_map_table(Callback<int(bd_addr_t, sfdp_cmd_addr_size_t, ui
335452 return 0 ;
336453}
337454
338-
339455size_t sfdp_detect_page_size (uint8_t *basic_param_table_ptr, size_t basic_param_table_size)
340456{
341457 constexpr int SFDP_BASIC_PARAM_TABLE_PAGE_SIZE = 40 ;
0 commit comments