8080#define DISABLE_STATUS_AFTER_WRITE 4
8181#define CW_PER_PAGE 6
8282#define UD_SIZE_BYTES 9
83+ #define UD_SIZE_BYTES_MASK GENMASK(18, 9)
8384#define ECC_PARITY_SIZE_BYTES_RS 19
8485#define SPARE_SIZE_BYTES 23
86+ #define SPARE_SIZE_BYTES_MASK GENMASK(26, 23)
8587#define NUM_ADDR_CYCLES 27
8688#define STATUS_BFR_READ 30
8789#define SET_RD_MODE_AFTER_STATUS 31
102104#define ECC_MODE 4
103105#define ECC_PARITY_SIZE_BYTES_BCH 8
104106#define ECC_NUM_DATA_BYTES 16
107+ #define ECC_NUM_DATA_BYTES_MASK GENMASK(25, 16)
105108#define ECC_FORCE_CLK_OPEN 30
106109
107110/* NAND_DEV_CMD1 bits */
@@ -431,13 +434,32 @@ struct qcom_nand_controller {
431434 u32 cmd1 , vld ;
432435};
433436
437+ /*
438+ * NAND special boot partitions
439+ *
440+ * @page_offset: offset of the partition where spare data is not protected
441+ * by ECC (value in pages)
442+ * @page_offset: size of the partition where spare data is not protected
443+ * by ECC (value in pages)
444+ */
445+ struct qcom_nand_boot_partition {
446+ u32 page_offset ;
447+ u32 page_size ;
448+ };
449+
434450/*
435451 * NAND chip structure
436452 *
453+ * @boot_partitions: array of boot partitions where offset and size of the
454+ * boot partitions are stored
455+ *
437456 * @chip: base NAND chip structure
438457 * @node: list node to add itself to host_list in
439458 * qcom_nand_controller
440459 *
460+ * @nr_boot_partitions: count of the boot partitions where spare data is not
461+ * protected by ECC
462+ *
441463 * @cs: chip select value for this chip
442464 * @cw_size: the number of bytes in a single step/codeword
443465 * of a page, consisting of all data, ecc, spare
@@ -456,14 +478,20 @@ struct qcom_nand_controller {
456478 *
457479 * @status: value to be returned if NAND_CMD_STATUS command
458480 * is executed
481+ * @codeword_fixup: keep track of the current layout used by
482+ * the driver for read/write operation.
459483 * @use_ecc: request the controller to use ECC for the
460484 * upcoming read/write
461485 * @bch_enabled: flag to tell whether BCH ECC mode is used
462486 */
463487struct qcom_nand_host {
488+ struct qcom_nand_boot_partition * boot_partitions ;
489+
464490 struct nand_chip chip ;
465491 struct list_head node ;
466492
493+ int nr_boot_partitions ;
494+
467495 int cs ;
468496 int cw_size ;
469497 int cw_data ;
@@ -481,6 +509,7 @@ struct qcom_nand_host {
481509 u32 clrreadstatus ;
482510
483511 u8 status ;
512+ bool codeword_fixup ;
484513 bool use_ecc ;
485514 bool bch_enabled ;
486515};
@@ -493,13 +522,15 @@ struct qcom_nand_host {
493522 * @is_bam - whether NAND controller is using BAM
494523 * @is_qpic - whether NAND CTRL is part of qpic IP
495524 * @qpic_v2 - flag to indicate QPIC IP version 2
525+ * @use_codeword_fixup - whether NAND has different layout for boot partitions
496526 */
497527struct qcom_nandc_props {
498528 u32 ecc_modes ;
499529 u32 dev_cmd_reg_start ;
500530 bool is_bam ;
501531 bool is_qpic ;
502532 bool qpic_v2 ;
533+ bool use_codeword_fixup ;
503534};
504535
505536/* Frees the BAM transaction memory */
@@ -1718,7 +1749,7 @@ qcom_nandc_read_cw_raw(struct mtd_info *mtd, struct nand_chip *chip,
17181749 data_size1 = mtd -> writesize - host -> cw_size * (ecc -> steps - 1 );
17191750 oob_size1 = host -> bbm_size ;
17201751
1721- if (qcom_nandc_is_last_cw (ecc , cw )) {
1752+ if (qcom_nandc_is_last_cw (ecc , cw ) && ! host -> codeword_fixup ) {
17221753 data_size2 = ecc -> size - data_size1 -
17231754 ((ecc -> steps - 1 ) * 4 );
17241755 oob_size2 = (ecc -> steps * 4 ) + host -> ecc_bytes_hw +
@@ -1799,7 +1830,7 @@ check_for_erased_page(struct qcom_nand_host *host, u8 *data_buf,
17991830 }
18001831
18011832 for_each_set_bit (cw , & uncorrectable_cws , ecc -> steps ) {
1802- if (qcom_nandc_is_last_cw (ecc , cw )) {
1833+ if (qcom_nandc_is_last_cw (ecc , cw ) && ! host -> codeword_fixup ) {
18031834 data_size = ecc -> size - ((ecc -> steps - 1 ) * 4 );
18041835 oob_size = (ecc -> steps * 4 ) + host -> ecc_bytes_hw ;
18051836 } else {
@@ -1957,7 +1988,7 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf,
19571988 for (i = 0 ; i < ecc -> steps ; i ++ ) {
19581989 int data_size , oob_size ;
19591990
1960- if (qcom_nandc_is_last_cw (ecc , i )) {
1991+ if (qcom_nandc_is_last_cw (ecc , i ) && ! host -> codeword_fixup ) {
19611992 data_size = ecc -> size - ((ecc -> steps - 1 ) << 2 );
19621993 oob_size = (ecc -> steps << 2 ) + host -> ecc_bytes_hw +
19631994 host -> spare_bytes ;
@@ -2054,6 +2085,69 @@ static int copy_last_cw(struct qcom_nand_host *host, int page)
20542085 return ret ;
20552086}
20562087
2088+ static bool qcom_nandc_is_boot_partition (struct qcom_nand_host * host , int page )
2089+ {
2090+ struct qcom_nand_boot_partition * boot_partition ;
2091+ u32 start , end ;
2092+ int i ;
2093+
2094+ /*
2095+ * Since the frequent access will be to the non-boot partitions like rootfs,
2096+ * optimize the page check by:
2097+ *
2098+ * 1. Checking if the page lies after the last boot partition.
2099+ * 2. Checking from the boot partition end.
2100+ */
2101+
2102+ /* First check the last boot partition */
2103+ boot_partition = & host -> boot_partitions [host -> nr_boot_partitions - 1 ];
2104+ start = boot_partition -> page_offset ;
2105+ end = start + boot_partition -> page_size ;
2106+
2107+ /* Page is after the last boot partition end. This is NOT a boot partition */
2108+ if (page > end )
2109+ return false;
2110+
2111+ /* Actually check if it's a boot partition */
2112+ if (page < end && page >= start )
2113+ return true;
2114+
2115+ /* Check the other boot partitions starting from the second-last partition */
2116+ for (i = host -> nr_boot_partitions - 2 ; i >= 0 ; i -- ) {
2117+ boot_partition = & host -> boot_partitions [i ];
2118+ start = boot_partition -> page_offset ;
2119+ end = start + boot_partition -> page_size ;
2120+
2121+ if (page < end && page >= start )
2122+ return true;
2123+ }
2124+
2125+ return false;
2126+ }
2127+
2128+ static void qcom_nandc_codeword_fixup (struct qcom_nand_host * host , int page )
2129+ {
2130+ bool codeword_fixup = qcom_nandc_is_boot_partition (host , page );
2131+
2132+ /* Skip conf write if we are already in the correct mode */
2133+ if (codeword_fixup == host -> codeword_fixup )
2134+ return ;
2135+
2136+ host -> codeword_fixup = codeword_fixup ;
2137+
2138+ host -> cw_data = codeword_fixup ? 512 : 516 ;
2139+ host -> spare_bytes = host -> cw_size - host -> ecc_bytes_hw -
2140+ host -> bbm_size - host -> cw_data ;
2141+
2142+ host -> cfg0 &= ~(SPARE_SIZE_BYTES_MASK | UD_SIZE_BYTES_MASK );
2143+ host -> cfg0 |= host -> spare_bytes << SPARE_SIZE_BYTES |
2144+ host -> cw_data << UD_SIZE_BYTES ;
2145+
2146+ host -> ecc_bch_cfg &= ~ECC_NUM_DATA_BYTES_MASK ;
2147+ host -> ecc_bch_cfg |= host -> cw_data << ECC_NUM_DATA_BYTES ;
2148+ host -> ecc_buf_cfg = (host -> cw_data - 1 ) << NUM_STEPS ;
2149+ }
2150+
20572151/* implements ecc->read_page() */
20582152static int qcom_nandc_read_page (struct nand_chip * chip , uint8_t * buf ,
20592153 int oob_required , int page )
@@ -2062,6 +2156,9 @@ static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf,
20622156 struct qcom_nand_controller * nandc = get_qcom_nand_controller (chip );
20632157 u8 * data_buf , * oob_buf = NULL ;
20642158
2159+ if (host -> nr_boot_partitions )
2160+ qcom_nandc_codeword_fixup (host , page );
2161+
20652162 nand_read_page_op (chip , page , 0 , NULL , 0 );
20662163 data_buf = buf ;
20672164 oob_buf = oob_required ? chip -> oob_poi : NULL ;
@@ -2081,6 +2178,9 @@ static int qcom_nandc_read_page_raw(struct nand_chip *chip, uint8_t *buf,
20812178 int cw , ret ;
20822179 u8 * data_buf = buf , * oob_buf = chip -> oob_poi ;
20832180
2181+ if (host -> nr_boot_partitions )
2182+ qcom_nandc_codeword_fixup (host , page );
2183+
20842184 for (cw = 0 ; cw < ecc -> steps ; cw ++ ) {
20852185 ret = qcom_nandc_read_cw_raw (mtd , chip , data_buf , oob_buf ,
20862186 page , cw );
@@ -2101,6 +2201,9 @@ static int qcom_nandc_read_oob(struct nand_chip *chip, int page)
21012201 struct qcom_nand_controller * nandc = get_qcom_nand_controller (chip );
21022202 struct nand_ecc_ctrl * ecc = & chip -> ecc ;
21032203
2204+ if (host -> nr_boot_partitions )
2205+ qcom_nandc_codeword_fixup (host , page );
2206+
21042207 clear_read_regs (nandc );
21052208 clear_bam_transaction (nandc );
21062209
@@ -2121,6 +2224,9 @@ static int qcom_nandc_write_page(struct nand_chip *chip, const uint8_t *buf,
21212224 u8 * data_buf , * oob_buf ;
21222225 int i , ret ;
21232226
2227+ if (host -> nr_boot_partitions )
2228+ qcom_nandc_codeword_fixup (host , page );
2229+
21242230 nand_prog_page_begin_op (chip , page , 0 , NULL , 0 );
21252231
21262232 clear_read_regs (nandc );
@@ -2136,7 +2242,7 @@ static int qcom_nandc_write_page(struct nand_chip *chip, const uint8_t *buf,
21362242 for (i = 0 ; i < ecc -> steps ; i ++ ) {
21372243 int data_size , oob_size ;
21382244
2139- if (qcom_nandc_is_last_cw (ecc , i )) {
2245+ if (qcom_nandc_is_last_cw (ecc , i ) && ! host -> codeword_fixup ) {
21402246 data_size = ecc -> size - ((ecc -> steps - 1 ) << 2 );
21412247 oob_size = (ecc -> steps << 2 ) + host -> ecc_bytes_hw +
21422248 host -> spare_bytes ;
@@ -2193,6 +2299,9 @@ static int qcom_nandc_write_page_raw(struct nand_chip *chip,
21932299 u8 * data_buf , * oob_buf ;
21942300 int i , ret ;
21952301
2302+ if (host -> nr_boot_partitions )
2303+ qcom_nandc_codeword_fixup (host , page );
2304+
21962305 nand_prog_page_begin_op (chip , page , 0 , NULL , 0 );
21972306 clear_read_regs (nandc );
21982307 clear_bam_transaction (nandc );
@@ -2211,7 +2320,7 @@ static int qcom_nandc_write_page_raw(struct nand_chip *chip,
22112320 data_size1 = mtd -> writesize - host -> cw_size * (ecc -> steps - 1 );
22122321 oob_size1 = host -> bbm_size ;
22132322
2214- if (qcom_nandc_is_last_cw (ecc , i )) {
2323+ if (qcom_nandc_is_last_cw (ecc , i ) && ! host -> codeword_fixup ) {
22152324 data_size2 = ecc -> size - data_size1 -
22162325 ((ecc -> steps - 1 ) << 2 );
22172326 oob_size2 = (ecc -> steps << 2 ) + host -> ecc_bytes_hw +
@@ -2271,6 +2380,9 @@ static int qcom_nandc_write_oob(struct nand_chip *chip, int page)
22712380 int data_size , oob_size ;
22722381 int ret ;
22732382
2383+ if (host -> nr_boot_partitions )
2384+ qcom_nandc_codeword_fixup (host , page );
2385+
22742386 host -> use_ecc = true;
22752387 clear_bam_transaction (nandc );
22762388
@@ -2932,6 +3044,74 @@ static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
29323044
29333045static const char * const probes [] = { "cmdlinepart" , "ofpart" , "qcomsmem" , NULL };
29343046
3047+ static int qcom_nand_host_parse_boot_partitions (struct qcom_nand_controller * nandc ,
3048+ struct qcom_nand_host * host ,
3049+ struct device_node * dn )
3050+ {
3051+ struct nand_chip * chip = & host -> chip ;
3052+ struct mtd_info * mtd = nand_to_mtd (chip );
3053+ struct qcom_nand_boot_partition * boot_partition ;
3054+ struct device * dev = nandc -> dev ;
3055+ int partitions_count , i , j , ret ;
3056+
3057+ if (!of_find_property (dn , "qcom,boot-partitions" , NULL ))
3058+ return 0 ;
3059+
3060+ partitions_count = of_property_count_u32_elems (dn , "qcom,boot-partitions" );
3061+ if (partitions_count <= 0 ) {
3062+ dev_err (dev , "Error parsing boot partition\n" );
3063+ return partitions_count ? partitions_count : - EINVAL ;
3064+ }
3065+
3066+ host -> nr_boot_partitions = partitions_count / 2 ;
3067+ host -> boot_partitions = devm_kcalloc (dev , host -> nr_boot_partitions ,
3068+ sizeof (* host -> boot_partitions ), GFP_KERNEL );
3069+ if (!host -> boot_partitions ) {
3070+ host -> nr_boot_partitions = 0 ;
3071+ return - ENOMEM ;
3072+ }
3073+
3074+ for (i = 0 , j = 0 ; i < host -> nr_boot_partitions ; i ++ , j += 2 ) {
3075+ boot_partition = & host -> boot_partitions [i ];
3076+
3077+ ret = of_property_read_u32_index (dn , "qcom,boot-partitions" , j ,
3078+ & boot_partition -> page_offset );
3079+ if (ret ) {
3080+ dev_err (dev , "Error parsing boot partition offset at index %d\n" , i );
3081+ host -> nr_boot_partitions = 0 ;
3082+ return ret ;
3083+ }
3084+
3085+ if (boot_partition -> page_offset % mtd -> writesize ) {
3086+ dev_err (dev , "Boot partition offset not multiple of writesize at index %i\n" ,
3087+ i );
3088+ host -> nr_boot_partitions = 0 ;
3089+ return - EINVAL ;
3090+ }
3091+ /* Convert offset to nand pages */
3092+ boot_partition -> page_offset /= mtd -> writesize ;
3093+
3094+ ret = of_property_read_u32_index (dn , "qcom,boot-partitions" , j + 1 ,
3095+ & boot_partition -> page_size );
3096+ if (ret ) {
3097+ dev_err (dev , "Error parsing boot partition size at index %d\n" , i );
3098+ host -> nr_boot_partitions = 0 ;
3099+ return ret ;
3100+ }
3101+
3102+ if (boot_partition -> page_size % mtd -> writesize ) {
3103+ dev_err (dev , "Boot partition size not multiple of writesize at index %i\n" ,
3104+ i );
3105+ host -> nr_boot_partitions = 0 ;
3106+ return - EINVAL ;
3107+ }
3108+ /* Convert size to nand pages */
3109+ boot_partition -> page_size /= mtd -> writesize ;
3110+ }
3111+
3112+ return 0 ;
3113+ }
3114+
29353115static int qcom_nand_host_init_and_register (struct qcom_nand_controller * nandc ,
29363116 struct qcom_nand_host * host ,
29373117 struct device_node * dn )
@@ -2989,6 +3169,14 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
29893169 if (ret )
29903170 nand_cleanup (chip );
29913171
3172+ if (nandc -> props -> use_codeword_fixup ) {
3173+ ret = qcom_nand_host_parse_boot_partitions (nandc , host , dn );
3174+ if (ret ) {
3175+ nand_cleanup (chip );
3176+ return ret ;
3177+ }
3178+ }
3179+
29923180 return ret ;
29933181}
29943182
@@ -3154,6 +3342,7 @@ static int qcom_nandc_remove(struct platform_device *pdev)
31543342static const struct qcom_nandc_props ipq806x_nandc_props = {
31553343 .ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT ),
31563344 .is_bam = false,
3345+ .use_codeword_fixup = true,
31573346 .dev_cmd_reg_start = 0x0 ,
31583347};
31593348
0 commit comments