ipq806x: 5.15: replace nandc patch with upstream version
Replace nandc fix patch with upstream version. Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
This commit is contained in:
		| @@ -1,240 +0,0 @@ | ||||
| From 6949d651e3be3ebbfedb6bbd5b541cfda6ee58a9 Mon Sep 17 00:00:00 2001 | ||||
| From: Ansuel Smith <ansuelsmth@gmail.com> | ||||
| Date: Wed, 10 Feb 2021 10:40:17 +0100 | ||||
| Subject: [PATCH 1/2] mtd: nand: raw: qcom_nandc: add boot_layout_mode support | ||||
|  | ||||
| ipq806x nand have a special ecc configuration for the boot pages. The | ||||
| use of the non-boot pages configuration on boot pages cause I/O error | ||||
| and can cause broken data written to the nand. Add support for this | ||||
| special configuration if the page to be read/write is in the size of the | ||||
| boot pages set by the dts. | ||||
|  | ||||
| Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com> | ||||
| --- | ||||
|  drivers/mtd/nand/raw/qcom_nandc.c | 82 +++++++++++++++++++++++++++++-- | ||||
|  1 file changed, 77 insertions(+), 5 deletions(-) | ||||
|  | ||||
| --- a/drivers/mtd/nand/raw/qcom_nandc.c | ||||
| +++ b/drivers/mtd/nand/raw/qcom_nandc.c | ||||
| @@ -163,6 +163,11 @@ | ||||
|  /* NAND_CTRL bits */ | ||||
|  #define	BAM_MODE_EN			BIT(0) | ||||
|   | ||||
| + | ||||
| +#define UD_SIZE_BYTES_MASK	(0x3ff << UD_SIZE_BYTES) | ||||
| +#define SPARE_SIZE_BYTES_MASK	(0xf << SPARE_SIZE_BYTES) | ||||
| +#define ECC_NUM_DATA_BYTES_MASK	(0x3ff << ECC_NUM_DATA_BYTES) | ||||
| + | ||||
|  /* | ||||
|   * the NAND controller performs reads/writes with ECC in 516 byte chunks. | ||||
|   * the driver calls the chunks 'step' or 'codeword' interchangeably | ||||
| @@ -443,6 +448,13 @@ struct qcom_nand_controller { | ||||
|   * @cfg0, cfg1, cfg0_raw..:	NANDc register configurations needed for | ||||
|   *				ecc/non-ecc mode for the current nand flash | ||||
|   *				device | ||||
| + * | ||||
| + * @boot_pages_conf:		keep track of the current ecc configuration used by | ||||
| + * 				the driver for read/write operation. (boot pages | ||||
| + * 				have different configuration than normal page) | ||||
| + * @boot_pages:			number of pages starting from 0 used as boot pages | ||||
| + * 				where the driver will use the boot pages ecc | ||||
| + * 				configuration for read/write operation | ||||
|   */ | ||||
|  struct qcom_nand_host { | ||||
|  	struct nand_chip chip; | ||||
| @@ -465,6 +477,9 @@ struct qcom_nand_host { | ||||
|  	u32 ecc_bch_cfg; | ||||
|  	u32 clrflashstatus; | ||||
|  	u32 clrreadstatus; | ||||
| + | ||||
| +	bool boot_pages_conf; | ||||
| +	u32 boot_pages; | ||||
|  }; | ||||
|   | ||||
|  /* | ||||
| @@ -474,6 +489,7 @@ struct qcom_nand_host { | ||||
|   * @is_bam - whether NAND controller is using BAM | ||||
|   * @is_qpic - whether NAND CTRL is part of qpic IP | ||||
|   * @qpic_v2 - flag to indicate QPIC IP version 2 | ||||
| + * @has_boot_pages - whether NAND has different ecc settings for boot pages | ||||
|   * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset | ||||
|   */ | ||||
|  struct qcom_nandc_props { | ||||
| @@ -481,6 +497,7 @@ struct qcom_nandc_props { | ||||
|  	bool is_bam; | ||||
|  	bool is_qpic; | ||||
|  	bool qpic_v2; | ||||
| +	bool has_boot_pages; | ||||
|  	u32 dev_cmd_reg_start; | ||||
|  }; | ||||
|   | ||||
| @@ -1691,7 +1708,7 @@ qcom_nandc_read_cw_raw(struct mtd_info * | ||||
|  	data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1); | ||||
|  	oob_size1 = host->bbm_size; | ||||
|   | ||||
| -	if (qcom_nandc_is_last_cw(ecc, cw)) { | ||||
| +	if (qcom_nandc_is_last_cw(ecc, cw) && !host->boot_pages_conf) { | ||||
|  		data_size2 = ecc->size - data_size1 - | ||||
|  			     ((ecc->steps - 1) * 4); | ||||
|  		oob_size2 = (ecc->steps * 4) + host->ecc_bytes_hw + | ||||
| @@ -1772,7 +1789,7 @@ check_for_erased_page(struct qcom_nand_h | ||||
|  	} | ||||
|   | ||||
|  	for_each_set_bit(cw, &uncorrectable_cws, ecc->steps) { | ||||
| -		if (qcom_nandc_is_last_cw(ecc, cw)) { | ||||
| +		if (qcom_nandc_is_last_cw(ecc, cw) && !host->boot_pages_conf) { | ||||
|  			data_size = ecc->size - ((ecc->steps - 1) * 4); | ||||
|  			oob_size = (ecc->steps * 4) + host->ecc_bytes_hw; | ||||
|  		} else { | ||||
| @@ -1930,7 +1947,7 @@ static int read_page_ecc(struct qcom_nan | ||||
|  	for (i = 0; i < ecc->steps; i++) { | ||||
|  		int data_size, oob_size; | ||||
|   | ||||
| -		if (qcom_nandc_is_last_cw(ecc, i)) { | ||||
| +		if (qcom_nandc_is_last_cw(ecc, i) && !host->boot_pages_conf) { | ||||
|  			data_size = ecc->size - ((ecc->steps - 1) << 2); | ||||
|  			oob_size = (ecc->steps << 2) + host->ecc_bytes_hw + | ||||
|  				   host->spare_bytes; | ||||
| @@ -2027,6 +2044,30 @@ static int copy_last_cw(struct qcom_nand | ||||
|  	return ret; | ||||
|  } | ||||
|   | ||||
| +static void | ||||
| +check_boot_pages_conf(struct qcom_nand_host *host, int page) | ||||
| +{ | ||||
| +	bool boot_pages_conf = page < host->boot_pages; | ||||
| + | ||||
| +	/* Skip conf write if we are already in the correct mode */ | ||||
| +	if (boot_pages_conf != host->boot_pages_conf) { | ||||
| +		host->boot_pages_conf = boot_pages_conf; | ||||
| + | ||||
| +		host->cw_data = boot_pages_conf ? 512 : 516; | ||||
| +		host->spare_bytes = host->cw_size - host->ecc_bytes_hw - | ||||
| +				    host->bbm_size - host->cw_data; | ||||
| + | ||||
| +		host->cfg0 &= ~(SPARE_SIZE_BYTES_MASK | UD_SIZE_BYTES_MASK); | ||||
| +		host->cfg0 |= host->spare_bytes << SPARE_SIZE_BYTES | | ||||
| +			      host->cw_data << UD_SIZE_BYTES; | ||||
| + | ||||
| +		host->ecc_bch_cfg &= ~ECC_NUM_DATA_BYTES_MASK; | ||||
| +		host->ecc_bch_cfg |= host->cw_data << ECC_NUM_DATA_BYTES; | ||||
| +		host->ecc_buf_cfg = (boot_pages_conf ? 0x1ff : 0x203) << | ||||
| +				     NUM_STEPS; | ||||
| +	} | ||||
| +} | ||||
| + | ||||
|  /* implements ecc->read_page() */ | ||||
|  static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf, | ||||
|  				int oob_required, int page) | ||||
| @@ -2035,6 +2076,9 @@ static int qcom_nandc_read_page(struct n | ||||
|  	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); | ||||
|  	u8 *data_buf, *oob_buf = NULL; | ||||
|   | ||||
| +	if (host->boot_pages) | ||||
| +		check_boot_pages_conf(host, page); | ||||
| + | ||||
|  	nand_read_page_op(chip, page, 0, NULL, 0); | ||||
|  	data_buf = buf; | ||||
|  	oob_buf = oob_required ? chip->oob_poi : NULL; | ||||
| @@ -2054,6 +2098,9 @@ static int qcom_nandc_read_page_raw(stru | ||||
|  	int cw, ret; | ||||
|  	u8 *data_buf = buf, *oob_buf = chip->oob_poi; | ||||
|   | ||||
| +	if (host->boot_pages) | ||||
| +		check_boot_pages_conf(host, page); | ||||
| + | ||||
|  	for (cw = 0; cw < ecc->steps; cw++) { | ||||
|  		ret = qcom_nandc_read_cw_raw(mtd, chip, data_buf, oob_buf, | ||||
|  					     page, cw); | ||||
| @@ -2074,6 +2121,9 @@ static int qcom_nandc_read_oob(struct na | ||||
|  	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); | ||||
|  	struct nand_ecc_ctrl *ecc = &chip->ecc; | ||||
|   | ||||
| +	if (host->boot_pages) | ||||
| +		check_boot_pages_conf(host, page); | ||||
| + | ||||
|  	clear_read_regs(nandc); | ||||
|  	clear_bam_transaction(nandc); | ||||
|   | ||||
| @@ -2094,6 +2144,9 @@ static int qcom_nandc_write_page(struct | ||||
|  	u8 *data_buf, *oob_buf; | ||||
|  	int i, ret; | ||||
|   | ||||
| +	if (host->boot_pages) | ||||
| +		check_boot_pages_conf(host, page); | ||||
| + | ||||
|  	nand_prog_page_begin_op(chip, page, 0, NULL, 0); | ||||
|   | ||||
|  	clear_read_regs(nandc); | ||||
| @@ -2109,7 +2162,7 @@ static int qcom_nandc_write_page(struct | ||||
|  	for (i = 0; i < ecc->steps; i++) { | ||||
|  		int data_size, oob_size; | ||||
|   | ||||
| -		if (qcom_nandc_is_last_cw(ecc, i)) { | ||||
| +		if (qcom_nandc_is_last_cw(ecc, i) && !host->boot_pages_conf) { | ||||
|  			data_size = ecc->size - ((ecc->steps - 1) << 2); | ||||
|  			oob_size = (ecc->steps << 2) + host->ecc_bytes_hw + | ||||
|  				   host->spare_bytes; | ||||
| @@ -2166,6 +2219,9 @@ static int qcom_nandc_write_page_raw(str | ||||
|  	u8 *data_buf, *oob_buf; | ||||
|  	int i, ret; | ||||
|   | ||||
| +	if (host->boot_pages) | ||||
| +		check_boot_pages_conf(host, page); | ||||
| + | ||||
|  	nand_prog_page_begin_op(chip, page, 0, NULL, 0); | ||||
|  	clear_read_regs(nandc); | ||||
|  	clear_bam_transaction(nandc); | ||||
| @@ -2184,7 +2240,7 @@ static int qcom_nandc_write_page_raw(str | ||||
|  		data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1); | ||||
|  		oob_size1 = host->bbm_size; | ||||
|   | ||||
| -		if (qcom_nandc_is_last_cw(ecc, i)) { | ||||
| +		if (qcom_nandc_is_last_cw(ecc, i) && !host->boot_pages_conf) { | ||||
|  			data_size2 = ecc->size - data_size1 - | ||||
|  				     ((ecc->steps - 1) << 2); | ||||
|  			oob_size2 = (ecc->steps << 2) + host->ecc_bytes_hw + | ||||
| @@ -2244,6 +2300,9 @@ static int qcom_nandc_write_oob(struct n | ||||
|  	int data_size, oob_size; | ||||
|  	int ret; | ||||
|   | ||||
| +	if (host->boot_pages) | ||||
| +		check_boot_pages_conf(host, page); | ||||
| + | ||||
|  	host->use_ecc = true; | ||||
|  	clear_bam_transaction(nandc); | ||||
|   | ||||
| @@ -2912,6 +2971,7 @@ static int qcom_nand_host_init_and_regis | ||||
|  	struct nand_chip *chip = &host->chip; | ||||
|  	struct mtd_info *mtd = nand_to_mtd(chip); | ||||
|  	struct device *dev = nandc->dev; | ||||
| +	u32 boot_pages_size; | ||||
|  	int ret; | ||||
|   | ||||
|  	ret = of_property_read_u32(dn, "reg", &host->cs); | ||||
| @@ -2962,6 +3022,17 @@ static int qcom_nand_host_init_and_regis | ||||
|  	if (ret) | ||||
|  		nand_cleanup(chip); | ||||
|   | ||||
| +	if (nandc->props->has_boot_pages && | ||||
| +	    of_property_read_bool(dn, "nand-is-boot-medium")) { | ||||
| +		ret = of_property_read_u32(dn, "qcom,boot_pages_size", | ||||
| +					   &boot_pages_size); | ||||
| +		if (ret) | ||||
| +			dev_warn(dev, "can't get boot pages size"); | ||||
| +		else | ||||
| +			/* Convert size to nand pages */ | ||||
| +			host->boot_pages = boot_pages_size / mtd->writesize; | ||||
| +	} | ||||
| + | ||||
|  	return ret; | ||||
|  } | ||||
|   | ||||
| @@ -3127,6 +3198,7 @@ static int qcom_nandc_remove(struct plat | ||||
|  static const struct qcom_nandc_props ipq806x_nandc_props = { | ||||
|  	.ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT), | ||||
|  	.is_bam = false, | ||||
| +	.has_boot_pages = true, | ||||
|  	.dev_cmd_reg_start = 0x0, | ||||
|  }; | ||||
|   | ||||
| @@ -1,41 +0,0 @@ | ||||
| From 6fb003a7a117f97a35b078ba726c84adeae29c4c Mon Sep 17 00:00:00 2001 | ||||
| From: Ansuel Smith <ansuelsmth@gmail.com> | ||||
| Date: Wed, 10 Feb 2021 10:54:19 +0100 | ||||
| Subject: [PATCH 2/2] Documentation: devicetree: mtd: qcom_nandc: document | ||||
|  qcom,boot_layout_size binding | ||||
|  | ||||
| Document new qcom,boot_layout_size binding used to apply special | ||||
| read/write confituation to boots partitions. | ||||
|  | ||||
| Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com> | ||||
| --- | ||||
|  Documentation/devicetree/bindings/mtd/qcom,nandc.yaml | 11 +++++++++++ | ||||
|  1 file changed, 11 insertions(+) | ||||
|  | ||||
| --- a/Documentation/devicetree/bindings/mtd/qcom,nandc.yaml | ||||
| +++ b/Documentation/devicetree/bindings/mtd/qcom,nandc.yaml | ||||
| @@ -78,6 +78,14 @@ allOf: | ||||
|              Must contain the ADM data type CRCI block instance number | ||||
|              specified for the NAND controller on the given platform | ||||
|   | ||||
| +        qcom,boot_pages_size: | ||||
| +          description: | ||||
| +            Should contain the size of the total boot partitions | ||||
| +            where the boot layout read/write specific configuration | ||||
| +            should be used. The boot layout is considered from the | ||||
| +            start of the nand to the value set in this binding. | ||||
| +            Only used in combination with 'nand-is-boot-medium'. | ||||
| + | ||||
|    - if: | ||||
|        properties: | ||||
|          compatible: | ||||
| @@ -135,6 +143,9 @@ examples: | ||||
|          nand-ecc-strength = <4>; | ||||
|          nand-bus-width = <8>; | ||||
|   | ||||
| +        nand-is-boot-medium; | ||||
| +        qcom,boot_pages_size: <0x58a0000>; | ||||
| + | ||||
|          partitions { | ||||
|            compatible = "fixed-partitions"; | ||||
|            #address-cells = <1>; | ||||
| @@ -0,0 +1,268 @@ | ||||
| From b360514edb4743cbf86fc377699c75e98b1264c7 Mon Sep 17 00:00:00 2001 | ||||
| From: Christian Marangi <ansuelsmth@gmail.com> | ||||
| Date: Thu, 16 Jun 2022 02:18:33 +0200 | ||||
| Subject: [PATCH 1/2] mtd: nand: raw: qcom_nandc: reorder qcom_nand_host struct | ||||
|  | ||||
| Reorder structs in nandc driver to save holes. | ||||
|  | ||||
| Signed-off-by: Christian Marangi <ansuelsmth@gmail.com> | ||||
| Reviewed-by: Manivannan Sadhasivam <mani@kernel.org> | ||||
| Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> | ||||
| Link: https://lore.kernel.org/linux-mtd/20220616001835.24393-2-ansuelsmth@gmail.com | ||||
| --- | ||||
|  drivers/mtd/nand/raw/qcom_nandc.c | 107 +++++++++++++++++------------- | ||||
|  1 file changed, 62 insertions(+), 45 deletions(-) | ||||
|  | ||||
| --- a/drivers/mtd/nand/raw/qcom_nandc.c | ||||
| +++ b/drivers/mtd/nand/raw/qcom_nandc.c | ||||
| @@ -237,6 +237,9 @@ nandc_set_reg(chip, reg,			\ | ||||
|   * @bam_ce - the array of BAM command elements | ||||
|   * @cmd_sgl - sgl for NAND BAM command pipe | ||||
|   * @data_sgl - sgl for NAND BAM consumer/producer pipe | ||||
| + * @last_data_desc - last DMA desc in data channel (tx/rx). | ||||
| + * @last_cmd_desc - last DMA desc in command channel. | ||||
| + * @txn_done - completion for NAND transfer. | ||||
|   * @bam_ce_pos - the index in bam_ce which is available for next sgl | ||||
|   * @bam_ce_start - the index in bam_ce which marks the start position ce | ||||
|   *		   for current sgl. It will be used for size calculation | ||||
| @@ -249,14 +252,14 @@ nandc_set_reg(chip, reg,			\ | ||||
|   * @rx_sgl_start - start index in data sgl for rx. | ||||
|   * @wait_second_completion - wait for second DMA desc completion before making | ||||
|   *			     the NAND transfer completion. | ||||
| - * @txn_done - completion for NAND transfer. | ||||
| - * @last_data_desc - last DMA desc in data channel (tx/rx). | ||||
| - * @last_cmd_desc - last DMA desc in command channel. | ||||
|   */ | ||||
|  struct bam_transaction { | ||||
|  	struct bam_cmd_element *bam_ce; | ||||
|  	struct scatterlist *cmd_sgl; | ||||
|  	struct scatterlist *data_sgl; | ||||
| +	struct dma_async_tx_descriptor *last_data_desc; | ||||
| +	struct dma_async_tx_descriptor *last_cmd_desc; | ||||
| +	struct completion txn_done; | ||||
|  	u32 bam_ce_pos; | ||||
|  	u32 bam_ce_start; | ||||
|  	u32 cmd_sgl_pos; | ||||
| @@ -266,25 +269,23 @@ struct bam_transaction { | ||||
|  	u32 rx_sgl_pos; | ||||
|  	u32 rx_sgl_start; | ||||
|  	bool wait_second_completion; | ||||
| -	struct completion txn_done; | ||||
| -	struct dma_async_tx_descriptor *last_data_desc; | ||||
| -	struct dma_async_tx_descriptor *last_cmd_desc; | ||||
|  }; | ||||
|   | ||||
|  /* | ||||
|   * This data type corresponds to the nand dma descriptor | ||||
| + * @dma_desc - low level DMA engine descriptor | ||||
|   * @list - list for desc_info | ||||
| - * @dir - DMA transfer direction | ||||
| + * | ||||
|   * @adm_sgl - sgl which will be used for single sgl dma descriptor. Only used by | ||||
|   *	      ADM | ||||
|   * @bam_sgl - sgl which will be used for dma descriptor. Only used by BAM | ||||
|   * @sgl_cnt - number of SGL in bam_sgl. Only used by BAM | ||||
| - * @dma_desc - low level DMA engine descriptor | ||||
| + * @dir - DMA transfer direction | ||||
|   */ | ||||
|  struct desc_info { | ||||
| +	struct dma_async_tx_descriptor *dma_desc; | ||||
|  	struct list_head node; | ||||
|   | ||||
| -	enum dma_data_direction dir; | ||||
|  	union { | ||||
|  		struct scatterlist adm_sgl; | ||||
|  		struct { | ||||
| @@ -292,7 +293,7 @@ struct desc_info { | ||||
|  			int sgl_cnt; | ||||
|  		}; | ||||
|  	}; | ||||
| -	struct dma_async_tx_descriptor *dma_desc; | ||||
| +	enum dma_data_direction dir; | ||||
|  }; | ||||
|   | ||||
|  /* | ||||
| @@ -336,52 +337,64 @@ struct nandc_regs { | ||||
|  /* | ||||
|   * NAND controller data struct | ||||
|   * | ||||
| - * @controller:			base controller structure | ||||
| - * @host_list:			list containing all the chips attached to the | ||||
| - *				controller | ||||
|   * @dev:			parent device | ||||
| + * | ||||
|   * @base:			MMIO base | ||||
| - * @base_phys:			physical base address of controller registers | ||||
| - * @base_dma:			dma base address of controller registers | ||||
| + * | ||||
|   * @core_clk:			controller clock | ||||
|   * @aon_clk:			another controller clock | ||||
|   * | ||||
| + * @regs:			a contiguous chunk of memory for DMA register | ||||
| + *				writes. contains the register values to be | ||||
| + *				written to controller | ||||
| + * | ||||
| + * @props:			properties of current NAND controller, | ||||
| + *				initialized via DT match data | ||||
| + * | ||||
| + * @controller:			base controller structure | ||||
| + * @host_list:			list containing all the chips attached to the | ||||
| + *				controller | ||||
| + * | ||||
|   * @chan:			dma channel | ||||
|   * @cmd_crci:			ADM DMA CRCI for command flow control | ||||
|   * @data_crci:			ADM DMA CRCI for data flow control | ||||
| + * | ||||
|   * @desc_list:			DMA descriptor list (list of desc_infos) | ||||
|   * | ||||
|   * @data_buffer:		our local DMA buffer for page read/writes, | ||||
|   *				used when we can't use the buffer provided | ||||
|   *				by upper layers directly | ||||
| - * @buf_size/count/start:	markers for chip->legacy.read_buf/write_buf | ||||
| - *				functions | ||||
|   * @reg_read_buf:		local buffer for reading back registers via DMA | ||||
| + * | ||||
| + * @base_phys:			physical base address of controller registers | ||||
| + * @base_dma:			dma base address of controller registers | ||||
|   * @reg_read_dma:		contains dma address for register read buffer | ||||
| - * @reg_read_pos:		marker for data read in reg_read_buf | ||||
|   * | ||||
| - * @regs:			a contiguous chunk of memory for DMA register | ||||
| - *				writes. contains the register values to be | ||||
| - *				written to controller | ||||
| - * @cmd1/vld:			some fixed controller register values | ||||
| - * @props:			properties of current NAND controller, | ||||
| - *				initialized via DT match data | ||||
| + * @buf_size/count/start:	markers for chip->legacy.read_buf/write_buf | ||||
| + *				functions | ||||
|   * @max_cwperpage:		maximum QPIC codewords required. calculated | ||||
|   *				from all connected NAND devices pagesize | ||||
| + * | ||||
| + * @reg_read_pos:		marker for data read in reg_read_buf | ||||
| + * | ||||
| + * @cmd1/vld:			some fixed controller register values | ||||
|   */ | ||||
|  struct qcom_nand_controller { | ||||
| -	struct nand_controller controller; | ||||
| -	struct list_head host_list; | ||||
| - | ||||
|  	struct device *dev; | ||||
|   | ||||
|  	void __iomem *base; | ||||
| -	phys_addr_t base_phys; | ||||
| -	dma_addr_t base_dma; | ||||
|   | ||||
|  	struct clk *core_clk; | ||||
|  	struct clk *aon_clk; | ||||
|   | ||||
| +	struct nandc_regs *regs; | ||||
| +	struct bam_transaction *bam_txn; | ||||
| + | ||||
| +	const struct qcom_nandc_props *props; | ||||
| + | ||||
| +	struct nand_controller controller; | ||||
| +	struct list_head host_list; | ||||
| + | ||||
|  	union { | ||||
|  		/* will be used only by QPIC for BAM DMA */ | ||||
|  		struct { | ||||
| @@ -399,22 +412,22 @@ struct qcom_nand_controller { | ||||
|  	}; | ||||
|   | ||||
|  	struct list_head desc_list; | ||||
| -	struct bam_transaction *bam_txn; | ||||
|   | ||||
|  	u8		*data_buffer; | ||||
| +	__le32		*reg_read_buf; | ||||
| + | ||||
| +	phys_addr_t base_phys; | ||||
| +	dma_addr_t base_dma; | ||||
| +	dma_addr_t reg_read_dma; | ||||
| + | ||||
|  	int		buf_size; | ||||
|  	int		buf_count; | ||||
|  	int		buf_start; | ||||
|  	unsigned int	max_cwperpage; | ||||
|   | ||||
| -	__le32 *reg_read_buf; | ||||
| -	dma_addr_t reg_read_dma; | ||||
|  	int reg_read_pos; | ||||
|   | ||||
| -	struct nandc_regs *regs; | ||||
| - | ||||
|  	u32 cmd1, vld; | ||||
| -	const struct qcom_nandc_props *props; | ||||
|  }; | ||||
|   | ||||
|  /* | ||||
| @@ -430,19 +443,21 @@ struct qcom_nand_controller { | ||||
|   *				and reserved bytes | ||||
|   * @cw_data:			the number of bytes within a codeword protected | ||||
|   *				by ECC | ||||
| - * @use_ecc:			request the controller to use ECC for the | ||||
| - *				upcoming read/write | ||||
| - * @bch_enabled:		flag to tell whether BCH ECC mode is used | ||||
|   * @ecc_bytes_hw:		ECC bytes used by controller hardware for this | ||||
|   *				chip | ||||
| - * @status:			value to be returned if NAND_CMD_STATUS command | ||||
| - *				is executed | ||||
| + * | ||||
|   * @last_command:		keeps track of last command on this chip. used | ||||
|   *				for reading correct status | ||||
|   * | ||||
|   * @cfg0, cfg1, cfg0_raw..:	NANDc register configurations needed for | ||||
|   *				ecc/non-ecc mode for the current nand flash | ||||
|   *				device | ||||
| + * | ||||
| + * @status:			value to be returned if NAND_CMD_STATUS command | ||||
| + *				is executed | ||||
| + * @use_ecc:			request the controller to use ECC for the | ||||
| + *				upcoming read/write | ||||
| + * @bch_enabled:		flag to tell whether BCH ECC mode is used | ||||
|   */ | ||||
|  struct qcom_nand_host { | ||||
|  	struct nand_chip chip; | ||||
| @@ -451,12 +466,10 @@ struct qcom_nand_host { | ||||
|  	int cs; | ||||
|  	int cw_size; | ||||
|  	int cw_data; | ||||
| -	bool use_ecc; | ||||
| -	bool bch_enabled; | ||||
|  	int ecc_bytes_hw; | ||||
|  	int spare_bytes; | ||||
|  	int bbm_size; | ||||
| -	u8 status; | ||||
| + | ||||
|  	int last_command; | ||||
|   | ||||
|  	u32 cfg0, cfg1; | ||||
| @@ -465,23 +478,27 @@ struct qcom_nand_host { | ||||
|  	u32 ecc_bch_cfg; | ||||
|  	u32 clrflashstatus; | ||||
|  	u32 clrreadstatus; | ||||
| + | ||||
| +	u8 status; | ||||
| +	bool use_ecc; | ||||
| +	bool bch_enabled; | ||||
|  }; | ||||
|   | ||||
|  /* | ||||
|   * This data type corresponds to the NAND controller properties which varies | ||||
|   * among different NAND controllers. | ||||
|   * @ecc_modes - ecc mode for NAND | ||||
| + * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset | ||||
|   * @is_bam - whether NAND controller is using BAM | ||||
|   * @is_qpic - whether NAND CTRL is part of qpic IP | ||||
|   * @qpic_v2 - flag to indicate QPIC IP version 2 | ||||
| - * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset | ||||
|   */ | ||||
|  struct qcom_nandc_props { | ||||
|  	u32 ecc_modes; | ||||
| +	u32 dev_cmd_reg_start; | ||||
|  	bool is_bam; | ||||
|  	bool is_qpic; | ||||
|  	bool qpic_v2; | ||||
| -	u32 dev_cmd_reg_start; | ||||
|  }; | ||||
|   | ||||
|  /* Frees the BAM transaction memory */ | ||||
| @@ -0,0 +1,406 @@ | ||||
| From 862bdedd7f4b8aebf00fdb422062e64896e97809 Mon Sep 17 00:00:00 2001 | ||||
| From: Christian Marangi <ansuelsmth@gmail.com> | ||||
| Date: Thu, 16 Jun 2022 02:18:34 +0200 | ||||
| Subject: [PATCH 2/2] mtd: nand: raw: qcom_nandc: add support for unprotected | ||||
|  spare data pages | ||||
|  | ||||
| IPQ8064 nand have special pages where a different layout scheme is used. | ||||
| These special page are used by boot partition and on reading them | ||||
| lots of warning are reported about wrong ECC data and if written to | ||||
| results in broken data and not bootable device. | ||||
|  | ||||
| The layout scheme used by these special page consist in using 512 bytes | ||||
| as the codeword size (even for the last codeword) while writing to CFG0 | ||||
| register. This forces the NAND controller to unprotect the 4 bytes of | ||||
| spare data. | ||||
|  | ||||
| Since the kernel is unaware of this different layout for these special | ||||
| page, it does try to protect the spare data too during read/write and | ||||
| warn about CRC errors. | ||||
|  | ||||
| Add support for this by permitting the user to declare these special | ||||
| pages in dts by declaring offset and size of the partition. The driver | ||||
| internally will convert these value to nand pages. | ||||
|  | ||||
| On user read/write the page is checked and if it's a boot page the | ||||
| correct layout is used. | ||||
|  | ||||
| Signed-off-by: Christian Marangi <ansuelsmth@gmail.com> | ||||
| Reviewed-by: Manivannan Sadhasivam <mani@kernel.org> | ||||
| Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> | ||||
| Link: https://lore.kernel.org/linux-mtd/20220616001835.24393-3-ansuelsmth@gmail.com | ||||
| --- | ||||
|  drivers/mtd/nand/raw/qcom_nandc.c | 199 +++++++++++++++++++++++++++++- | ||||
|  1 file changed, 194 insertions(+), 5 deletions(-) | ||||
|  | ||||
| --- a/drivers/mtd/nand/raw/qcom_nandc.c | ||||
| +++ b/drivers/mtd/nand/raw/qcom_nandc.c | ||||
| @@ -79,8 +79,10 @@ | ||||
|  #define	DISABLE_STATUS_AFTER_WRITE	4 | ||||
|  #define	CW_PER_PAGE			6 | ||||
|  #define	UD_SIZE_BYTES			9 | ||||
| +#define	UD_SIZE_BYTES_MASK		GENMASK(18, 9) | ||||
|  #define	ECC_PARITY_SIZE_BYTES_RS	19 | ||||
|  #define	SPARE_SIZE_BYTES		23 | ||||
| +#define	SPARE_SIZE_BYTES_MASK		GENMASK(26, 23) | ||||
|  #define	NUM_ADDR_CYCLES			27 | ||||
|  #define	STATUS_BFR_READ			30 | ||||
|  #define	SET_RD_MODE_AFTER_STATUS	31 | ||||
| @@ -101,6 +103,7 @@ | ||||
|  #define	ECC_MODE			4 | ||||
|  #define	ECC_PARITY_SIZE_BYTES_BCH	8 | ||||
|  #define	ECC_NUM_DATA_BYTES		16 | ||||
| +#define	ECC_NUM_DATA_BYTES_MASK		GENMASK(25, 16) | ||||
|  #define	ECC_FORCE_CLK_OPEN		30 | ||||
|   | ||||
|  /* NAND_DEV_CMD1 bits */ | ||||
| @@ -431,12 +434,31 @@ struct qcom_nand_controller { | ||||
|  }; | ||||
|   | ||||
|  /* | ||||
| + * NAND special boot partitions | ||||
| + * | ||||
| + * @page_offset:		offset of the partition where spare data is not protected | ||||
| + *				by ECC (value in pages) | ||||
| + * @page_offset:		size of the partition where spare data is not protected | ||||
| + *				by ECC (value in pages) | ||||
| + */ | ||||
| +struct qcom_nand_boot_partition { | ||||
| +	u32 page_offset; | ||||
| +	u32 page_size; | ||||
| +}; | ||||
| + | ||||
| +/* | ||||
|   * NAND chip structure | ||||
|   * | ||||
| + * @boot_partitions:		array of boot partitions where offset and size of the | ||||
| + *				boot partitions are stored | ||||
| + * | ||||
|   * @chip:			base NAND chip structure | ||||
|   * @node:			list node to add itself to host_list in | ||||
|   *				qcom_nand_controller | ||||
|   * | ||||
| + * @nr_boot_partitions:		count of the boot partitions where spare data is not | ||||
| + *				protected by ECC | ||||
| + * | ||||
|   * @cs:				chip select value for this chip | ||||
|   * @cw_size:			the number of bytes in a single step/codeword | ||||
|   *				of a page, consisting of all data, ecc, spare | ||||
| @@ -455,14 +477,20 @@ struct qcom_nand_controller { | ||||
|   * | ||||
|   * @status:			value to be returned if NAND_CMD_STATUS command | ||||
|   *				is executed | ||||
| + * @codeword_fixup:		keep track of the current layout used by | ||||
| + *				the driver for read/write operation. | ||||
|   * @use_ecc:			request the controller to use ECC for the | ||||
|   *				upcoming read/write | ||||
|   * @bch_enabled:		flag to tell whether BCH ECC mode is used | ||||
|   */ | ||||
|  struct qcom_nand_host { | ||||
| +	struct qcom_nand_boot_partition *boot_partitions; | ||||
| + | ||||
|  	struct nand_chip chip; | ||||
|  	struct list_head node; | ||||
|   | ||||
| +	int nr_boot_partitions; | ||||
| + | ||||
|  	int cs; | ||||
|  	int cw_size; | ||||
|  	int cw_data; | ||||
| @@ -480,6 +508,7 @@ struct qcom_nand_host { | ||||
|  	u32 clrreadstatus; | ||||
|   | ||||
|  	u8 status; | ||||
| +	bool codeword_fixup; | ||||
|  	bool use_ecc; | ||||
|  	bool bch_enabled; | ||||
|  }; | ||||
| @@ -492,6 +521,7 @@ struct qcom_nand_host { | ||||
|   * @is_bam - whether NAND controller is using BAM | ||||
|   * @is_qpic - whether NAND CTRL is part of qpic IP | ||||
|   * @qpic_v2 - flag to indicate QPIC IP version 2 | ||||
| + * @use_codeword_fixup - whether NAND has different layout for boot partitions | ||||
|   */ | ||||
|  struct qcom_nandc_props { | ||||
|  	u32 ecc_modes; | ||||
| @@ -499,6 +529,7 @@ struct qcom_nandc_props { | ||||
|  	bool is_bam; | ||||
|  	bool is_qpic; | ||||
|  	bool qpic_v2; | ||||
| +	bool use_codeword_fixup; | ||||
|  }; | ||||
|   | ||||
|  /* Frees the BAM transaction memory */ | ||||
| @@ -1708,7 +1739,7 @@ qcom_nandc_read_cw_raw(struct mtd_info * | ||||
|  	data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1); | ||||
|  	oob_size1 = host->bbm_size; | ||||
|   | ||||
| -	if (qcom_nandc_is_last_cw(ecc, cw)) { | ||||
| +	if (qcom_nandc_is_last_cw(ecc, cw) && !host->codeword_fixup) { | ||||
|  		data_size2 = ecc->size - data_size1 - | ||||
|  			     ((ecc->steps - 1) * 4); | ||||
|  		oob_size2 = (ecc->steps * 4) + host->ecc_bytes_hw + | ||||
| @@ -1789,7 +1820,7 @@ check_for_erased_page(struct qcom_nand_h | ||||
|  	} | ||||
|   | ||||
|  	for_each_set_bit(cw, &uncorrectable_cws, ecc->steps) { | ||||
| -		if (qcom_nandc_is_last_cw(ecc, cw)) { | ||||
| +		if (qcom_nandc_is_last_cw(ecc, cw) && !host->codeword_fixup) { | ||||
|  			data_size = ecc->size - ((ecc->steps - 1) * 4); | ||||
|  			oob_size = (ecc->steps * 4) + host->ecc_bytes_hw; | ||||
|  		} else { | ||||
| @@ -1947,7 +1978,7 @@ static int read_page_ecc(struct qcom_nan | ||||
|  	for (i = 0; i < ecc->steps; i++) { | ||||
|  		int data_size, oob_size; | ||||
|   | ||||
| -		if (qcom_nandc_is_last_cw(ecc, i)) { | ||||
| +		if (qcom_nandc_is_last_cw(ecc, i) && !host->codeword_fixup) { | ||||
|  			data_size = ecc->size - ((ecc->steps - 1) << 2); | ||||
|  			oob_size = (ecc->steps << 2) + host->ecc_bytes_hw + | ||||
|  				   host->spare_bytes; | ||||
| @@ -2044,6 +2075,69 @@ static int copy_last_cw(struct qcom_nand | ||||
|  	return ret; | ||||
|  } | ||||
|   | ||||
| +static bool qcom_nandc_is_boot_partition(struct qcom_nand_host *host, int page) | ||||
| +{ | ||||
| +	struct qcom_nand_boot_partition *boot_partition; | ||||
| +	u32 start, end; | ||||
| +	int i; | ||||
| + | ||||
| +	/* | ||||
| +	 * Since the frequent access will be to the non-boot partitions like rootfs, | ||||
| +	 * optimize the page check by: | ||||
| +	 * | ||||
| +	 * 1. Checking if the page lies after the last boot partition. | ||||
| +	 * 2. Checking from the boot partition end. | ||||
| +	 */ | ||||
| + | ||||
| +	/* First check the last boot partition */ | ||||
| +	boot_partition = &host->boot_partitions[host->nr_boot_partitions - 1]; | ||||
| +	start = boot_partition->page_offset; | ||||
| +	end = start + boot_partition->page_size; | ||||
| + | ||||
| +	/* Page is after the last boot partition end. This is NOT a boot partition */ | ||||
| +	if (page > end) | ||||
| +		return false; | ||||
| + | ||||
| +	/* Actually check if it's a boot partition */ | ||||
| +	if (page < end && page >= start) | ||||
| +		return true; | ||||
| + | ||||
| +	/* Check the other boot partitions starting from the second-last partition */ | ||||
| +	for (i = host->nr_boot_partitions - 2; i >= 0; i--) { | ||||
| +		boot_partition = &host->boot_partitions[i]; | ||||
| +		start = boot_partition->page_offset; | ||||
| +		end = start + boot_partition->page_size; | ||||
| + | ||||
| +		if (page < end && page >= start) | ||||
| +			return true; | ||||
| +	} | ||||
| + | ||||
| +	return false; | ||||
| +} | ||||
| + | ||||
| +static void qcom_nandc_codeword_fixup(struct qcom_nand_host *host, int page) | ||||
| +{ | ||||
| +	bool codeword_fixup = qcom_nandc_is_boot_partition(host, page); | ||||
| + | ||||
| +	/* Skip conf write if we are already in the correct mode */ | ||||
| +	if (codeword_fixup == host->codeword_fixup) | ||||
| +		return; | ||||
| + | ||||
| +	host->codeword_fixup = codeword_fixup; | ||||
| + | ||||
| +	host->cw_data = codeword_fixup ? 512 : 516; | ||||
| +	host->spare_bytes = host->cw_size - host->ecc_bytes_hw - | ||||
| +			    host->bbm_size - host->cw_data; | ||||
| + | ||||
| +	host->cfg0 &= ~(SPARE_SIZE_BYTES_MASK | UD_SIZE_BYTES_MASK); | ||||
| +	host->cfg0 |= host->spare_bytes << SPARE_SIZE_BYTES | | ||||
| +		      host->cw_data << UD_SIZE_BYTES; | ||||
| + | ||||
| +	host->ecc_bch_cfg &= ~ECC_NUM_DATA_BYTES_MASK; | ||||
| +	host->ecc_bch_cfg |= host->cw_data << ECC_NUM_DATA_BYTES; | ||||
| +	host->ecc_buf_cfg = (host->cw_data - 1) << NUM_STEPS; | ||||
| +} | ||||
| + | ||||
|  /* implements ecc->read_page() */ | ||||
|  static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf, | ||||
|  				int oob_required, int page) | ||||
| @@ -2052,6 +2146,9 @@ static int qcom_nandc_read_page(struct n | ||||
|  	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); | ||||
|  	u8 *data_buf, *oob_buf = NULL; | ||||
|   | ||||
| +	if (host->nr_boot_partitions) | ||||
| +		qcom_nandc_codeword_fixup(host, page); | ||||
| + | ||||
|  	nand_read_page_op(chip, page, 0, NULL, 0); | ||||
|  	data_buf = buf; | ||||
|  	oob_buf = oob_required ? chip->oob_poi : NULL; | ||||
| @@ -2071,6 +2168,9 @@ static int qcom_nandc_read_page_raw(stru | ||||
|  	int cw, ret; | ||||
|  	u8 *data_buf = buf, *oob_buf = chip->oob_poi; | ||||
|   | ||||
| +	if (host->nr_boot_partitions) | ||||
| +		qcom_nandc_codeword_fixup(host, page); | ||||
| + | ||||
|  	for (cw = 0; cw < ecc->steps; cw++) { | ||||
|  		ret = qcom_nandc_read_cw_raw(mtd, chip, data_buf, oob_buf, | ||||
|  					     page, cw); | ||||
| @@ -2091,6 +2191,9 @@ static int qcom_nandc_read_oob(struct na | ||||
|  	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); | ||||
|  	struct nand_ecc_ctrl *ecc = &chip->ecc; | ||||
|   | ||||
| +	if (host->nr_boot_partitions) | ||||
| +		qcom_nandc_codeword_fixup(host, page); | ||||
| + | ||||
|  	clear_read_regs(nandc); | ||||
|  	clear_bam_transaction(nandc); | ||||
|   | ||||
| @@ -2111,6 +2214,9 @@ static int qcom_nandc_write_page(struct | ||||
|  	u8 *data_buf, *oob_buf; | ||||
|  	int i, ret; | ||||
|   | ||||
| +	if (host->nr_boot_partitions) | ||||
| +		qcom_nandc_codeword_fixup(host, page); | ||||
| + | ||||
|  	nand_prog_page_begin_op(chip, page, 0, NULL, 0); | ||||
|   | ||||
|  	clear_read_regs(nandc); | ||||
| @@ -2126,7 +2232,7 @@ static int qcom_nandc_write_page(struct | ||||
|  	for (i = 0; i < ecc->steps; i++) { | ||||
|  		int data_size, oob_size; | ||||
|   | ||||
| -		if (qcom_nandc_is_last_cw(ecc, i)) { | ||||
| +		if (qcom_nandc_is_last_cw(ecc, i) && !host->codeword_fixup) { | ||||
|  			data_size = ecc->size - ((ecc->steps - 1) << 2); | ||||
|  			oob_size = (ecc->steps << 2) + host->ecc_bytes_hw + | ||||
|  				   host->spare_bytes; | ||||
| @@ -2183,6 +2289,9 @@ static int qcom_nandc_write_page_raw(str | ||||
|  	u8 *data_buf, *oob_buf; | ||||
|  	int i, ret; | ||||
|   | ||||
| +	if (host->nr_boot_partitions) | ||||
| +		qcom_nandc_codeword_fixup(host, page); | ||||
| + | ||||
|  	nand_prog_page_begin_op(chip, page, 0, NULL, 0); | ||||
|  	clear_read_regs(nandc); | ||||
|  	clear_bam_transaction(nandc); | ||||
| @@ -2201,7 +2310,7 @@ static int qcom_nandc_write_page_raw(str | ||||
|  		data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1); | ||||
|  		oob_size1 = host->bbm_size; | ||||
|   | ||||
| -		if (qcom_nandc_is_last_cw(ecc, i)) { | ||||
| +		if (qcom_nandc_is_last_cw(ecc, i) && !host->codeword_fixup) { | ||||
|  			data_size2 = ecc->size - data_size1 - | ||||
|  				     ((ecc->steps - 1) << 2); | ||||
|  			oob_size2 = (ecc->steps << 2) + host->ecc_bytes_hw + | ||||
| @@ -2261,6 +2370,9 @@ static int qcom_nandc_write_oob(struct n | ||||
|  	int data_size, oob_size; | ||||
|  	int ret; | ||||
|   | ||||
| +	if (host->nr_boot_partitions) | ||||
| +		qcom_nandc_codeword_fixup(host, page); | ||||
| + | ||||
|  	host->use_ecc = true; | ||||
|  	clear_bam_transaction(nandc); | ||||
|   | ||||
| @@ -2922,6 +3034,74 @@ static int qcom_nandc_setup(struct qcom_ | ||||
|   | ||||
|  static const char * const probes[] = { "cmdlinepart", "ofpart", "qcomsmem", NULL }; | ||||
|   | ||||
| +static int qcom_nand_host_parse_boot_partitions(struct qcom_nand_controller *nandc, | ||||
| +						struct qcom_nand_host *host, | ||||
| +						struct device_node *dn) | ||||
| +{ | ||||
| +	struct nand_chip *chip = &host->chip; | ||||
| +	struct mtd_info *mtd = nand_to_mtd(chip); | ||||
| +	struct qcom_nand_boot_partition *boot_partition; | ||||
| +	struct device *dev = nandc->dev; | ||||
| +	int partitions_count, i, j, ret; | ||||
| + | ||||
| +	if (!of_find_property(dn, "qcom,boot-partitions", NULL)) | ||||
| +		return 0; | ||||
| + | ||||
| +	partitions_count = of_property_count_u32_elems(dn, "qcom,boot-partitions"); | ||||
| +	if (partitions_count <= 0) { | ||||
| +		dev_err(dev, "Error parsing boot partition\n"); | ||||
| +		return partitions_count ? partitions_count : -EINVAL; | ||||
| +	} | ||||
| + | ||||
| +	host->nr_boot_partitions = partitions_count / 2; | ||||
| +	host->boot_partitions = devm_kcalloc(dev, host->nr_boot_partitions, | ||||
| +					     sizeof(*host->boot_partitions), GFP_KERNEL); | ||||
| +	if (!host->boot_partitions) { | ||||
| +		host->nr_boot_partitions = 0; | ||||
| +		return -ENOMEM; | ||||
| +	} | ||||
| + | ||||
| +	for (i = 0, j = 0; i < host->nr_boot_partitions; i++, j += 2) { | ||||
| +		boot_partition = &host->boot_partitions[i]; | ||||
| + | ||||
| +		ret = of_property_read_u32_index(dn, "qcom,boot-partitions", j, | ||||
| +						 &boot_partition->page_offset); | ||||
| +		if (ret) { | ||||
| +			dev_err(dev, "Error parsing boot partition offset at index %d\n", i); | ||||
| +			host->nr_boot_partitions = 0; | ||||
| +			return ret; | ||||
| +		} | ||||
| + | ||||
| +		if (boot_partition->page_offset % mtd->writesize) { | ||||
| +			dev_err(dev, "Boot partition offset not multiple of writesize at index %i\n", | ||||
| +				i); | ||||
| +			host->nr_boot_partitions = 0; | ||||
| +			return -EINVAL; | ||||
| +		} | ||||
| +		/* Convert offset to nand pages */ | ||||
| +		boot_partition->page_offset /= mtd->writesize; | ||||
| + | ||||
| +		ret = of_property_read_u32_index(dn, "qcom,boot-partitions", j + 1, | ||||
| +						 &boot_partition->page_size); | ||||
| +		if (ret) { | ||||
| +			dev_err(dev, "Error parsing boot partition size at index %d\n", i); | ||||
| +			host->nr_boot_partitions = 0; | ||||
| +			return ret; | ||||
| +		} | ||||
| + | ||||
| +		if (boot_partition->page_size % mtd->writesize) { | ||||
| +			dev_err(dev, "Boot partition size not multiple of writesize at index %i\n", | ||||
| +				i); | ||||
| +			host->nr_boot_partitions = 0; | ||||
| +			return -EINVAL; | ||||
| +		} | ||||
| +		/* Convert size to nand pages */ | ||||
| +		boot_partition->page_size /= mtd->writesize; | ||||
| +	} | ||||
| + | ||||
| +	return 0; | ||||
| +} | ||||
| + | ||||
|  static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc, | ||||
|  					    struct qcom_nand_host *host, | ||||
|  					    struct device_node *dn) | ||||
| @@ -2979,6 +3159,14 @@ static int qcom_nand_host_init_and_regis | ||||
|  	if (ret) | ||||
|  		nand_cleanup(chip); | ||||
|   | ||||
| +	if (nandc->props->use_codeword_fixup) { | ||||
| +		ret = qcom_nand_host_parse_boot_partitions(nandc, host, dn); | ||||
| +		if (ret) { | ||||
| +			nand_cleanup(chip); | ||||
| +			return ret; | ||||
| +		} | ||||
| +	} | ||||
| + | ||||
|  	return ret; | ||||
|  } | ||||
|   | ||||
| @@ -3144,6 +3332,7 @@ static int qcom_nandc_remove(struct plat | ||||
|  static const struct qcom_nandc_props ipq806x_nandc_props = { | ||||
|  	.ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT), | ||||
|  	.is_bam = false, | ||||
| +	.use_codeword_fixup = true, | ||||
|  	.dev_cmd_reg_start = 0x0, | ||||
|  }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Christian Marangi
					Christian Marangi