@@ -2096,6 +2096,36 @@ spi_nor_set_pp_settings(struct spi_nor_pp_command *pp,
20962096 * Serial Flash Discoverable Parameters (SFDP) parsing.
20972097 */
20982098
2099+ /**
2100+ * spi_nor_read_raw() - raw read of serial flash memory. read_opcode,
2101+ * addr_width and read_dummy members of the struct spi_nor
2102+ * should be previously
2103+ * set.
2104+ * @nor: pointer to a 'struct spi_nor'
2105+ * @addr: offset in the serial flash memory
2106+ * @len: number of bytes to read
2107+ * @buf: buffer where the data is copied into
2108+ *
2109+ * Return: 0 on success, -errno otherwise.
2110+ */
2111+ static int spi_nor_read_raw (struct spi_nor * nor , u32 addr , size_t len , u8 * buf )
2112+ {
2113+ int ret ;
2114+
2115+ while (len ) {
2116+ ret = nor -> read (nor , addr , len , buf );
2117+ if (!ret || ret > len )
2118+ return - EIO ;
2119+ if (ret < 0 )
2120+ return ret ;
2121+
2122+ buf += ret ;
2123+ addr += ret ;
2124+ len -= ret ;
2125+ }
2126+ return 0 ;
2127+ }
2128+
20992129/**
21002130 * spi_nor_read_sfdp() - read Serial Flash Discoverable Parameters.
21012131 * @nor: pointer to a 'struct spi_nor'
@@ -2123,22 +2153,8 @@ static int spi_nor_read_sfdp(struct spi_nor *nor, u32 addr,
21232153 nor -> addr_width = 3 ;
21242154 nor -> read_dummy = 8 ;
21252155
2126- while (len ) {
2127- ret = nor -> read (nor , addr , len , (u8 * )buf );
2128- if (!ret || ret > len ) {
2129- ret = - EIO ;
2130- goto read_err ;
2131- }
2132- if (ret < 0 )
2133- goto read_err ;
2134-
2135- buf += ret ;
2136- addr += ret ;
2137- len -= ret ;
2138- }
2139- ret = 0 ;
2156+ ret = spi_nor_read_raw (nor , addr , len , buf );
21402157
2141- read_err :
21422158 nor -> read_opcode = read_opcode ;
21432159 nor -> addr_width = addr_width ;
21442160 nor -> read_dummy = read_dummy ;
@@ -2698,6 +2714,277 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
26982714 return 0 ;
26992715}
27002716
2717+ #define SMPT_CMD_ADDRESS_LEN_MASK GENMASK(23, 22)
2718+ #define SMPT_CMD_ADDRESS_LEN_0 (0x0UL << 22)
2719+ #define SMPT_CMD_ADDRESS_LEN_3 (0x1UL << 22)
2720+ #define SMPT_CMD_ADDRESS_LEN_4 (0x2UL << 22)
2721+ #define SMPT_CMD_ADDRESS_LEN_USE_CURRENT (0x3UL << 22)
2722+
2723+ #define SMPT_CMD_READ_DUMMY_MASK GENMASK(19, 16)
2724+ #define SMPT_CMD_READ_DUMMY_SHIFT 16
2725+ #define SMPT_CMD_READ_DUMMY (_cmd ) \
2726+ (((_cmd) & SMPT_CMD_READ_DUMMY_MASK) >> SMPT_CMD_READ_DUMMY_SHIFT)
2727+ #define SMPT_CMD_READ_DUMMY_IS_VARIABLE 0xfUL
2728+
2729+ #define SMPT_CMD_READ_DATA_MASK GENMASK(31, 24)
2730+ #define SMPT_CMD_READ_DATA_SHIFT 24
2731+ #define SMPT_CMD_READ_DATA (_cmd ) \
2732+ (((_cmd) & SMPT_CMD_READ_DATA_MASK) >> SMPT_CMD_READ_DATA_SHIFT)
2733+
2734+ #define SMPT_CMD_OPCODE_MASK GENMASK(15, 8)
2735+ #define SMPT_CMD_OPCODE_SHIFT 8
2736+ #define SMPT_CMD_OPCODE (_cmd ) \
2737+ (((_cmd) & SMPT_CMD_OPCODE_MASK) >> SMPT_CMD_OPCODE_SHIFT)
2738+
2739+ #define SMPT_MAP_REGION_COUNT_MASK GENMASK(23, 16)
2740+ #define SMPT_MAP_REGION_COUNT_SHIFT 16
2741+ #define SMPT_MAP_REGION_COUNT (_header ) \
2742+ ((((_header) & SMPT_MAP_REGION_COUNT_MASK) >> \
2743+ SMPT_MAP_REGION_COUNT_SHIFT) + 1)
2744+
2745+ #define SMPT_MAP_ID_MASK GENMASK(15, 8)
2746+ #define SMPT_MAP_ID_SHIFT 8
2747+ #define SMPT_MAP_ID (_header ) \
2748+ (((_header) & SMPT_MAP_ID_MASK) >> SMPT_MAP_ID_SHIFT)
2749+
2750+ #define SMPT_MAP_REGION_SIZE_MASK GENMASK(31, 8)
2751+ #define SMPT_MAP_REGION_SIZE_SHIFT 8
2752+ #define SMPT_MAP_REGION_SIZE (_region ) \
2753+ (((((_region) & SMPT_MAP_REGION_SIZE_MASK) >> \
2754+ SMPT_MAP_REGION_SIZE_SHIFT) + 1) * 256)
2755+
2756+ #define SMPT_MAP_REGION_ERASE_TYPE_MASK GENMASK(3, 0)
2757+ #define SMPT_MAP_REGION_ERASE_TYPE (_region ) \
2758+ ((_region) & SMPT_MAP_REGION_ERASE_TYPE_MASK)
2759+
2760+ #define SMPT_DESC_TYPE_MAP BIT(1)
2761+ #define SMPT_DESC_END BIT(0)
2762+
2763+ /**
2764+ * spi_nor_smpt_addr_width() - return the address width used in the
2765+ * configuration detection command.
2766+ * @nor: pointer to a 'struct spi_nor'
2767+ * @settings: configuration detection command descriptor, dword1
2768+ */
2769+ static u8 spi_nor_smpt_addr_width (const struct spi_nor * nor , const u32 settings )
2770+ {
2771+ switch (settings & SMPT_CMD_ADDRESS_LEN_MASK ) {
2772+ case SMPT_CMD_ADDRESS_LEN_0 :
2773+ return 0 ;
2774+ case SMPT_CMD_ADDRESS_LEN_3 :
2775+ return 3 ;
2776+ case SMPT_CMD_ADDRESS_LEN_4 :
2777+ return 4 ;
2778+ case SMPT_CMD_ADDRESS_LEN_USE_CURRENT :
2779+ /* fall through */
2780+ default :
2781+ return nor -> addr_width ;
2782+ }
2783+ }
2784+
2785+ /**
2786+ * spi_nor_smpt_read_dummy() - return the configuration detection command read
2787+ * latency, in clock cycles.
2788+ * @nor: pointer to a 'struct spi_nor'
2789+ * @settings: configuration detection command descriptor, dword1
2790+ *
2791+ * Return: the number of dummy cycles for an SMPT read
2792+ */
2793+ static u8 spi_nor_smpt_read_dummy (const struct spi_nor * nor , const u32 settings )
2794+ {
2795+ u8 read_dummy = SMPT_CMD_READ_DUMMY (settings );
2796+
2797+ if (read_dummy == SMPT_CMD_READ_DUMMY_IS_VARIABLE )
2798+ return nor -> read_dummy ;
2799+ return read_dummy ;
2800+ }
2801+
2802+ /**
2803+ * spi_nor_get_map_in_use() - get the configuration map in use
2804+ * @nor: pointer to a 'struct spi_nor'
2805+ * @smpt: pointer to the sector map parameter table
2806+ */
2807+ static const u32 * spi_nor_get_map_in_use (struct spi_nor * nor , const u32 * smpt )
2808+ {
2809+ const u32 * ret = NULL ;
2810+ u32 i , addr ;
2811+ int err ;
2812+ u8 addr_width , read_opcode , read_dummy ;
2813+ u8 read_data_mask , data_byte , map_id ;
2814+
2815+ addr_width = nor -> addr_width ;
2816+ read_dummy = nor -> read_dummy ;
2817+ read_opcode = nor -> read_opcode ;
2818+
2819+ map_id = 0 ;
2820+ i = 0 ;
2821+ /* Determine if there are any optional Detection Command Descriptors */
2822+ while (!(smpt [i ] & SMPT_DESC_TYPE_MAP )) {
2823+ read_data_mask = SMPT_CMD_READ_DATA (smpt [i ]);
2824+ nor -> addr_width = spi_nor_smpt_addr_width (nor , smpt [i ]);
2825+ nor -> read_dummy = spi_nor_smpt_read_dummy (nor , smpt [i ]);
2826+ nor -> read_opcode = SMPT_CMD_OPCODE (smpt [i ]);
2827+ addr = smpt [i + 1 ];
2828+
2829+ err = spi_nor_read_raw (nor , addr , 1 , & data_byte );
2830+ if (err )
2831+ goto out ;
2832+
2833+ /*
2834+ * Build an index value that is used to select the Sector Map
2835+ * Configuration that is currently in use.
2836+ */
2837+ map_id = map_id << 1 | !!(data_byte & read_data_mask );
2838+ i = i + 2 ;
2839+ }
2840+
2841+ /* Find the matching configuration map */
2842+ while (SMPT_MAP_ID (smpt [i ]) != map_id ) {
2843+ if (smpt [i ] & SMPT_DESC_END )
2844+ goto out ;
2845+ /* increment the table index to the next map */
2846+ i += SMPT_MAP_REGION_COUNT (smpt [i ]) + 1 ;
2847+ }
2848+
2849+ ret = smpt + i ;
2850+ /* fall through */
2851+ out :
2852+ nor -> addr_width = addr_width ;
2853+ nor -> read_dummy = read_dummy ;
2854+ nor -> read_opcode = read_opcode ;
2855+ return ret ;
2856+ }
2857+
2858+ /**
2859+ * spi_nor_region_check_overlay() - set overlay bit when the region is overlaid
2860+ * @region: pointer to a structure that describes a SPI NOR erase region
2861+ * @erase: pointer to a structure that describes a SPI NOR erase type
2862+ * @erase_type: erase type bitmask
2863+ */
2864+ static void
2865+ spi_nor_region_check_overlay (struct spi_nor_erase_region * region ,
2866+ const struct spi_nor_erase_type * erase ,
2867+ const u8 erase_type )
2868+ {
2869+ int i ;
2870+
2871+ for (i = 0 ; i < SNOR_ERASE_TYPE_MAX ; i ++ ) {
2872+ if (!(erase_type & BIT (i )))
2873+ continue ;
2874+ if (region -> size & erase [i ].size_mask ) {
2875+ spi_nor_region_mark_overlay (region );
2876+ return ;
2877+ }
2878+ }
2879+ }
2880+
2881+ /**
2882+ * spi_nor_init_non_uniform_erase_map() - initialize the non-uniform erase map
2883+ * @nor: pointer to a 'struct spi_nor'
2884+ * @smpt: pointer to the sector map parameter table
2885+ *
2886+ * Return: 0 on success, -errno otherwise.
2887+ */
2888+ static int spi_nor_init_non_uniform_erase_map (struct spi_nor * nor ,
2889+ const u32 * smpt )
2890+ {
2891+ struct spi_nor_erase_map * map = & nor -> erase_map ;
2892+ const struct spi_nor_erase_type * erase = map -> erase_type ;
2893+ struct spi_nor_erase_region * region ;
2894+ u64 offset ;
2895+ u32 region_count ;
2896+ int i , j ;
2897+ u8 erase_type ;
2898+
2899+ region_count = SMPT_MAP_REGION_COUNT (* smpt );
2900+ /*
2901+ * The regions will be freed when the driver detaches from the
2902+ * device.
2903+ */
2904+ region = devm_kcalloc (nor -> dev , region_count , sizeof (* region ),
2905+ GFP_KERNEL );
2906+ if (!region )
2907+ return - ENOMEM ;
2908+ map -> regions = region ;
2909+
2910+ map -> uniform_erase_type = 0xff ;
2911+ offset = 0 ;
2912+ /* Populate regions. */
2913+ for (i = 0 ; i < region_count ; i ++ ) {
2914+ j = i + 1 ; /* index for the region dword */
2915+ region [i ].size = SMPT_MAP_REGION_SIZE (smpt [j ]);
2916+ erase_type = SMPT_MAP_REGION_ERASE_TYPE (smpt [j ]);
2917+ region [i ].offset = offset | erase_type ;
2918+
2919+ spi_nor_region_check_overlay (& region [i ], erase , erase_type );
2920+
2921+ /*
2922+ * Save the erase types that are supported in all regions and
2923+ * can erase the entire flash memory.
2924+ */
2925+ map -> uniform_erase_type &= erase_type ;
2926+
2927+ offset = (region [i ].offset & ~SNOR_ERASE_FLAGS_MASK ) +
2928+ region [i ].size ;
2929+ }
2930+
2931+ spi_nor_region_mark_end (& region [i - 1 ]);
2932+
2933+ return 0 ;
2934+ }
2935+
2936+ /**
2937+ * spi_nor_parse_smpt() - parse Sector Map Parameter Table
2938+ * @nor: pointer to a 'struct spi_nor'
2939+ * @smpt_header: sector map parameter table header
2940+ *
2941+ * This table is optional, but when available, we parse it to identify the
2942+ * location and size of sectors within the main data array of the flash memory
2943+ * device and to identify which Erase Types are supported by each sector.
2944+ *
2945+ * Return: 0 on success, -errno otherwise.
2946+ */
2947+ static int spi_nor_parse_smpt (struct spi_nor * nor ,
2948+ const struct sfdp_parameter_header * smpt_header )
2949+ {
2950+ const u32 * sector_map ;
2951+ u32 * smpt ;
2952+ size_t len ;
2953+ u32 addr ;
2954+ int i , ret ;
2955+
2956+ /* Read the Sector Map Parameter Table. */
2957+ len = smpt_header -> length * sizeof (* smpt );
2958+ smpt = kzalloc (len , GFP_KERNEL );
2959+ if (!smpt )
2960+ return - ENOMEM ;
2961+
2962+ addr = SFDP_PARAM_HEADER_PTP (smpt_header );
2963+ ret = spi_nor_read_sfdp (nor , addr , len , smpt );
2964+ if (ret )
2965+ goto out ;
2966+
2967+ /* Fix endianness of the SMPT DWORDs. */
2968+ for (i = 0 ; i < smpt_header -> length ; i ++ )
2969+ smpt [i ] = le32_to_cpu (smpt [i ]);
2970+
2971+ sector_map = spi_nor_get_map_in_use (nor , smpt );
2972+ if (!sector_map ) {
2973+ ret = - EINVAL ;
2974+ goto out ;
2975+ }
2976+
2977+ ret = spi_nor_init_non_uniform_erase_map (nor , sector_map );
2978+ if (ret )
2979+ goto out ;
2980+
2981+ spi_nor_regions_sort_erase_types (& nor -> erase_map );
2982+ /* fall through */
2983+ out :
2984+ kfree (smpt );
2985+ return ret ;
2986+ }
2987+
27012988/**
27022989 * spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters.
27032990 * @nor: pointer to a 'struct spi_nor'
@@ -2793,7 +3080,7 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor,
27933080
27943081 switch (SFDP_PARAM_HEADER_ID (param_header )) {
27953082 case SFDP_SECTOR_MAP_ID :
2796- dev_info ( dev , "non-uniform erase sector maps are not supported yet.\n" );
3083+ err = spi_nor_parse_smpt ( nor , param_header );
27973084 break ;
27983085
27993086 default :
0 commit comments