+ * @mtd: MTD device structure
+ * @dat: The pointer to data on which ecc is computed (unused here)
+ * @ecc: The ECC output buffer
+ */
+static int omap_calculate_ecc_bch(struct mtd_info *mtd, const uint8_t *dat,
+ uint8_t *ecc)
+{
+ int ret = 0;
+ size_t i;
+ unsigned long nsectors, val1, val2, val3, val4;
+
+ nsectors = ((readl(&gpmc_cfg->ecc_config) >> 4) & 0x7) + 1;
+
+ for (i = 0; i < nsectors; i++) {
+ /* Read hw-computed remainder */
+ val1 = readl(&gpmc_cfg->bch_result_0_3[i].bch_result_x[0]);
+ val2 = readl(&gpmc_cfg->bch_result_0_3[i].bch_result_x[1]);
+ val3 = readl(&gpmc_cfg->bch_result_0_3[i].bch_result_x[2]);
+ val4 = readl(&gpmc_cfg->bch_result_0_3[i].bch_result_x[3]);
+
+ /*
+ * Add constant polynomial to remainder, in order to get an ecc
+ * sequence of 0xFFs for a buffer filled with 0xFFs.
+ */
+ *ecc++ = 0xef ^ (val4 & 0xFF);
+ *ecc++ = 0x51 ^ ((val3 >> 24) & 0xFF);
+ *ecc++ = 0x2e ^ ((val3 >> 16) & 0xFF);
+ *ecc++ = 0x09 ^ ((val3 >> 8) & 0xFF);
+ *ecc++ = 0xed ^ (val3 & 0xFF);
+ *ecc++ = 0x93 ^ ((val2 >> 24) & 0xFF);
+ *ecc++ = 0x9a ^ ((val2 >> 16) & 0xFF);
+ *ecc++ = 0xc2 ^ ((val2 >> 8) & 0xFF);
+ *ecc++ = 0x97 ^ (val2 & 0xFF);
+ *ecc++ = 0x79 ^ ((val1 >> 24) & 0xFF);
+ *ecc++ = 0xe5 ^ ((val1 >> 16) & 0xFF);
+ *ecc++ = 0x24 ^ ((val1 >> 8) & 0xFF);
+ *ecc++ = 0xb5 ^ (val1 & 0xFF);
+ }
+
+ /*
+ * Stop reading anymore ECC vals and clear old results
+ * enable will be called if more reads are required
+ */
+ omap_ecc_disable(mtd);
+
+ return ret;
+}
+
+/**
+ * omap_correct_data_bch - Decode received data and correct errors
+ * @mtd: MTD device structure
+ * @data: page data
+ * @read_ecc: ecc read from nand flash
+ * @calc_ecc: ecc read from HW ECC registers
+ */
+static int omap_correct_data_bch(struct mtd_info *mtd, u_char *data,
+ u_char *read_ecc, u_char *calc_ecc)
+{
+ int i, count;
+ /* cannot correct more than 8 errors */
+ unsigned int errloc[8];
+ struct nand_chip *chip = mtd->priv;
+ struct nand_bch_priv *chip_priv = chip->priv;
+ struct bch_control *bch = chip_priv->control;
+
+ count = decode_bch(bch, NULL, 512, read_ecc, calc_ecc, NULL, errloc);
+ if (count > 0) {
+ /* correct errors */
+ for (i = 0; i < count; i++) {
+ /* correct data only, not ecc bytes */
+ if (errloc[i] < 8*512)
+ data[errloc[i]/8] ^= 1 << (errloc[i] & 7);
+ printf("corrected bitflip %u\n", errloc[i]);
+#ifdef DEBUG
+ puts("read_ecc: ");
+ /*
+ * BCH8 have 13 bytes of ECC; BCH4 needs adoption
+ * here!
+ */
+ for (i = 0; i < 13; i++)
+ printf("%02x ", read_ecc[i]);
+ puts("\n");
+ puts("calc_ecc: ");
+ for (i = 0; i < 13; i++)
+ printf("%02x ", calc_ecc[i]);
+ puts("\n");
+#endif
+ }
+ } else if (count < 0) {
+ puts("ecc unrecoverable error\n");
+ }
+ return count;
+}
+
+/**
+ * omap_free_bch - Release BCH ecc resources
+ * @mtd: MTD device structure
+ */
+static void __maybe_unused omap_free_bch(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct nand_bch_priv *chip_priv = chip->priv;
+ struct bch_control *bch = NULL;
+
+ if (chip_priv)
+ bch = chip_priv->control;
+
+ if (bch) {
+ free_bch(bch);
+ chip_priv->control = NULL;
+ }
+}
+#endif /* CONFIG_NAND_OMAP_BCH8 */
+
+#ifndef CONFIG_SPL_BUILD
+/*
+ * omap_nand_switch_ecc - switch the ECC operation between different engines
+ * (h/w and s/w) and different algorithms (hamming and BCHx)