@@ -2000,6 +2000,35 @@ spi_nor_set_pp_settings(struct spi_nor_pp_command *pp,
20002000 * Serial Flash Discoverable Parameters (SFDP) parsing.
20012001 */
20022002
2003+ /**
2004+ * spi_nor_read_raw() - raw read of serial flash memory. read_opcode,
2005+ * addr_width and read_dummy members of the struct spi_nor should be previously
2006+ * set.
2007+ * @nor: pointer to a 'struct spi_nor'
2008+ * @addr: offset in the serial flash memory
2009+ * @len: number of bytes to read
2010+ * @buf: buffer where the data is copied into
2011+ *
2012+ * Return: 0 on success, -errno otherwise.
2013+ */
2014+ static int spi_nor_read_raw (struct spi_nor * nor , u32 addr , size_t len , u8 * buf )
2015+ {
2016+ int ret ;
2017+
2018+ while (len ) {
2019+ ret = nor -> read (nor , addr , len , buf );
2020+ if (!ret || ret > len )
2021+ return - EIO ;
2022+ if (ret < 0 )
2023+ return ret ;
2024+
2025+ buf += ret ;
2026+ addr += ret ;
2027+ len -= ret ;
2028+ }
2029+ return 0 ;
2030+ }
2031+
20032032/**
20042033 * spi_nor_read_sfdp() - read Serial Flash Discoverable Parameters.
20052034 * @nor: pointer to a 'struct spi_nor'
@@ -2027,22 +2056,8 @@ static int spi_nor_read_sfdp(struct spi_nor *nor, u32 addr,
20272056 nor -> addr_width = 3 ;
20282057 nor -> read_dummy = 8 ;
20292058
2030- while (len ) {
2031- ret = nor -> read (nor , addr , len , (u8 * )buf );
2032- if (!ret || ret > len ) {
2033- ret = - EIO ;
2034- goto read_err ;
2035- }
2036- if (ret < 0 )
2037- goto read_err ;
2059+ ret = spi_nor_read_raw (nor , addr , len , buf );
20382060
2039- buf += ret ;
2040- addr += ret ;
2041- len -= ret ;
2042- }
2043- ret = 0 ;
2044-
2045- read_err :
20462061 nor -> read_opcode = read_opcode ;
20472062 nor -> addr_width = addr_width ;
20482063 nor -> read_dummy = read_dummy ;
@@ -2562,6 +2577,228 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
25622577 return 0 ;
25632578}
25642579
2580+ #define SMPT_CMD_ADDRESS_LEN_MASK GENMASK(23, 22)
2581+ #define SMPT_CMD_ADDRESS_LEN_0 (0x0UL << 22)
2582+ #define SMPT_CMD_ADDRESS_LEN_3 (0x1UL << 22)
2583+ #define SMPT_CMD_ADDRESS_LEN_4 (0x2UL << 22)
2584+ #define SMPT_CMD_ADDRESS_LEN_USE_CURRENT (0x3UL << 22)
2585+
2586+ #define SMPT_CMD_READ_DUMMY_MASK GENMASK(19, 16)
2587+ #define SMPT_CMD_READ_DUMMY_SHIFT 16
2588+ #define SMPT_CMD_READ_DUMMY (_cmd ) \
2589+ ((_cmd & SMPT_CMD_READ_DUMMY_MASK) >> SMPT_CMD_READ_DUMMY_SHIFT)
2590+ #define SMPT_CMD_READ_DUMMY_IS_VARIABLE 0xfUL
2591+
2592+ #define SMPT_CMD_READ_DATA_MASK GENMASK(31, 24)
2593+ #define SMPT_CMD_READ_DATA_SHIFT 24
2594+ #define SMPT_CMD_READ_DATA (_cmd ) \
2595+ ((_cmd & SMPT_CMD_READ_DATA_MASK) >> SMPT_CMD_READ_DATA_SHIFT)
2596+
2597+ #define SMPT_CMD_OPCODE_MASK GENMASK(15, 8)
2598+ #define SMPT_CMD_OPCODE_SHIFT 8
2599+ #define SMPT_CMD_OPCODE (_cmd ) \
2600+ ((_cmd & SMPT_CMD_OPCODE_MASK) >> SMPT_CMD_OPCODE_SHIFT)
2601+
2602+ #define SMPT_MAP_REGION_COUNT_MASK GENMASK(23, 16)
2603+ #define SMPT_MAP_REGION_COUNT_SHIFT 16
2604+ #define SMPT_MAP_REGION_COUNT (_header ) \
2605+ (((_header & SMPT_MAP_REGION_COUNT_MASK) >> \
2606+ SMPT_MAP_REGION_COUNT_SHIFT) + 1)
2607+
2608+ #define SMPT_MAP_ID_MASK GENMASK(15, 8)
2609+ #define SMPT_MAP_ID_SHIFT 8
2610+ #define SMPT_MAP_ID (_header ) ((_header & SMPT_MAP_ID_MASK) >> SMPT_MAP_ID_SHIFT)
2611+
2612+ #define SMPT_MAP_REGION_SIZE_MASK GENMASK(31, 8)
2613+ #define SMPT_MAP_REGION_SIZE_SHIFT 8
2614+ #define SMPT_MAP_REGION_SIZE (_region ) \
2615+ ((((_region & SMPT_MAP_REGION_SIZE_MASK) >> \
2616+ SMPT_MAP_REGION_SIZE_SHIFT) + 1) * 256)
2617+
2618+ #define SMPT_MAP_REGION_ERASE_TYPE_MASK GENMASK(3, 0)
2619+ #define SMPT_MAP_REGION_ERASE_TYPE (_region ) \
2620+ (_region & SMPT_MAP_REGION_ERASE_TYPE_MASK)
2621+
2622+ #define SMPT_DESC_TYPE_MAP BIT(1)
2623+ #define SMPT_DESC_END BIT(0)
2624+
2625+ static u8 spi_nor_smpt_addr_width (const struct spi_nor * nor , const u32 settings )
2626+ {
2627+ switch (settings & SMPT_CMD_ADDRESS_LEN_MASK ) {
2628+ case SMPT_CMD_ADDRESS_LEN_0 :
2629+ return 0 ;
2630+ case SMPT_CMD_ADDRESS_LEN_3 :
2631+ return 3 ;
2632+ case SMPT_CMD_ADDRESS_LEN_4 :
2633+ return 4 ;
2634+ case SMPT_CMD_ADDRESS_LEN_USE_CURRENT :
2635+ /* fall through */
2636+ default :
2637+ return nor -> addr_width ;
2638+ }
2639+ }
2640+
2641+ static u8 spi_nor_smpt_read_dummy (const struct spi_nor * nor , const u32 settings )
2642+ {
2643+ u8 read_dummy = SMPT_CMD_READ_DUMMY (settings );
2644+
2645+ if (read_dummy == SMPT_CMD_READ_DUMMY_IS_VARIABLE )
2646+ return nor -> read_dummy ;
2647+ return read_dummy ;
2648+ }
2649+
2650+ static const u32 * spi_nor_get_map_in_use (struct spi_nor * nor , const u32 * smpt )
2651+ {
2652+ const u32 * ret = NULL ;
2653+ u32 i , addr ;
2654+ int err ;
2655+ u8 addr_width , read_opcode , read_dummy ;
2656+ u8 read_data_mask , data_byte , map_id ;
2657+
2658+ addr_width = nor -> addr_width ;
2659+ read_dummy = nor -> read_dummy ;
2660+ read_opcode = nor -> read_opcode ;
2661+
2662+ map_id = 0 ;
2663+ i = 0 ;
2664+ /* Determine if there are any optional Detection Command Descriptors */
2665+ while (!(smpt [i ] & SMPT_DESC_TYPE_MAP )) {
2666+ read_data_mask = SMPT_CMD_READ_DATA (smpt [i ]);
2667+ nor -> addr_width = spi_nor_smpt_addr_width (nor , smpt [i ]);
2668+ nor -> read_dummy = spi_nor_smpt_read_dummy (nor , smpt [i ]);
2669+ nor -> read_opcode = SMPT_CMD_OPCODE (smpt [i ]);
2670+ addr = smpt [i + 1 ];
2671+
2672+ err = spi_nor_read_raw (nor , addr , 1 , & data_byte );
2673+ if (err )
2674+ goto out ;
2675+
2676+ /*
2677+ * Build an index value that is used to select the Sector Map
2678+ * Configuration that is currently in use.
2679+ */
2680+ map_id = map_id << 1 | (!(data_byte & read_data_mask ) ? 0 : 1 );
2681+ i = i + 2 ;
2682+ }
2683+
2684+ /* Find the matching configuration map */
2685+ while (SMPT_MAP_ID (smpt [i ]) != map_id ) {
2686+ if (smpt [i ] & SMPT_DESC_END )
2687+ goto out ;
2688+ /* increment the table index to the next map */
2689+ i += SMPT_MAP_REGION_COUNT (smpt [i ]) + 1 ;
2690+ }
2691+
2692+ ret = smpt + i ;
2693+ /* fall through */
2694+ out :
2695+ nor -> addr_width = addr_width ;
2696+ nor -> read_dummy = read_dummy ;
2697+ nor -> read_opcode = read_opcode ;
2698+ return ret ;
2699+ }
2700+
2701+ static void
2702+ spi_nor_region_check_overlay (struct spi_nor_erase_region * region ,
2703+ const struct spi_nor_erase_type * erase ,
2704+ const u8 erase_type )
2705+ {
2706+ int i ;
2707+
2708+ for (i = 0 ; i < SNOR_ERASE_TYPE_MAX ; i ++ ) {
2709+ if (!(erase_type & BIT (i )))
2710+ continue ;
2711+ if (region -> size & erase [i ].size_mask ) {
2712+ spi_nor_region_mark_overlay (region );
2713+ return ;
2714+ }
2715+ }
2716+ }
2717+
2718+ static int spi_nor_init_non_uniform_erase_map (struct spi_nor * nor ,
2719+ const u32 * smpt )
2720+ {
2721+ struct spi_nor_erase_map * map = & nor -> erase_map ;
2722+ const struct spi_nor_erase_type * erase = map -> erase_type ;
2723+ struct spi_nor_erase_region * region ;
2724+ u64 offset ;
2725+ u32 region_count ;
2726+ int i , j ;
2727+ u8 erase_type ;
2728+
2729+ region_count = SMPT_MAP_REGION_COUNT (* smpt );
2730+ region = devm_kcalloc (nor -> dev , region_count , sizeof (* region ),
2731+ GFP_KERNEL );
2732+ if (!region )
2733+ return - ENOMEM ;
2734+ map -> regions = region ;
2735+
2736+ map -> uniform_erase_type = 0xff ;
2737+ offset = 0 ;
2738+ for (i = 0 ; i < region_count ; i ++ ) {
2739+ j = i + 1 ; /* index for the region dword */
2740+ region [i ].size = SMPT_MAP_REGION_SIZE (smpt [j ]);
2741+ erase_type = SMPT_MAP_REGION_ERASE_TYPE (smpt [j ]);
2742+ region [i ].offset = offset | erase_type ;
2743+
2744+ spi_nor_region_check_overlay (& region [i ], erase , erase_type );
2745+
2746+ /*
2747+ * Save the erase types that are supported in all regions and
2748+ * can erase the entire flash memory.
2749+ */
2750+ map -> uniform_erase_type &= erase_type ;
2751+
2752+ offset = (region [i ].offset & ~SNOR_ERASE_FLAGS_MASK ) +
2753+ region [i ].size ;
2754+ }
2755+
2756+ spi_nor_region_mark_end (& region [i - 1 ]);
2757+
2758+ return 0 ;
2759+ }
2760+
2761+ static int spi_nor_parse_smpt (struct spi_nor * nor ,
2762+ const struct sfdp_parameter_header * smpt_header )
2763+ {
2764+ const u32 * sector_map ;
2765+ u32 * smpt ;
2766+ size_t len ;
2767+ u32 addr ;
2768+ int i , ret ;
2769+
2770+ /* Read the Sector Map Parameter Table. */
2771+ len = smpt_header -> length * sizeof (* smpt );
2772+ smpt = kzalloc (len , GFP_KERNEL );
2773+ if (!smpt )
2774+ return - ENOMEM ;
2775+
2776+ addr = SFDP_PARAM_HEADER_PTP (smpt_header );
2777+ ret = spi_nor_read_sfdp (nor , addr , len , smpt );
2778+ if (ret )
2779+ goto out ;
2780+
2781+ /* Fix endianness of the SMPT DWORDs. */
2782+ for (i = 0 ; i < smpt_header -> length ; i ++ )
2783+ smpt [i ] = le32_to_cpu (smpt [i ]);
2784+
2785+ sector_map = spi_nor_get_map_in_use (nor , smpt );
2786+ if (!sector_map ) {
2787+ ret = - EINVAL ;
2788+ goto out ;
2789+ }
2790+
2791+ ret = spi_nor_init_non_uniform_erase_map (nor , sector_map );
2792+ if (ret )
2793+ goto out ;
2794+
2795+ spi_nor_regions_sort_erase_types (& nor -> erase_map );
2796+ /* fall through */
2797+ out :
2798+ kfree (smpt );
2799+ return ret ;
2800+ }
2801+
25652802/**
25662803 * spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters.
25672804 * @nor: pointer to a 'struct spi_nor'
@@ -2657,7 +2894,7 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor,
26572894
26582895 switch (SFDP_PARAM_HEADER_ID (param_header )) {
26592896 case SFDP_SECTOR_MAP_ID :
2660- dev_info ( dev , "non-uniform erase sector maps are not supported yet.\n" );
2897+ err = spi_nor_parse_smpt ( nor , param_header );
26612898 break ;
26622899
26632900 default :
0 commit comments