162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) STMicroelectronics 2018 462306a36Sopenharmony_ci * Author: Christophe Kerello <christophe.kerello@st.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/bitfield.h> 862306a36Sopenharmony_ci#include <linux/clk.h> 962306a36Sopenharmony_ci#include <linux/dmaengine.h> 1062306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1162306a36Sopenharmony_ci#include <linux/errno.h> 1262306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1362306a36Sopenharmony_ci#include <linux/interrupt.h> 1462306a36Sopenharmony_ci#include <linux/iopoll.h> 1562306a36Sopenharmony_ci#include <linux/mfd/syscon.h> 1662306a36Sopenharmony_ci#include <linux/module.h> 1762306a36Sopenharmony_ci#include <linux/mtd/rawnand.h> 1862306a36Sopenharmony_ci#include <linux/of_address.h> 1962306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h> 2062306a36Sopenharmony_ci#include <linux/platform_device.h> 2162306a36Sopenharmony_ci#include <linux/regmap.h> 2262306a36Sopenharmony_ci#include <linux/reset.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* Bad block marker length */ 2562306a36Sopenharmony_ci#define FMC2_BBM_LEN 2 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* ECC step size */ 2862306a36Sopenharmony_ci#define FMC2_ECC_STEP_SIZE 512 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* BCHDSRx registers length */ 3162306a36Sopenharmony_ci#define FMC2_BCHDSRS_LEN 20 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* HECCR length */ 3462306a36Sopenharmony_ci#define FMC2_HECCR_LEN 4 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* Max requests done for a 8k nand page size */ 3762306a36Sopenharmony_ci#define FMC2_MAX_SG 16 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* Max chip enable */ 4062306a36Sopenharmony_ci#define FMC2_MAX_CE 2 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* Max ECC buffer length */ 4362306a36Sopenharmony_ci#define FMC2_MAX_ECC_BUF_LEN (FMC2_BCHDSRS_LEN * FMC2_MAX_SG) 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#define FMC2_TIMEOUT_MS 5000 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* Timings */ 4862306a36Sopenharmony_ci#define FMC2_THIZ 1 4962306a36Sopenharmony_ci#define FMC2_TIO 8000 5062306a36Sopenharmony_ci#define FMC2_TSYNC 3000 5162306a36Sopenharmony_ci#define FMC2_PCR_TIMING_MASK 0xf 5262306a36Sopenharmony_ci#define FMC2_PMEM_PATT_TIMING_MASK 0xff 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* FMC2 Controller Registers */ 5562306a36Sopenharmony_ci#define FMC2_BCR1 0x0 5662306a36Sopenharmony_ci#define FMC2_PCR 0x80 5762306a36Sopenharmony_ci#define FMC2_SR 0x84 5862306a36Sopenharmony_ci#define FMC2_PMEM 0x88 5962306a36Sopenharmony_ci#define FMC2_PATT 0x8c 6062306a36Sopenharmony_ci#define FMC2_HECCR 0x94 6162306a36Sopenharmony_ci#define FMC2_ISR 0x184 6262306a36Sopenharmony_ci#define FMC2_ICR 0x188 6362306a36Sopenharmony_ci#define FMC2_CSQCR 0x200 6462306a36Sopenharmony_ci#define FMC2_CSQCFGR1 0x204 6562306a36Sopenharmony_ci#define FMC2_CSQCFGR2 0x208 6662306a36Sopenharmony_ci#define FMC2_CSQCFGR3 0x20c 6762306a36Sopenharmony_ci#define FMC2_CSQAR1 0x210 6862306a36Sopenharmony_ci#define FMC2_CSQAR2 0x214 6962306a36Sopenharmony_ci#define FMC2_CSQIER 0x220 7062306a36Sopenharmony_ci#define FMC2_CSQISR 0x224 7162306a36Sopenharmony_ci#define FMC2_CSQICR 0x228 7262306a36Sopenharmony_ci#define FMC2_CSQEMSR 0x230 7362306a36Sopenharmony_ci#define FMC2_BCHIER 0x250 7462306a36Sopenharmony_ci#define FMC2_BCHISR 0x254 7562306a36Sopenharmony_ci#define FMC2_BCHICR 0x258 7662306a36Sopenharmony_ci#define FMC2_BCHPBR1 0x260 7762306a36Sopenharmony_ci#define FMC2_BCHPBR2 0x264 7862306a36Sopenharmony_ci#define FMC2_BCHPBR3 0x268 7962306a36Sopenharmony_ci#define FMC2_BCHPBR4 0x26c 8062306a36Sopenharmony_ci#define FMC2_BCHDSR0 0x27c 8162306a36Sopenharmony_ci#define FMC2_BCHDSR1 0x280 8262306a36Sopenharmony_ci#define FMC2_BCHDSR2 0x284 8362306a36Sopenharmony_ci#define FMC2_BCHDSR3 0x288 8462306a36Sopenharmony_ci#define FMC2_BCHDSR4 0x28c 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci/* Register: FMC2_BCR1 */ 8762306a36Sopenharmony_ci#define FMC2_BCR1_FMC2EN BIT(31) 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/* Register: FMC2_PCR */ 9062306a36Sopenharmony_ci#define FMC2_PCR_PWAITEN BIT(1) 9162306a36Sopenharmony_ci#define FMC2_PCR_PBKEN BIT(2) 9262306a36Sopenharmony_ci#define FMC2_PCR_PWID GENMASK(5, 4) 9362306a36Sopenharmony_ci#define FMC2_PCR_PWID_BUSWIDTH_8 0 9462306a36Sopenharmony_ci#define FMC2_PCR_PWID_BUSWIDTH_16 1 9562306a36Sopenharmony_ci#define FMC2_PCR_ECCEN BIT(6) 9662306a36Sopenharmony_ci#define FMC2_PCR_ECCALG BIT(8) 9762306a36Sopenharmony_ci#define FMC2_PCR_TCLR GENMASK(12, 9) 9862306a36Sopenharmony_ci#define FMC2_PCR_TCLR_DEFAULT 0xf 9962306a36Sopenharmony_ci#define FMC2_PCR_TAR GENMASK(16, 13) 10062306a36Sopenharmony_ci#define FMC2_PCR_TAR_DEFAULT 0xf 10162306a36Sopenharmony_ci#define FMC2_PCR_ECCSS GENMASK(19, 17) 10262306a36Sopenharmony_ci#define FMC2_PCR_ECCSS_512 1 10362306a36Sopenharmony_ci#define FMC2_PCR_ECCSS_2048 3 10462306a36Sopenharmony_ci#define FMC2_PCR_BCHECC BIT(24) 10562306a36Sopenharmony_ci#define FMC2_PCR_WEN BIT(25) 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci/* Register: FMC2_SR */ 10862306a36Sopenharmony_ci#define FMC2_SR_NWRF BIT(6) 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci/* Register: FMC2_PMEM */ 11162306a36Sopenharmony_ci#define FMC2_PMEM_MEMSET GENMASK(7, 0) 11262306a36Sopenharmony_ci#define FMC2_PMEM_MEMWAIT GENMASK(15, 8) 11362306a36Sopenharmony_ci#define FMC2_PMEM_MEMHOLD GENMASK(23, 16) 11462306a36Sopenharmony_ci#define FMC2_PMEM_MEMHIZ GENMASK(31, 24) 11562306a36Sopenharmony_ci#define FMC2_PMEM_DEFAULT 0x0a0a0a0a 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci/* Register: FMC2_PATT */ 11862306a36Sopenharmony_ci#define FMC2_PATT_ATTSET GENMASK(7, 0) 11962306a36Sopenharmony_ci#define FMC2_PATT_ATTWAIT GENMASK(15, 8) 12062306a36Sopenharmony_ci#define FMC2_PATT_ATTHOLD GENMASK(23, 16) 12162306a36Sopenharmony_ci#define FMC2_PATT_ATTHIZ GENMASK(31, 24) 12262306a36Sopenharmony_ci#define FMC2_PATT_DEFAULT 0x0a0a0a0a 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci/* Register: FMC2_ISR */ 12562306a36Sopenharmony_ci#define FMC2_ISR_IHLF BIT(1) 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci/* Register: FMC2_ICR */ 12862306a36Sopenharmony_ci#define FMC2_ICR_CIHLF BIT(1) 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci/* Register: FMC2_CSQCR */ 13162306a36Sopenharmony_ci#define FMC2_CSQCR_CSQSTART BIT(0) 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci/* Register: FMC2_CSQCFGR1 */ 13462306a36Sopenharmony_ci#define FMC2_CSQCFGR1_CMD2EN BIT(1) 13562306a36Sopenharmony_ci#define FMC2_CSQCFGR1_DMADEN BIT(2) 13662306a36Sopenharmony_ci#define FMC2_CSQCFGR1_ACYNBR GENMASK(6, 4) 13762306a36Sopenharmony_ci#define FMC2_CSQCFGR1_CMD1 GENMASK(15, 8) 13862306a36Sopenharmony_ci#define FMC2_CSQCFGR1_CMD2 GENMASK(23, 16) 13962306a36Sopenharmony_ci#define FMC2_CSQCFGR1_CMD1T BIT(24) 14062306a36Sopenharmony_ci#define FMC2_CSQCFGR1_CMD2T BIT(25) 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci/* Register: FMC2_CSQCFGR2 */ 14362306a36Sopenharmony_ci#define FMC2_CSQCFGR2_SQSDTEN BIT(0) 14462306a36Sopenharmony_ci#define FMC2_CSQCFGR2_RCMD2EN BIT(1) 14562306a36Sopenharmony_ci#define FMC2_CSQCFGR2_DMASEN BIT(2) 14662306a36Sopenharmony_ci#define FMC2_CSQCFGR2_RCMD1 GENMASK(15, 8) 14762306a36Sopenharmony_ci#define FMC2_CSQCFGR2_RCMD2 GENMASK(23, 16) 14862306a36Sopenharmony_ci#define FMC2_CSQCFGR2_RCMD1T BIT(24) 14962306a36Sopenharmony_ci#define FMC2_CSQCFGR2_RCMD2T BIT(25) 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci/* Register: FMC2_CSQCFGR3 */ 15262306a36Sopenharmony_ci#define FMC2_CSQCFGR3_SNBR GENMASK(13, 8) 15362306a36Sopenharmony_ci#define FMC2_CSQCFGR3_AC1T BIT(16) 15462306a36Sopenharmony_ci#define FMC2_CSQCFGR3_AC2T BIT(17) 15562306a36Sopenharmony_ci#define FMC2_CSQCFGR3_AC3T BIT(18) 15662306a36Sopenharmony_ci#define FMC2_CSQCFGR3_AC4T BIT(19) 15762306a36Sopenharmony_ci#define FMC2_CSQCFGR3_AC5T BIT(20) 15862306a36Sopenharmony_ci#define FMC2_CSQCFGR3_SDT BIT(21) 15962306a36Sopenharmony_ci#define FMC2_CSQCFGR3_RAC1T BIT(22) 16062306a36Sopenharmony_ci#define FMC2_CSQCFGR3_RAC2T BIT(23) 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci/* Register: FMC2_CSQCAR1 */ 16362306a36Sopenharmony_ci#define FMC2_CSQCAR1_ADDC1 GENMASK(7, 0) 16462306a36Sopenharmony_ci#define FMC2_CSQCAR1_ADDC2 GENMASK(15, 8) 16562306a36Sopenharmony_ci#define FMC2_CSQCAR1_ADDC3 GENMASK(23, 16) 16662306a36Sopenharmony_ci#define FMC2_CSQCAR1_ADDC4 GENMASK(31, 24) 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci/* Register: FMC2_CSQCAR2 */ 16962306a36Sopenharmony_ci#define FMC2_CSQCAR2_ADDC5 GENMASK(7, 0) 17062306a36Sopenharmony_ci#define FMC2_CSQCAR2_NANDCEN GENMASK(11, 10) 17162306a36Sopenharmony_ci#define FMC2_CSQCAR2_SAO GENMASK(31, 16) 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci/* Register: FMC2_CSQIER */ 17462306a36Sopenharmony_ci#define FMC2_CSQIER_TCIE BIT(0) 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci/* Register: FMC2_CSQICR */ 17762306a36Sopenharmony_ci#define FMC2_CSQICR_CLEAR_IRQ GENMASK(4, 0) 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci/* Register: FMC2_CSQEMSR */ 18062306a36Sopenharmony_ci#define FMC2_CSQEMSR_SEM GENMASK(15, 0) 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci/* Register: FMC2_BCHIER */ 18362306a36Sopenharmony_ci#define FMC2_BCHIER_DERIE BIT(1) 18462306a36Sopenharmony_ci#define FMC2_BCHIER_EPBRIE BIT(4) 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci/* Register: FMC2_BCHICR */ 18762306a36Sopenharmony_ci#define FMC2_BCHICR_CLEAR_IRQ GENMASK(4, 0) 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci/* Register: FMC2_BCHDSR0 */ 19062306a36Sopenharmony_ci#define FMC2_BCHDSR0_DUE BIT(0) 19162306a36Sopenharmony_ci#define FMC2_BCHDSR0_DEF BIT(1) 19262306a36Sopenharmony_ci#define FMC2_BCHDSR0_DEN GENMASK(7, 4) 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci/* Register: FMC2_BCHDSR1 */ 19562306a36Sopenharmony_ci#define FMC2_BCHDSR1_EBP1 GENMASK(12, 0) 19662306a36Sopenharmony_ci#define FMC2_BCHDSR1_EBP2 GENMASK(28, 16) 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci/* Register: FMC2_BCHDSR2 */ 19962306a36Sopenharmony_ci#define FMC2_BCHDSR2_EBP3 GENMASK(12, 0) 20062306a36Sopenharmony_ci#define FMC2_BCHDSR2_EBP4 GENMASK(28, 16) 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci/* Register: FMC2_BCHDSR3 */ 20362306a36Sopenharmony_ci#define FMC2_BCHDSR3_EBP5 GENMASK(12, 0) 20462306a36Sopenharmony_ci#define FMC2_BCHDSR3_EBP6 GENMASK(28, 16) 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci/* Register: FMC2_BCHDSR4 */ 20762306a36Sopenharmony_ci#define FMC2_BCHDSR4_EBP7 GENMASK(12, 0) 20862306a36Sopenharmony_ci#define FMC2_BCHDSR4_EBP8 GENMASK(28, 16) 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cienum stm32_fmc2_ecc { 21162306a36Sopenharmony_ci FMC2_ECC_HAM = 1, 21262306a36Sopenharmony_ci FMC2_ECC_BCH4 = 4, 21362306a36Sopenharmony_ci FMC2_ECC_BCH8 = 8 21462306a36Sopenharmony_ci}; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cienum stm32_fmc2_irq_state { 21762306a36Sopenharmony_ci FMC2_IRQ_UNKNOWN = 0, 21862306a36Sopenharmony_ci FMC2_IRQ_BCH, 21962306a36Sopenharmony_ci FMC2_IRQ_SEQ 22062306a36Sopenharmony_ci}; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistruct stm32_fmc2_timings { 22362306a36Sopenharmony_ci u8 tclr; 22462306a36Sopenharmony_ci u8 tar; 22562306a36Sopenharmony_ci u8 thiz; 22662306a36Sopenharmony_ci u8 twait; 22762306a36Sopenharmony_ci u8 thold_mem; 22862306a36Sopenharmony_ci u8 tset_mem; 22962306a36Sopenharmony_ci u8 thold_att; 23062306a36Sopenharmony_ci u8 tset_att; 23162306a36Sopenharmony_ci}; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistruct stm32_fmc2_nand { 23462306a36Sopenharmony_ci struct nand_chip chip; 23562306a36Sopenharmony_ci struct gpio_desc *wp_gpio; 23662306a36Sopenharmony_ci struct stm32_fmc2_timings timings; 23762306a36Sopenharmony_ci int ncs; 23862306a36Sopenharmony_ci int cs_used[FMC2_MAX_CE]; 23962306a36Sopenharmony_ci}; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic inline struct stm32_fmc2_nand *to_fmc2_nand(struct nand_chip *chip) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci return container_of(chip, struct stm32_fmc2_nand, chip); 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistruct stm32_fmc2_nfc { 24762306a36Sopenharmony_ci struct nand_controller base; 24862306a36Sopenharmony_ci struct stm32_fmc2_nand nand; 24962306a36Sopenharmony_ci struct device *dev; 25062306a36Sopenharmony_ci struct device *cdev; 25162306a36Sopenharmony_ci struct regmap *regmap; 25262306a36Sopenharmony_ci void __iomem *data_base[FMC2_MAX_CE]; 25362306a36Sopenharmony_ci void __iomem *cmd_base[FMC2_MAX_CE]; 25462306a36Sopenharmony_ci void __iomem *addr_base[FMC2_MAX_CE]; 25562306a36Sopenharmony_ci phys_addr_t io_phys_addr; 25662306a36Sopenharmony_ci phys_addr_t data_phys_addr[FMC2_MAX_CE]; 25762306a36Sopenharmony_ci struct clk *clk; 25862306a36Sopenharmony_ci u8 irq_state; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci struct dma_chan *dma_tx_ch; 26162306a36Sopenharmony_ci struct dma_chan *dma_rx_ch; 26262306a36Sopenharmony_ci struct dma_chan *dma_ecc_ch; 26362306a36Sopenharmony_ci struct sg_table dma_data_sg; 26462306a36Sopenharmony_ci struct sg_table dma_ecc_sg; 26562306a36Sopenharmony_ci u8 *ecc_buf; 26662306a36Sopenharmony_ci int dma_ecc_len; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci struct completion complete; 26962306a36Sopenharmony_ci struct completion dma_data_complete; 27062306a36Sopenharmony_ci struct completion dma_ecc_complete; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci u8 cs_assigned; 27362306a36Sopenharmony_ci int cs_sel; 27462306a36Sopenharmony_ci}; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_cistatic inline struct stm32_fmc2_nfc *to_stm32_nfc(struct nand_controller *base) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci return container_of(base, struct stm32_fmc2_nfc, base); 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic void stm32_fmc2_nfc_timings_init(struct nand_chip *chip) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); 28462306a36Sopenharmony_ci struct stm32_fmc2_nand *nand = to_fmc2_nand(chip); 28562306a36Sopenharmony_ci struct stm32_fmc2_timings *timings = &nand->timings; 28662306a36Sopenharmony_ci u32 pmem, patt; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci /* Set tclr/tar timings */ 28962306a36Sopenharmony_ci regmap_update_bits(nfc->regmap, FMC2_PCR, 29062306a36Sopenharmony_ci FMC2_PCR_TCLR | FMC2_PCR_TAR, 29162306a36Sopenharmony_ci FIELD_PREP(FMC2_PCR_TCLR, timings->tclr) | 29262306a36Sopenharmony_ci FIELD_PREP(FMC2_PCR_TAR, timings->tar)); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci /* Set tset/twait/thold/thiz timings in common bank */ 29562306a36Sopenharmony_ci pmem = FIELD_PREP(FMC2_PMEM_MEMSET, timings->tset_mem); 29662306a36Sopenharmony_ci pmem |= FIELD_PREP(FMC2_PMEM_MEMWAIT, timings->twait); 29762306a36Sopenharmony_ci pmem |= FIELD_PREP(FMC2_PMEM_MEMHOLD, timings->thold_mem); 29862306a36Sopenharmony_ci pmem |= FIELD_PREP(FMC2_PMEM_MEMHIZ, timings->thiz); 29962306a36Sopenharmony_ci regmap_write(nfc->regmap, FMC2_PMEM, pmem); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* Set tset/twait/thold/thiz timings in attribut bank */ 30262306a36Sopenharmony_ci patt = FIELD_PREP(FMC2_PATT_ATTSET, timings->tset_att); 30362306a36Sopenharmony_ci patt |= FIELD_PREP(FMC2_PATT_ATTWAIT, timings->twait); 30462306a36Sopenharmony_ci patt |= FIELD_PREP(FMC2_PATT_ATTHOLD, timings->thold_att); 30562306a36Sopenharmony_ci patt |= FIELD_PREP(FMC2_PATT_ATTHIZ, timings->thiz); 30662306a36Sopenharmony_ci regmap_write(nfc->regmap, FMC2_PATT, patt); 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_cistatic void stm32_fmc2_nfc_setup(struct nand_chip *chip) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); 31262306a36Sopenharmony_ci u32 pcr = 0, pcr_mask; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci /* Configure ECC algorithm (default configuration is Hamming) */ 31562306a36Sopenharmony_ci pcr_mask = FMC2_PCR_ECCALG; 31662306a36Sopenharmony_ci pcr_mask |= FMC2_PCR_BCHECC; 31762306a36Sopenharmony_ci if (chip->ecc.strength == FMC2_ECC_BCH8) { 31862306a36Sopenharmony_ci pcr |= FMC2_PCR_ECCALG; 31962306a36Sopenharmony_ci pcr |= FMC2_PCR_BCHECC; 32062306a36Sopenharmony_ci } else if (chip->ecc.strength == FMC2_ECC_BCH4) { 32162306a36Sopenharmony_ci pcr |= FMC2_PCR_ECCALG; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci /* Set buswidth */ 32562306a36Sopenharmony_ci pcr_mask |= FMC2_PCR_PWID; 32662306a36Sopenharmony_ci if (chip->options & NAND_BUSWIDTH_16) 32762306a36Sopenharmony_ci pcr |= FIELD_PREP(FMC2_PCR_PWID, FMC2_PCR_PWID_BUSWIDTH_16); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci /* Set ECC sector size */ 33062306a36Sopenharmony_ci pcr_mask |= FMC2_PCR_ECCSS; 33162306a36Sopenharmony_ci pcr |= FIELD_PREP(FMC2_PCR_ECCSS, FMC2_PCR_ECCSS_512); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci regmap_update_bits(nfc->regmap, FMC2_PCR, pcr_mask, pcr); 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic int stm32_fmc2_nfc_select_chip(struct nand_chip *chip, int chipnr) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); 33962306a36Sopenharmony_ci struct stm32_fmc2_nand *nand = to_fmc2_nand(chip); 34062306a36Sopenharmony_ci struct dma_slave_config dma_cfg; 34162306a36Sopenharmony_ci int ret; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (nand->cs_used[chipnr] == nfc->cs_sel) 34462306a36Sopenharmony_ci return 0; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci nfc->cs_sel = nand->cs_used[chipnr]; 34762306a36Sopenharmony_ci stm32_fmc2_nfc_setup(chip); 34862306a36Sopenharmony_ci stm32_fmc2_nfc_timings_init(chip); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci if (nfc->dma_tx_ch && nfc->dma_rx_ch) { 35162306a36Sopenharmony_ci memset(&dma_cfg, 0, sizeof(dma_cfg)); 35262306a36Sopenharmony_ci dma_cfg.src_addr = nfc->data_phys_addr[nfc->cs_sel]; 35362306a36Sopenharmony_ci dma_cfg.dst_addr = nfc->data_phys_addr[nfc->cs_sel]; 35462306a36Sopenharmony_ci dma_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 35562306a36Sopenharmony_ci dma_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 35662306a36Sopenharmony_ci dma_cfg.src_maxburst = 32; 35762306a36Sopenharmony_ci dma_cfg.dst_maxburst = 32; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci ret = dmaengine_slave_config(nfc->dma_tx_ch, &dma_cfg); 36062306a36Sopenharmony_ci if (ret) { 36162306a36Sopenharmony_ci dev_err(nfc->dev, "tx DMA engine slave config failed\n"); 36262306a36Sopenharmony_ci return ret; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci ret = dmaengine_slave_config(nfc->dma_rx_ch, &dma_cfg); 36662306a36Sopenharmony_ci if (ret) { 36762306a36Sopenharmony_ci dev_err(nfc->dev, "rx DMA engine slave config failed\n"); 36862306a36Sopenharmony_ci return ret; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci if (nfc->dma_ecc_ch) { 37362306a36Sopenharmony_ci /* 37462306a36Sopenharmony_ci * Hamming: we read HECCR register 37562306a36Sopenharmony_ci * BCH4/BCH8: we read BCHDSRSx registers 37662306a36Sopenharmony_ci */ 37762306a36Sopenharmony_ci memset(&dma_cfg, 0, sizeof(dma_cfg)); 37862306a36Sopenharmony_ci dma_cfg.src_addr = nfc->io_phys_addr; 37962306a36Sopenharmony_ci dma_cfg.src_addr += chip->ecc.strength == FMC2_ECC_HAM ? 38062306a36Sopenharmony_ci FMC2_HECCR : FMC2_BCHDSR0; 38162306a36Sopenharmony_ci dma_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci ret = dmaengine_slave_config(nfc->dma_ecc_ch, &dma_cfg); 38462306a36Sopenharmony_ci if (ret) { 38562306a36Sopenharmony_ci dev_err(nfc->dev, "ECC DMA engine slave config failed\n"); 38662306a36Sopenharmony_ci return ret; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci /* Calculate ECC length needed for one sector */ 39062306a36Sopenharmony_ci nfc->dma_ecc_len = chip->ecc.strength == FMC2_ECC_HAM ? 39162306a36Sopenharmony_ci FMC2_HECCR_LEN : FMC2_BCHDSRS_LEN; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci return 0; 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_cistatic void stm32_fmc2_nfc_set_buswidth_16(struct stm32_fmc2_nfc *nfc, bool set) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci u32 pcr; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci pcr = set ? FIELD_PREP(FMC2_PCR_PWID, FMC2_PCR_PWID_BUSWIDTH_16) : 40262306a36Sopenharmony_ci FIELD_PREP(FMC2_PCR_PWID, FMC2_PCR_PWID_BUSWIDTH_8); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci regmap_update_bits(nfc->regmap, FMC2_PCR, FMC2_PCR_PWID, pcr); 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic void stm32_fmc2_nfc_set_ecc(struct stm32_fmc2_nfc *nfc, bool enable) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci regmap_update_bits(nfc->regmap, FMC2_PCR, FMC2_PCR_ECCEN, 41062306a36Sopenharmony_ci enable ? FMC2_PCR_ECCEN : 0); 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cistatic void stm32_fmc2_nfc_enable_seq_irq(struct stm32_fmc2_nfc *nfc) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci nfc->irq_state = FMC2_IRQ_SEQ; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci regmap_update_bits(nfc->regmap, FMC2_CSQIER, 41862306a36Sopenharmony_ci FMC2_CSQIER_TCIE, FMC2_CSQIER_TCIE); 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic void stm32_fmc2_nfc_disable_seq_irq(struct stm32_fmc2_nfc *nfc) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci regmap_update_bits(nfc->regmap, FMC2_CSQIER, FMC2_CSQIER_TCIE, 0); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci nfc->irq_state = FMC2_IRQ_UNKNOWN; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic void stm32_fmc2_nfc_clear_seq_irq(struct stm32_fmc2_nfc *nfc) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci regmap_write(nfc->regmap, FMC2_CSQICR, FMC2_CSQICR_CLEAR_IRQ); 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic void stm32_fmc2_nfc_enable_bch_irq(struct stm32_fmc2_nfc *nfc, int mode) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci nfc->irq_state = FMC2_IRQ_BCH; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci if (mode == NAND_ECC_WRITE) 43862306a36Sopenharmony_ci regmap_update_bits(nfc->regmap, FMC2_BCHIER, 43962306a36Sopenharmony_ci FMC2_BCHIER_EPBRIE, FMC2_BCHIER_EPBRIE); 44062306a36Sopenharmony_ci else 44162306a36Sopenharmony_ci regmap_update_bits(nfc->regmap, FMC2_BCHIER, 44262306a36Sopenharmony_ci FMC2_BCHIER_DERIE, FMC2_BCHIER_DERIE); 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cistatic void stm32_fmc2_nfc_disable_bch_irq(struct stm32_fmc2_nfc *nfc) 44662306a36Sopenharmony_ci{ 44762306a36Sopenharmony_ci regmap_update_bits(nfc->regmap, FMC2_BCHIER, 44862306a36Sopenharmony_ci FMC2_BCHIER_DERIE | FMC2_BCHIER_EPBRIE, 0); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci nfc->irq_state = FMC2_IRQ_UNKNOWN; 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_cistatic void stm32_fmc2_nfc_clear_bch_irq(struct stm32_fmc2_nfc *nfc) 45462306a36Sopenharmony_ci{ 45562306a36Sopenharmony_ci regmap_write(nfc->regmap, FMC2_BCHICR, FMC2_BCHICR_CLEAR_IRQ); 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci/* 45962306a36Sopenharmony_ci * Enable ECC logic and reset syndrome/parity bits previously calculated 46062306a36Sopenharmony_ci * Syndrome/parity bits is cleared by setting the ECCEN bit to 0 46162306a36Sopenharmony_ci */ 46262306a36Sopenharmony_cistatic void stm32_fmc2_nfc_hwctl(struct nand_chip *chip, int mode) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci stm32_fmc2_nfc_set_ecc(nfc, false); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci if (chip->ecc.strength != FMC2_ECC_HAM) { 46962306a36Sopenharmony_ci regmap_update_bits(nfc->regmap, FMC2_PCR, FMC2_PCR_WEN, 47062306a36Sopenharmony_ci mode == NAND_ECC_WRITE ? FMC2_PCR_WEN : 0); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci reinit_completion(&nfc->complete); 47362306a36Sopenharmony_ci stm32_fmc2_nfc_clear_bch_irq(nfc); 47462306a36Sopenharmony_ci stm32_fmc2_nfc_enable_bch_irq(nfc, mode); 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci stm32_fmc2_nfc_set_ecc(nfc, true); 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci/* 48162306a36Sopenharmony_ci * ECC Hamming calculation 48262306a36Sopenharmony_ci * ECC is 3 bytes for 512 bytes of data (supports error correction up to 48362306a36Sopenharmony_ci * max of 1-bit) 48462306a36Sopenharmony_ci */ 48562306a36Sopenharmony_cistatic void stm32_fmc2_nfc_ham_set_ecc(const u32 ecc_sta, u8 *ecc) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci ecc[0] = ecc_sta; 48862306a36Sopenharmony_ci ecc[1] = ecc_sta >> 8; 48962306a36Sopenharmony_ci ecc[2] = ecc_sta >> 16; 49062306a36Sopenharmony_ci} 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_cistatic int stm32_fmc2_nfc_ham_calculate(struct nand_chip *chip, const u8 *data, 49362306a36Sopenharmony_ci u8 *ecc) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); 49662306a36Sopenharmony_ci u32 sr, heccr; 49762306a36Sopenharmony_ci int ret; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci ret = regmap_read_poll_timeout(nfc->regmap, FMC2_SR, sr, 50062306a36Sopenharmony_ci sr & FMC2_SR_NWRF, 1, 50162306a36Sopenharmony_ci 1000 * FMC2_TIMEOUT_MS); 50262306a36Sopenharmony_ci if (ret) { 50362306a36Sopenharmony_ci dev_err(nfc->dev, "ham timeout\n"); 50462306a36Sopenharmony_ci return ret; 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci regmap_read(nfc->regmap, FMC2_HECCR, &heccr); 50862306a36Sopenharmony_ci stm32_fmc2_nfc_ham_set_ecc(heccr, ecc); 50962306a36Sopenharmony_ci stm32_fmc2_nfc_set_ecc(nfc, false); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci return 0; 51262306a36Sopenharmony_ci} 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_cistatic int stm32_fmc2_nfc_ham_correct(struct nand_chip *chip, u8 *dat, 51562306a36Sopenharmony_ci u8 *read_ecc, u8 *calc_ecc) 51662306a36Sopenharmony_ci{ 51762306a36Sopenharmony_ci u8 bit_position = 0, b0, b1, b2; 51862306a36Sopenharmony_ci u32 byte_addr = 0, b; 51962306a36Sopenharmony_ci u32 i, shifting = 1; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci /* Indicate which bit and byte is faulty (if any) */ 52262306a36Sopenharmony_ci b0 = read_ecc[0] ^ calc_ecc[0]; 52362306a36Sopenharmony_ci b1 = read_ecc[1] ^ calc_ecc[1]; 52462306a36Sopenharmony_ci b2 = read_ecc[2] ^ calc_ecc[2]; 52562306a36Sopenharmony_ci b = b0 | (b1 << 8) | (b2 << 16); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci /* No errors */ 52862306a36Sopenharmony_ci if (likely(!b)) 52962306a36Sopenharmony_ci return 0; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci /* Calculate bit position */ 53262306a36Sopenharmony_ci for (i = 0; i < 3; i++) { 53362306a36Sopenharmony_ci switch (b % 4) { 53462306a36Sopenharmony_ci case 2: 53562306a36Sopenharmony_ci bit_position += shifting; 53662306a36Sopenharmony_ci break; 53762306a36Sopenharmony_ci case 1: 53862306a36Sopenharmony_ci break; 53962306a36Sopenharmony_ci default: 54062306a36Sopenharmony_ci return -EBADMSG; 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci shifting <<= 1; 54362306a36Sopenharmony_ci b >>= 2; 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci /* Calculate byte position */ 54762306a36Sopenharmony_ci shifting = 1; 54862306a36Sopenharmony_ci for (i = 0; i < 9; i++) { 54962306a36Sopenharmony_ci switch (b % 4) { 55062306a36Sopenharmony_ci case 2: 55162306a36Sopenharmony_ci byte_addr += shifting; 55262306a36Sopenharmony_ci break; 55362306a36Sopenharmony_ci case 1: 55462306a36Sopenharmony_ci break; 55562306a36Sopenharmony_ci default: 55662306a36Sopenharmony_ci return -EBADMSG; 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci shifting <<= 1; 55962306a36Sopenharmony_ci b >>= 2; 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci /* Flip the bit */ 56362306a36Sopenharmony_ci dat[byte_addr] ^= (1 << bit_position); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci return 1; 56662306a36Sopenharmony_ci} 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci/* 56962306a36Sopenharmony_ci * ECC BCH calculation and correction 57062306a36Sopenharmony_ci * ECC is 7/13 bytes for 512 bytes of data (supports error correction up to 57162306a36Sopenharmony_ci * max of 4-bit/8-bit) 57262306a36Sopenharmony_ci */ 57362306a36Sopenharmony_cistatic int stm32_fmc2_nfc_bch_calculate(struct nand_chip *chip, const u8 *data, 57462306a36Sopenharmony_ci u8 *ecc) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); 57762306a36Sopenharmony_ci u32 bchpbr; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci /* Wait until the BCH code is ready */ 58062306a36Sopenharmony_ci if (!wait_for_completion_timeout(&nfc->complete, 58162306a36Sopenharmony_ci msecs_to_jiffies(FMC2_TIMEOUT_MS))) { 58262306a36Sopenharmony_ci dev_err(nfc->dev, "bch timeout\n"); 58362306a36Sopenharmony_ci stm32_fmc2_nfc_disable_bch_irq(nfc); 58462306a36Sopenharmony_ci return -ETIMEDOUT; 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci /* Read parity bits */ 58862306a36Sopenharmony_ci regmap_read(nfc->regmap, FMC2_BCHPBR1, &bchpbr); 58962306a36Sopenharmony_ci ecc[0] = bchpbr; 59062306a36Sopenharmony_ci ecc[1] = bchpbr >> 8; 59162306a36Sopenharmony_ci ecc[2] = bchpbr >> 16; 59262306a36Sopenharmony_ci ecc[3] = bchpbr >> 24; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci regmap_read(nfc->regmap, FMC2_BCHPBR2, &bchpbr); 59562306a36Sopenharmony_ci ecc[4] = bchpbr; 59662306a36Sopenharmony_ci ecc[5] = bchpbr >> 8; 59762306a36Sopenharmony_ci ecc[6] = bchpbr >> 16; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci if (chip->ecc.strength == FMC2_ECC_BCH8) { 60062306a36Sopenharmony_ci ecc[7] = bchpbr >> 24; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci regmap_read(nfc->regmap, FMC2_BCHPBR3, &bchpbr); 60362306a36Sopenharmony_ci ecc[8] = bchpbr; 60462306a36Sopenharmony_ci ecc[9] = bchpbr >> 8; 60562306a36Sopenharmony_ci ecc[10] = bchpbr >> 16; 60662306a36Sopenharmony_ci ecc[11] = bchpbr >> 24; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci regmap_read(nfc->regmap, FMC2_BCHPBR4, &bchpbr); 60962306a36Sopenharmony_ci ecc[12] = bchpbr; 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci stm32_fmc2_nfc_set_ecc(nfc, false); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci return 0; 61562306a36Sopenharmony_ci} 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_cistatic int stm32_fmc2_nfc_bch_decode(int eccsize, u8 *dat, u32 *ecc_sta) 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci u32 bchdsr0 = ecc_sta[0]; 62062306a36Sopenharmony_ci u32 bchdsr1 = ecc_sta[1]; 62162306a36Sopenharmony_ci u32 bchdsr2 = ecc_sta[2]; 62262306a36Sopenharmony_ci u32 bchdsr3 = ecc_sta[3]; 62362306a36Sopenharmony_ci u32 bchdsr4 = ecc_sta[4]; 62462306a36Sopenharmony_ci u16 pos[8]; 62562306a36Sopenharmony_ci int i, den; 62662306a36Sopenharmony_ci unsigned int nb_errs = 0; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci /* No errors found */ 62962306a36Sopenharmony_ci if (likely(!(bchdsr0 & FMC2_BCHDSR0_DEF))) 63062306a36Sopenharmony_ci return 0; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci /* Too many errors detected */ 63362306a36Sopenharmony_ci if (unlikely(bchdsr0 & FMC2_BCHDSR0_DUE)) 63462306a36Sopenharmony_ci return -EBADMSG; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci pos[0] = FIELD_GET(FMC2_BCHDSR1_EBP1, bchdsr1); 63762306a36Sopenharmony_ci pos[1] = FIELD_GET(FMC2_BCHDSR1_EBP2, bchdsr1); 63862306a36Sopenharmony_ci pos[2] = FIELD_GET(FMC2_BCHDSR2_EBP3, bchdsr2); 63962306a36Sopenharmony_ci pos[3] = FIELD_GET(FMC2_BCHDSR2_EBP4, bchdsr2); 64062306a36Sopenharmony_ci pos[4] = FIELD_GET(FMC2_BCHDSR3_EBP5, bchdsr3); 64162306a36Sopenharmony_ci pos[5] = FIELD_GET(FMC2_BCHDSR3_EBP6, bchdsr3); 64262306a36Sopenharmony_ci pos[6] = FIELD_GET(FMC2_BCHDSR4_EBP7, bchdsr4); 64362306a36Sopenharmony_ci pos[7] = FIELD_GET(FMC2_BCHDSR4_EBP8, bchdsr4); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci den = FIELD_GET(FMC2_BCHDSR0_DEN, bchdsr0); 64662306a36Sopenharmony_ci for (i = 0; i < den; i++) { 64762306a36Sopenharmony_ci if (pos[i] < eccsize * 8) { 64862306a36Sopenharmony_ci change_bit(pos[i], (unsigned long *)dat); 64962306a36Sopenharmony_ci nb_errs++; 65062306a36Sopenharmony_ci } 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci return nb_errs; 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_cistatic int stm32_fmc2_nfc_bch_correct(struct nand_chip *chip, u8 *dat, 65762306a36Sopenharmony_ci u8 *read_ecc, u8 *calc_ecc) 65862306a36Sopenharmony_ci{ 65962306a36Sopenharmony_ci struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); 66062306a36Sopenharmony_ci u32 ecc_sta[5]; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci /* Wait until the decoding error is ready */ 66362306a36Sopenharmony_ci if (!wait_for_completion_timeout(&nfc->complete, 66462306a36Sopenharmony_ci msecs_to_jiffies(FMC2_TIMEOUT_MS))) { 66562306a36Sopenharmony_ci dev_err(nfc->dev, "bch timeout\n"); 66662306a36Sopenharmony_ci stm32_fmc2_nfc_disable_bch_irq(nfc); 66762306a36Sopenharmony_ci return -ETIMEDOUT; 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci regmap_bulk_read(nfc->regmap, FMC2_BCHDSR0, ecc_sta, 5); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci stm32_fmc2_nfc_set_ecc(nfc, false); 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci return stm32_fmc2_nfc_bch_decode(chip->ecc.size, dat, ecc_sta); 67562306a36Sopenharmony_ci} 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_cistatic int stm32_fmc2_nfc_read_page(struct nand_chip *chip, u8 *buf, 67862306a36Sopenharmony_ci int oob_required, int page) 67962306a36Sopenharmony_ci{ 68062306a36Sopenharmony_ci struct mtd_info *mtd = nand_to_mtd(chip); 68162306a36Sopenharmony_ci int ret, i, s, stat, eccsize = chip->ecc.size; 68262306a36Sopenharmony_ci int eccbytes = chip->ecc.bytes; 68362306a36Sopenharmony_ci int eccsteps = chip->ecc.steps; 68462306a36Sopenharmony_ci int eccstrength = chip->ecc.strength; 68562306a36Sopenharmony_ci u8 *p = buf; 68662306a36Sopenharmony_ci u8 *ecc_calc = chip->ecc.calc_buf; 68762306a36Sopenharmony_ci u8 *ecc_code = chip->ecc.code_buf; 68862306a36Sopenharmony_ci unsigned int max_bitflips = 0; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci ret = nand_read_page_op(chip, page, 0, NULL, 0); 69162306a36Sopenharmony_ci if (ret) 69262306a36Sopenharmony_ci return ret; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci for (i = mtd->writesize + FMC2_BBM_LEN, s = 0; s < eccsteps; 69562306a36Sopenharmony_ci s++, i += eccbytes, p += eccsize) { 69662306a36Sopenharmony_ci chip->ecc.hwctl(chip, NAND_ECC_READ); 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci /* Read the nand page sector (512 bytes) */ 69962306a36Sopenharmony_ci ret = nand_change_read_column_op(chip, s * eccsize, p, 70062306a36Sopenharmony_ci eccsize, false); 70162306a36Sopenharmony_ci if (ret) 70262306a36Sopenharmony_ci return ret; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci /* Read the corresponding ECC bytes */ 70562306a36Sopenharmony_ci ret = nand_change_read_column_op(chip, i, ecc_code, 70662306a36Sopenharmony_ci eccbytes, false); 70762306a36Sopenharmony_ci if (ret) 70862306a36Sopenharmony_ci return ret; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci /* Correct the data */ 71162306a36Sopenharmony_ci stat = chip->ecc.correct(chip, p, ecc_code, ecc_calc); 71262306a36Sopenharmony_ci if (stat == -EBADMSG) 71362306a36Sopenharmony_ci /* Check for empty pages with bitflips */ 71462306a36Sopenharmony_ci stat = nand_check_erased_ecc_chunk(p, eccsize, 71562306a36Sopenharmony_ci ecc_code, eccbytes, 71662306a36Sopenharmony_ci NULL, 0, 71762306a36Sopenharmony_ci eccstrength); 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci if (stat < 0) { 72062306a36Sopenharmony_ci mtd->ecc_stats.failed++; 72162306a36Sopenharmony_ci } else { 72262306a36Sopenharmony_ci mtd->ecc_stats.corrected += stat; 72362306a36Sopenharmony_ci max_bitflips = max_t(unsigned int, max_bitflips, stat); 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci } 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci /* Read oob */ 72862306a36Sopenharmony_ci if (oob_required) { 72962306a36Sopenharmony_ci ret = nand_change_read_column_op(chip, mtd->writesize, 73062306a36Sopenharmony_ci chip->oob_poi, mtd->oobsize, 73162306a36Sopenharmony_ci false); 73262306a36Sopenharmony_ci if (ret) 73362306a36Sopenharmony_ci return ret; 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci return max_bitflips; 73762306a36Sopenharmony_ci} 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci/* Sequencer read/write configuration */ 74062306a36Sopenharmony_cistatic void stm32_fmc2_nfc_rw_page_init(struct nand_chip *chip, int page, 74162306a36Sopenharmony_ci int raw, bool write_data) 74262306a36Sopenharmony_ci{ 74362306a36Sopenharmony_ci struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); 74462306a36Sopenharmony_ci struct mtd_info *mtd = nand_to_mtd(chip); 74562306a36Sopenharmony_ci u32 ecc_offset = mtd->writesize + FMC2_BBM_LEN; 74662306a36Sopenharmony_ci /* 74762306a36Sopenharmony_ci * cfg[0] => csqcfgr1, cfg[1] => csqcfgr2, cfg[2] => csqcfgr3 74862306a36Sopenharmony_ci * cfg[3] => csqar1, cfg[4] => csqar2 74962306a36Sopenharmony_ci */ 75062306a36Sopenharmony_ci u32 cfg[5]; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci regmap_update_bits(nfc->regmap, FMC2_PCR, FMC2_PCR_WEN, 75362306a36Sopenharmony_ci write_data ? FMC2_PCR_WEN : 0); 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci /* 75662306a36Sopenharmony_ci * - Set Program Page/Page Read command 75762306a36Sopenharmony_ci * - Enable DMA request data 75862306a36Sopenharmony_ci * - Set timings 75962306a36Sopenharmony_ci */ 76062306a36Sopenharmony_ci cfg[0] = FMC2_CSQCFGR1_DMADEN | FMC2_CSQCFGR1_CMD1T; 76162306a36Sopenharmony_ci if (write_data) 76262306a36Sopenharmony_ci cfg[0] |= FIELD_PREP(FMC2_CSQCFGR1_CMD1, NAND_CMD_SEQIN); 76362306a36Sopenharmony_ci else 76462306a36Sopenharmony_ci cfg[0] |= FIELD_PREP(FMC2_CSQCFGR1_CMD1, NAND_CMD_READ0) | 76562306a36Sopenharmony_ci FMC2_CSQCFGR1_CMD2EN | 76662306a36Sopenharmony_ci FIELD_PREP(FMC2_CSQCFGR1_CMD2, NAND_CMD_READSTART) | 76762306a36Sopenharmony_ci FMC2_CSQCFGR1_CMD2T; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci /* 77062306a36Sopenharmony_ci * - Set Random Data Input/Random Data Read command 77162306a36Sopenharmony_ci * - Enable the sequencer to access the Spare data area 77262306a36Sopenharmony_ci * - Enable DMA request status decoding for read 77362306a36Sopenharmony_ci * - Set timings 77462306a36Sopenharmony_ci */ 77562306a36Sopenharmony_ci if (write_data) 77662306a36Sopenharmony_ci cfg[1] = FIELD_PREP(FMC2_CSQCFGR2_RCMD1, NAND_CMD_RNDIN); 77762306a36Sopenharmony_ci else 77862306a36Sopenharmony_ci cfg[1] = FIELD_PREP(FMC2_CSQCFGR2_RCMD1, NAND_CMD_RNDOUT) | 77962306a36Sopenharmony_ci FMC2_CSQCFGR2_RCMD2EN | 78062306a36Sopenharmony_ci FIELD_PREP(FMC2_CSQCFGR2_RCMD2, NAND_CMD_RNDOUTSTART) | 78162306a36Sopenharmony_ci FMC2_CSQCFGR2_RCMD1T | 78262306a36Sopenharmony_ci FMC2_CSQCFGR2_RCMD2T; 78362306a36Sopenharmony_ci if (!raw) { 78462306a36Sopenharmony_ci cfg[1] |= write_data ? 0 : FMC2_CSQCFGR2_DMASEN; 78562306a36Sopenharmony_ci cfg[1] |= FMC2_CSQCFGR2_SQSDTEN; 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci /* 78962306a36Sopenharmony_ci * - Set the number of sectors to be written 79062306a36Sopenharmony_ci * - Set timings 79162306a36Sopenharmony_ci */ 79262306a36Sopenharmony_ci cfg[2] = FIELD_PREP(FMC2_CSQCFGR3_SNBR, chip->ecc.steps - 1); 79362306a36Sopenharmony_ci if (write_data) { 79462306a36Sopenharmony_ci cfg[2] |= FMC2_CSQCFGR3_RAC2T; 79562306a36Sopenharmony_ci if (chip->options & NAND_ROW_ADDR_3) 79662306a36Sopenharmony_ci cfg[2] |= FMC2_CSQCFGR3_AC5T; 79762306a36Sopenharmony_ci else 79862306a36Sopenharmony_ci cfg[2] |= FMC2_CSQCFGR3_AC4T; 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci /* 80262306a36Sopenharmony_ci * Set the fourth first address cycles 80362306a36Sopenharmony_ci * Byte 1 and byte 2 => column, we start at 0x0 80462306a36Sopenharmony_ci * Byte 3 and byte 4 => page 80562306a36Sopenharmony_ci */ 80662306a36Sopenharmony_ci cfg[3] = FIELD_PREP(FMC2_CSQCAR1_ADDC3, page); 80762306a36Sopenharmony_ci cfg[3] |= FIELD_PREP(FMC2_CSQCAR1_ADDC4, page >> 8); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci /* 81062306a36Sopenharmony_ci * - Set chip enable number 81162306a36Sopenharmony_ci * - Set ECC byte offset in the spare area 81262306a36Sopenharmony_ci * - Calculate the number of address cycles to be issued 81362306a36Sopenharmony_ci * - Set byte 5 of address cycle if needed 81462306a36Sopenharmony_ci */ 81562306a36Sopenharmony_ci cfg[4] = FIELD_PREP(FMC2_CSQCAR2_NANDCEN, nfc->cs_sel); 81662306a36Sopenharmony_ci if (chip->options & NAND_BUSWIDTH_16) 81762306a36Sopenharmony_ci cfg[4] |= FIELD_PREP(FMC2_CSQCAR2_SAO, ecc_offset >> 1); 81862306a36Sopenharmony_ci else 81962306a36Sopenharmony_ci cfg[4] |= FIELD_PREP(FMC2_CSQCAR2_SAO, ecc_offset); 82062306a36Sopenharmony_ci if (chip->options & NAND_ROW_ADDR_3) { 82162306a36Sopenharmony_ci cfg[0] |= FIELD_PREP(FMC2_CSQCFGR1_ACYNBR, 5); 82262306a36Sopenharmony_ci cfg[4] |= FIELD_PREP(FMC2_CSQCAR2_ADDC5, page >> 16); 82362306a36Sopenharmony_ci } else { 82462306a36Sopenharmony_ci cfg[0] |= FIELD_PREP(FMC2_CSQCFGR1_ACYNBR, 4); 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci regmap_bulk_write(nfc->regmap, FMC2_CSQCFGR1, cfg, 5); 82862306a36Sopenharmony_ci} 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_cistatic void stm32_fmc2_nfc_dma_callback(void *arg) 83162306a36Sopenharmony_ci{ 83262306a36Sopenharmony_ci complete((struct completion *)arg); 83362306a36Sopenharmony_ci} 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci/* Read/write data from/to a page */ 83662306a36Sopenharmony_cistatic int stm32_fmc2_nfc_xfer(struct nand_chip *chip, const u8 *buf, 83762306a36Sopenharmony_ci int raw, bool write_data) 83862306a36Sopenharmony_ci{ 83962306a36Sopenharmony_ci struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); 84062306a36Sopenharmony_ci struct dma_async_tx_descriptor *desc_data, *desc_ecc; 84162306a36Sopenharmony_ci struct scatterlist *sg; 84262306a36Sopenharmony_ci struct dma_chan *dma_ch = nfc->dma_rx_ch; 84362306a36Sopenharmony_ci enum dma_data_direction dma_data_dir = DMA_FROM_DEVICE; 84462306a36Sopenharmony_ci enum dma_transfer_direction dma_transfer_dir = DMA_DEV_TO_MEM; 84562306a36Sopenharmony_ci int eccsteps = chip->ecc.steps; 84662306a36Sopenharmony_ci int eccsize = chip->ecc.size; 84762306a36Sopenharmony_ci unsigned long timeout = msecs_to_jiffies(FMC2_TIMEOUT_MS); 84862306a36Sopenharmony_ci const u8 *p = buf; 84962306a36Sopenharmony_ci int s, ret; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci /* Configure DMA data */ 85262306a36Sopenharmony_ci if (write_data) { 85362306a36Sopenharmony_ci dma_data_dir = DMA_TO_DEVICE; 85462306a36Sopenharmony_ci dma_transfer_dir = DMA_MEM_TO_DEV; 85562306a36Sopenharmony_ci dma_ch = nfc->dma_tx_ch; 85662306a36Sopenharmony_ci } 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci for_each_sg(nfc->dma_data_sg.sgl, sg, eccsteps, s) { 85962306a36Sopenharmony_ci sg_set_buf(sg, p, eccsize); 86062306a36Sopenharmony_ci p += eccsize; 86162306a36Sopenharmony_ci } 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci ret = dma_map_sg(nfc->dev, nfc->dma_data_sg.sgl, 86462306a36Sopenharmony_ci eccsteps, dma_data_dir); 86562306a36Sopenharmony_ci if (!ret) 86662306a36Sopenharmony_ci return -EIO; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci desc_data = dmaengine_prep_slave_sg(dma_ch, nfc->dma_data_sg.sgl, 86962306a36Sopenharmony_ci eccsteps, dma_transfer_dir, 87062306a36Sopenharmony_ci DMA_PREP_INTERRUPT); 87162306a36Sopenharmony_ci if (!desc_data) { 87262306a36Sopenharmony_ci ret = -ENOMEM; 87362306a36Sopenharmony_ci goto err_unmap_data; 87462306a36Sopenharmony_ci } 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci reinit_completion(&nfc->dma_data_complete); 87762306a36Sopenharmony_ci reinit_completion(&nfc->complete); 87862306a36Sopenharmony_ci desc_data->callback = stm32_fmc2_nfc_dma_callback; 87962306a36Sopenharmony_ci desc_data->callback_param = &nfc->dma_data_complete; 88062306a36Sopenharmony_ci ret = dma_submit_error(dmaengine_submit(desc_data)); 88162306a36Sopenharmony_ci if (ret) 88262306a36Sopenharmony_ci goto err_unmap_data; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci dma_async_issue_pending(dma_ch); 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci if (!write_data && !raw) { 88762306a36Sopenharmony_ci /* Configure DMA ECC status */ 88862306a36Sopenharmony_ci p = nfc->ecc_buf; 88962306a36Sopenharmony_ci for_each_sg(nfc->dma_ecc_sg.sgl, sg, eccsteps, s) { 89062306a36Sopenharmony_ci sg_set_buf(sg, p, nfc->dma_ecc_len); 89162306a36Sopenharmony_ci p += nfc->dma_ecc_len; 89262306a36Sopenharmony_ci } 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci ret = dma_map_sg(nfc->dev, nfc->dma_ecc_sg.sgl, 89562306a36Sopenharmony_ci eccsteps, dma_data_dir); 89662306a36Sopenharmony_ci if (!ret) { 89762306a36Sopenharmony_ci ret = -EIO; 89862306a36Sopenharmony_ci goto err_unmap_data; 89962306a36Sopenharmony_ci } 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci desc_ecc = dmaengine_prep_slave_sg(nfc->dma_ecc_ch, 90262306a36Sopenharmony_ci nfc->dma_ecc_sg.sgl, 90362306a36Sopenharmony_ci eccsteps, dma_transfer_dir, 90462306a36Sopenharmony_ci DMA_PREP_INTERRUPT); 90562306a36Sopenharmony_ci if (!desc_ecc) { 90662306a36Sopenharmony_ci ret = -ENOMEM; 90762306a36Sopenharmony_ci goto err_unmap_ecc; 90862306a36Sopenharmony_ci } 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci reinit_completion(&nfc->dma_ecc_complete); 91162306a36Sopenharmony_ci desc_ecc->callback = stm32_fmc2_nfc_dma_callback; 91262306a36Sopenharmony_ci desc_ecc->callback_param = &nfc->dma_ecc_complete; 91362306a36Sopenharmony_ci ret = dma_submit_error(dmaengine_submit(desc_ecc)); 91462306a36Sopenharmony_ci if (ret) 91562306a36Sopenharmony_ci goto err_unmap_ecc; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci dma_async_issue_pending(nfc->dma_ecc_ch); 91862306a36Sopenharmony_ci } 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci stm32_fmc2_nfc_clear_seq_irq(nfc); 92162306a36Sopenharmony_ci stm32_fmc2_nfc_enable_seq_irq(nfc); 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci /* Start the transfer */ 92462306a36Sopenharmony_ci regmap_update_bits(nfc->regmap, FMC2_CSQCR, 92562306a36Sopenharmony_ci FMC2_CSQCR_CSQSTART, FMC2_CSQCR_CSQSTART); 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci /* Wait end of sequencer transfer */ 92862306a36Sopenharmony_ci if (!wait_for_completion_timeout(&nfc->complete, timeout)) { 92962306a36Sopenharmony_ci dev_err(nfc->dev, "seq timeout\n"); 93062306a36Sopenharmony_ci stm32_fmc2_nfc_disable_seq_irq(nfc); 93162306a36Sopenharmony_ci dmaengine_terminate_all(dma_ch); 93262306a36Sopenharmony_ci if (!write_data && !raw) 93362306a36Sopenharmony_ci dmaengine_terminate_all(nfc->dma_ecc_ch); 93462306a36Sopenharmony_ci ret = -ETIMEDOUT; 93562306a36Sopenharmony_ci goto err_unmap_ecc; 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci /* Wait DMA data transfer completion */ 93962306a36Sopenharmony_ci if (!wait_for_completion_timeout(&nfc->dma_data_complete, timeout)) { 94062306a36Sopenharmony_ci dev_err(nfc->dev, "data DMA timeout\n"); 94162306a36Sopenharmony_ci dmaengine_terminate_all(dma_ch); 94262306a36Sopenharmony_ci ret = -ETIMEDOUT; 94362306a36Sopenharmony_ci } 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci /* Wait DMA ECC transfer completion */ 94662306a36Sopenharmony_ci if (!write_data && !raw) { 94762306a36Sopenharmony_ci if (!wait_for_completion_timeout(&nfc->dma_ecc_complete, 94862306a36Sopenharmony_ci timeout)) { 94962306a36Sopenharmony_ci dev_err(nfc->dev, "ECC DMA timeout\n"); 95062306a36Sopenharmony_ci dmaengine_terminate_all(nfc->dma_ecc_ch); 95162306a36Sopenharmony_ci ret = -ETIMEDOUT; 95262306a36Sopenharmony_ci } 95362306a36Sopenharmony_ci } 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_cierr_unmap_ecc: 95662306a36Sopenharmony_ci if (!write_data && !raw) 95762306a36Sopenharmony_ci dma_unmap_sg(nfc->dev, nfc->dma_ecc_sg.sgl, 95862306a36Sopenharmony_ci eccsteps, dma_data_dir); 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_cierr_unmap_data: 96162306a36Sopenharmony_ci dma_unmap_sg(nfc->dev, nfc->dma_data_sg.sgl, eccsteps, dma_data_dir); 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci return ret; 96462306a36Sopenharmony_ci} 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_cistatic int stm32_fmc2_nfc_seq_write(struct nand_chip *chip, const u8 *buf, 96762306a36Sopenharmony_ci int oob_required, int page, int raw) 96862306a36Sopenharmony_ci{ 96962306a36Sopenharmony_ci struct mtd_info *mtd = nand_to_mtd(chip); 97062306a36Sopenharmony_ci int ret; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci /* Configure the sequencer */ 97362306a36Sopenharmony_ci stm32_fmc2_nfc_rw_page_init(chip, page, raw, true); 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci /* Write the page */ 97662306a36Sopenharmony_ci ret = stm32_fmc2_nfc_xfer(chip, buf, raw, true); 97762306a36Sopenharmony_ci if (ret) 97862306a36Sopenharmony_ci return ret; 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci /* Write oob */ 98162306a36Sopenharmony_ci if (oob_required) { 98262306a36Sopenharmony_ci ret = nand_change_write_column_op(chip, mtd->writesize, 98362306a36Sopenharmony_ci chip->oob_poi, mtd->oobsize, 98462306a36Sopenharmony_ci false); 98562306a36Sopenharmony_ci if (ret) 98662306a36Sopenharmony_ci return ret; 98762306a36Sopenharmony_ci } 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci return nand_prog_page_end_op(chip); 99062306a36Sopenharmony_ci} 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_cistatic int stm32_fmc2_nfc_seq_write_page(struct nand_chip *chip, const u8 *buf, 99362306a36Sopenharmony_ci int oob_required, int page) 99462306a36Sopenharmony_ci{ 99562306a36Sopenharmony_ci int ret; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci ret = stm32_fmc2_nfc_select_chip(chip, chip->cur_cs); 99862306a36Sopenharmony_ci if (ret) 99962306a36Sopenharmony_ci return ret; 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci return stm32_fmc2_nfc_seq_write(chip, buf, oob_required, page, false); 100262306a36Sopenharmony_ci} 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_cistatic int stm32_fmc2_nfc_seq_write_page_raw(struct nand_chip *chip, 100562306a36Sopenharmony_ci const u8 *buf, int oob_required, 100662306a36Sopenharmony_ci int page) 100762306a36Sopenharmony_ci{ 100862306a36Sopenharmony_ci int ret; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci ret = stm32_fmc2_nfc_select_chip(chip, chip->cur_cs); 101162306a36Sopenharmony_ci if (ret) 101262306a36Sopenharmony_ci return ret; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci return stm32_fmc2_nfc_seq_write(chip, buf, oob_required, page, true); 101562306a36Sopenharmony_ci} 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci/* Get a status indicating which sectors have errors */ 101862306a36Sopenharmony_cistatic u16 stm32_fmc2_nfc_get_mapping_status(struct stm32_fmc2_nfc *nfc) 101962306a36Sopenharmony_ci{ 102062306a36Sopenharmony_ci u32 csqemsr; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci regmap_read(nfc->regmap, FMC2_CSQEMSR, &csqemsr); 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci return FIELD_GET(FMC2_CSQEMSR_SEM, csqemsr); 102562306a36Sopenharmony_ci} 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_cistatic int stm32_fmc2_nfc_seq_correct(struct nand_chip *chip, u8 *dat, 102862306a36Sopenharmony_ci u8 *read_ecc, u8 *calc_ecc) 102962306a36Sopenharmony_ci{ 103062306a36Sopenharmony_ci struct mtd_info *mtd = nand_to_mtd(chip); 103162306a36Sopenharmony_ci struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); 103262306a36Sopenharmony_ci int eccbytes = chip->ecc.bytes; 103362306a36Sopenharmony_ci int eccsteps = chip->ecc.steps; 103462306a36Sopenharmony_ci int eccstrength = chip->ecc.strength; 103562306a36Sopenharmony_ci int i, s, eccsize = chip->ecc.size; 103662306a36Sopenharmony_ci u32 *ecc_sta = (u32 *)nfc->ecc_buf; 103762306a36Sopenharmony_ci u16 sta_map = stm32_fmc2_nfc_get_mapping_status(nfc); 103862306a36Sopenharmony_ci unsigned int max_bitflips = 0; 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, dat += eccsize) { 104162306a36Sopenharmony_ci int stat = 0; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci if (eccstrength == FMC2_ECC_HAM) { 104462306a36Sopenharmony_ci /* Ecc_sta = FMC2_HECCR */ 104562306a36Sopenharmony_ci if (sta_map & BIT(s)) { 104662306a36Sopenharmony_ci stm32_fmc2_nfc_ham_set_ecc(*ecc_sta, 104762306a36Sopenharmony_ci &calc_ecc[i]); 104862306a36Sopenharmony_ci stat = stm32_fmc2_nfc_ham_correct(chip, dat, 104962306a36Sopenharmony_ci &read_ecc[i], 105062306a36Sopenharmony_ci &calc_ecc[i]); 105162306a36Sopenharmony_ci } 105262306a36Sopenharmony_ci ecc_sta++; 105362306a36Sopenharmony_ci } else { 105462306a36Sopenharmony_ci /* 105562306a36Sopenharmony_ci * Ecc_sta[0] = FMC2_BCHDSR0 105662306a36Sopenharmony_ci * Ecc_sta[1] = FMC2_BCHDSR1 105762306a36Sopenharmony_ci * Ecc_sta[2] = FMC2_BCHDSR2 105862306a36Sopenharmony_ci * Ecc_sta[3] = FMC2_BCHDSR3 105962306a36Sopenharmony_ci * Ecc_sta[4] = FMC2_BCHDSR4 106062306a36Sopenharmony_ci */ 106162306a36Sopenharmony_ci if (sta_map & BIT(s)) 106262306a36Sopenharmony_ci stat = stm32_fmc2_nfc_bch_decode(eccsize, dat, 106362306a36Sopenharmony_ci ecc_sta); 106462306a36Sopenharmony_ci ecc_sta += 5; 106562306a36Sopenharmony_ci } 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci if (stat == -EBADMSG) 106862306a36Sopenharmony_ci /* Check for empty pages with bitflips */ 106962306a36Sopenharmony_ci stat = nand_check_erased_ecc_chunk(dat, eccsize, 107062306a36Sopenharmony_ci &read_ecc[i], 107162306a36Sopenharmony_ci eccbytes, 107262306a36Sopenharmony_ci NULL, 0, 107362306a36Sopenharmony_ci eccstrength); 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci if (stat < 0) { 107662306a36Sopenharmony_ci mtd->ecc_stats.failed++; 107762306a36Sopenharmony_ci } else { 107862306a36Sopenharmony_ci mtd->ecc_stats.corrected += stat; 107962306a36Sopenharmony_ci max_bitflips = max_t(unsigned int, max_bitflips, stat); 108062306a36Sopenharmony_ci } 108162306a36Sopenharmony_ci } 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci return max_bitflips; 108462306a36Sopenharmony_ci} 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_cistatic int stm32_fmc2_nfc_seq_read_page(struct nand_chip *chip, u8 *buf, 108762306a36Sopenharmony_ci int oob_required, int page) 108862306a36Sopenharmony_ci{ 108962306a36Sopenharmony_ci struct mtd_info *mtd = nand_to_mtd(chip); 109062306a36Sopenharmony_ci struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); 109162306a36Sopenharmony_ci u8 *ecc_calc = chip->ecc.calc_buf; 109262306a36Sopenharmony_ci u8 *ecc_code = chip->ecc.code_buf; 109362306a36Sopenharmony_ci u16 sta_map; 109462306a36Sopenharmony_ci int ret; 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci ret = stm32_fmc2_nfc_select_chip(chip, chip->cur_cs); 109762306a36Sopenharmony_ci if (ret) 109862306a36Sopenharmony_ci return ret; 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci /* Configure the sequencer */ 110162306a36Sopenharmony_ci stm32_fmc2_nfc_rw_page_init(chip, page, 0, false); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci /* Read the page */ 110462306a36Sopenharmony_ci ret = stm32_fmc2_nfc_xfer(chip, buf, 0, false); 110562306a36Sopenharmony_ci if (ret) 110662306a36Sopenharmony_ci return ret; 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci sta_map = stm32_fmc2_nfc_get_mapping_status(nfc); 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci /* Check if errors happen */ 111162306a36Sopenharmony_ci if (likely(!sta_map)) { 111262306a36Sopenharmony_ci if (oob_required) 111362306a36Sopenharmony_ci return nand_change_read_column_op(chip, mtd->writesize, 111462306a36Sopenharmony_ci chip->oob_poi, 111562306a36Sopenharmony_ci mtd->oobsize, false); 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci return 0; 111862306a36Sopenharmony_ci } 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci /* Read oob */ 112162306a36Sopenharmony_ci ret = nand_change_read_column_op(chip, mtd->writesize, 112262306a36Sopenharmony_ci chip->oob_poi, mtd->oobsize, false); 112362306a36Sopenharmony_ci if (ret) 112462306a36Sopenharmony_ci return ret; 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0, 112762306a36Sopenharmony_ci chip->ecc.total); 112862306a36Sopenharmony_ci if (ret) 112962306a36Sopenharmony_ci return ret; 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci /* Correct data */ 113262306a36Sopenharmony_ci return chip->ecc.correct(chip, buf, ecc_code, ecc_calc); 113362306a36Sopenharmony_ci} 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_cistatic int stm32_fmc2_nfc_seq_read_page_raw(struct nand_chip *chip, u8 *buf, 113662306a36Sopenharmony_ci int oob_required, int page) 113762306a36Sopenharmony_ci{ 113862306a36Sopenharmony_ci struct mtd_info *mtd = nand_to_mtd(chip); 113962306a36Sopenharmony_ci int ret; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci ret = stm32_fmc2_nfc_select_chip(chip, chip->cur_cs); 114262306a36Sopenharmony_ci if (ret) 114362306a36Sopenharmony_ci return ret; 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci /* Configure the sequencer */ 114662306a36Sopenharmony_ci stm32_fmc2_nfc_rw_page_init(chip, page, 1, false); 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci /* Read the page */ 114962306a36Sopenharmony_ci ret = stm32_fmc2_nfc_xfer(chip, buf, 1, false); 115062306a36Sopenharmony_ci if (ret) 115162306a36Sopenharmony_ci return ret; 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci /* Read oob */ 115462306a36Sopenharmony_ci if (oob_required) 115562306a36Sopenharmony_ci return nand_change_read_column_op(chip, mtd->writesize, 115662306a36Sopenharmony_ci chip->oob_poi, mtd->oobsize, 115762306a36Sopenharmony_ci false); 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci return 0; 116062306a36Sopenharmony_ci} 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_cistatic irqreturn_t stm32_fmc2_nfc_irq(int irq, void *dev_id) 116362306a36Sopenharmony_ci{ 116462306a36Sopenharmony_ci struct stm32_fmc2_nfc *nfc = (struct stm32_fmc2_nfc *)dev_id; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci if (nfc->irq_state == FMC2_IRQ_SEQ) 116762306a36Sopenharmony_ci /* Sequencer is used */ 116862306a36Sopenharmony_ci stm32_fmc2_nfc_disable_seq_irq(nfc); 116962306a36Sopenharmony_ci else if (nfc->irq_state == FMC2_IRQ_BCH) 117062306a36Sopenharmony_ci /* BCH is used */ 117162306a36Sopenharmony_ci stm32_fmc2_nfc_disable_bch_irq(nfc); 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci complete(&nfc->complete); 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci return IRQ_HANDLED; 117662306a36Sopenharmony_ci} 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_cistatic void stm32_fmc2_nfc_read_data(struct nand_chip *chip, void *buf, 117962306a36Sopenharmony_ci unsigned int len, bool force_8bit) 118062306a36Sopenharmony_ci{ 118162306a36Sopenharmony_ci struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); 118262306a36Sopenharmony_ci void __iomem *io_addr_r = nfc->data_base[nfc->cs_sel]; 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci if (force_8bit && chip->options & NAND_BUSWIDTH_16) 118562306a36Sopenharmony_ci /* Reconfigure bus width to 8-bit */ 118662306a36Sopenharmony_ci stm32_fmc2_nfc_set_buswidth_16(nfc, false); 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci if (!IS_ALIGNED((uintptr_t)buf, sizeof(u32))) { 118962306a36Sopenharmony_ci if (!IS_ALIGNED((uintptr_t)buf, sizeof(u16)) && len) { 119062306a36Sopenharmony_ci *(u8 *)buf = readb_relaxed(io_addr_r); 119162306a36Sopenharmony_ci buf += sizeof(u8); 119262306a36Sopenharmony_ci len -= sizeof(u8); 119362306a36Sopenharmony_ci } 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci if (!IS_ALIGNED((uintptr_t)buf, sizeof(u32)) && 119662306a36Sopenharmony_ci len >= sizeof(u16)) { 119762306a36Sopenharmony_ci *(u16 *)buf = readw_relaxed(io_addr_r); 119862306a36Sopenharmony_ci buf += sizeof(u16); 119962306a36Sopenharmony_ci len -= sizeof(u16); 120062306a36Sopenharmony_ci } 120162306a36Sopenharmony_ci } 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci /* Buf is aligned */ 120462306a36Sopenharmony_ci while (len >= sizeof(u32)) { 120562306a36Sopenharmony_ci *(u32 *)buf = readl_relaxed(io_addr_r); 120662306a36Sopenharmony_ci buf += sizeof(u32); 120762306a36Sopenharmony_ci len -= sizeof(u32); 120862306a36Sopenharmony_ci } 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci /* Read remaining bytes */ 121162306a36Sopenharmony_ci if (len >= sizeof(u16)) { 121262306a36Sopenharmony_ci *(u16 *)buf = readw_relaxed(io_addr_r); 121362306a36Sopenharmony_ci buf += sizeof(u16); 121462306a36Sopenharmony_ci len -= sizeof(u16); 121562306a36Sopenharmony_ci } 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci if (len) 121862306a36Sopenharmony_ci *(u8 *)buf = readb_relaxed(io_addr_r); 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci if (force_8bit && chip->options & NAND_BUSWIDTH_16) 122162306a36Sopenharmony_ci /* Reconfigure bus width to 16-bit */ 122262306a36Sopenharmony_ci stm32_fmc2_nfc_set_buswidth_16(nfc, true); 122362306a36Sopenharmony_ci} 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_cistatic void stm32_fmc2_nfc_write_data(struct nand_chip *chip, const void *buf, 122662306a36Sopenharmony_ci unsigned int len, bool force_8bit) 122762306a36Sopenharmony_ci{ 122862306a36Sopenharmony_ci struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); 122962306a36Sopenharmony_ci void __iomem *io_addr_w = nfc->data_base[nfc->cs_sel]; 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci if (force_8bit && chip->options & NAND_BUSWIDTH_16) 123262306a36Sopenharmony_ci /* Reconfigure bus width to 8-bit */ 123362306a36Sopenharmony_ci stm32_fmc2_nfc_set_buswidth_16(nfc, false); 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci if (!IS_ALIGNED((uintptr_t)buf, sizeof(u32))) { 123662306a36Sopenharmony_ci if (!IS_ALIGNED((uintptr_t)buf, sizeof(u16)) && len) { 123762306a36Sopenharmony_ci writeb_relaxed(*(u8 *)buf, io_addr_w); 123862306a36Sopenharmony_ci buf += sizeof(u8); 123962306a36Sopenharmony_ci len -= sizeof(u8); 124062306a36Sopenharmony_ci } 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci if (!IS_ALIGNED((uintptr_t)buf, sizeof(u32)) && 124362306a36Sopenharmony_ci len >= sizeof(u16)) { 124462306a36Sopenharmony_ci writew_relaxed(*(u16 *)buf, io_addr_w); 124562306a36Sopenharmony_ci buf += sizeof(u16); 124662306a36Sopenharmony_ci len -= sizeof(u16); 124762306a36Sopenharmony_ci } 124862306a36Sopenharmony_ci } 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci /* Buf is aligned */ 125162306a36Sopenharmony_ci while (len >= sizeof(u32)) { 125262306a36Sopenharmony_ci writel_relaxed(*(u32 *)buf, io_addr_w); 125362306a36Sopenharmony_ci buf += sizeof(u32); 125462306a36Sopenharmony_ci len -= sizeof(u32); 125562306a36Sopenharmony_ci } 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci /* Write remaining bytes */ 125862306a36Sopenharmony_ci if (len >= sizeof(u16)) { 125962306a36Sopenharmony_ci writew_relaxed(*(u16 *)buf, io_addr_w); 126062306a36Sopenharmony_ci buf += sizeof(u16); 126162306a36Sopenharmony_ci len -= sizeof(u16); 126262306a36Sopenharmony_ci } 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci if (len) 126562306a36Sopenharmony_ci writeb_relaxed(*(u8 *)buf, io_addr_w); 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci if (force_8bit && chip->options & NAND_BUSWIDTH_16) 126862306a36Sopenharmony_ci /* Reconfigure bus width to 16-bit */ 126962306a36Sopenharmony_ci stm32_fmc2_nfc_set_buswidth_16(nfc, true); 127062306a36Sopenharmony_ci} 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_cistatic int stm32_fmc2_nfc_waitrdy(struct nand_chip *chip, 127362306a36Sopenharmony_ci unsigned long timeout_ms) 127462306a36Sopenharmony_ci{ 127562306a36Sopenharmony_ci struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); 127662306a36Sopenharmony_ci const struct nand_sdr_timings *timings; 127762306a36Sopenharmony_ci u32 isr, sr; 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci /* Check if there is no pending requests to the NAND flash */ 128062306a36Sopenharmony_ci if (regmap_read_poll_timeout(nfc->regmap, FMC2_SR, sr, 128162306a36Sopenharmony_ci sr & FMC2_SR_NWRF, 1, 128262306a36Sopenharmony_ci 1000 * FMC2_TIMEOUT_MS)) 128362306a36Sopenharmony_ci dev_warn(nfc->dev, "Waitrdy timeout\n"); 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci /* Wait tWB before R/B# signal is low */ 128662306a36Sopenharmony_ci timings = nand_get_sdr_timings(nand_get_interface_config(chip)); 128762306a36Sopenharmony_ci ndelay(PSEC_TO_NSEC(timings->tWB_max)); 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci /* R/B# signal is low, clear high level flag */ 129062306a36Sopenharmony_ci regmap_write(nfc->regmap, FMC2_ICR, FMC2_ICR_CIHLF); 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci /* Wait R/B# signal is high */ 129362306a36Sopenharmony_ci return regmap_read_poll_timeout(nfc->regmap, FMC2_ISR, isr, 129462306a36Sopenharmony_ci isr & FMC2_ISR_IHLF, 5, 129562306a36Sopenharmony_ci 1000 * FMC2_TIMEOUT_MS); 129662306a36Sopenharmony_ci} 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_cistatic int stm32_fmc2_nfc_exec_op(struct nand_chip *chip, 129962306a36Sopenharmony_ci const struct nand_operation *op, 130062306a36Sopenharmony_ci bool check_only) 130162306a36Sopenharmony_ci{ 130262306a36Sopenharmony_ci struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); 130362306a36Sopenharmony_ci const struct nand_op_instr *instr = NULL; 130462306a36Sopenharmony_ci unsigned int op_id, i, timeout; 130562306a36Sopenharmony_ci int ret; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci if (check_only) 130862306a36Sopenharmony_ci return 0; 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci ret = stm32_fmc2_nfc_select_chip(chip, op->cs); 131162306a36Sopenharmony_ci if (ret) 131262306a36Sopenharmony_ci return ret; 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci for (op_id = 0; op_id < op->ninstrs; op_id++) { 131562306a36Sopenharmony_ci instr = &op->instrs[op_id]; 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci switch (instr->type) { 131862306a36Sopenharmony_ci case NAND_OP_CMD_INSTR: 131962306a36Sopenharmony_ci writeb_relaxed(instr->ctx.cmd.opcode, 132062306a36Sopenharmony_ci nfc->cmd_base[nfc->cs_sel]); 132162306a36Sopenharmony_ci break; 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci case NAND_OP_ADDR_INSTR: 132462306a36Sopenharmony_ci for (i = 0; i < instr->ctx.addr.naddrs; i++) 132562306a36Sopenharmony_ci writeb_relaxed(instr->ctx.addr.addrs[i], 132662306a36Sopenharmony_ci nfc->addr_base[nfc->cs_sel]); 132762306a36Sopenharmony_ci break; 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci case NAND_OP_DATA_IN_INSTR: 133062306a36Sopenharmony_ci stm32_fmc2_nfc_read_data(chip, instr->ctx.data.buf.in, 133162306a36Sopenharmony_ci instr->ctx.data.len, 133262306a36Sopenharmony_ci instr->ctx.data.force_8bit); 133362306a36Sopenharmony_ci break; 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci case NAND_OP_DATA_OUT_INSTR: 133662306a36Sopenharmony_ci stm32_fmc2_nfc_write_data(chip, instr->ctx.data.buf.out, 133762306a36Sopenharmony_ci instr->ctx.data.len, 133862306a36Sopenharmony_ci instr->ctx.data.force_8bit); 133962306a36Sopenharmony_ci break; 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci case NAND_OP_WAITRDY_INSTR: 134262306a36Sopenharmony_ci timeout = instr->ctx.waitrdy.timeout_ms; 134362306a36Sopenharmony_ci ret = stm32_fmc2_nfc_waitrdy(chip, timeout); 134462306a36Sopenharmony_ci break; 134562306a36Sopenharmony_ci } 134662306a36Sopenharmony_ci } 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci return ret; 134962306a36Sopenharmony_ci} 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_cistatic void stm32_fmc2_nfc_init(struct stm32_fmc2_nfc *nfc) 135262306a36Sopenharmony_ci{ 135362306a36Sopenharmony_ci u32 pcr; 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci regmap_read(nfc->regmap, FMC2_PCR, &pcr); 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci /* Set CS used to undefined */ 135862306a36Sopenharmony_ci nfc->cs_sel = -1; 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci /* Enable wait feature and nand flash memory bank */ 136162306a36Sopenharmony_ci pcr |= FMC2_PCR_PWAITEN; 136262306a36Sopenharmony_ci pcr |= FMC2_PCR_PBKEN; 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci /* Set buswidth to 8 bits mode for identification */ 136562306a36Sopenharmony_ci pcr &= ~FMC2_PCR_PWID; 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci /* ECC logic is disabled */ 136862306a36Sopenharmony_ci pcr &= ~FMC2_PCR_ECCEN; 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci /* Default mode */ 137162306a36Sopenharmony_ci pcr &= ~FMC2_PCR_ECCALG; 137262306a36Sopenharmony_ci pcr &= ~FMC2_PCR_BCHECC; 137362306a36Sopenharmony_ci pcr &= ~FMC2_PCR_WEN; 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci /* Set default ECC sector size */ 137662306a36Sopenharmony_ci pcr &= ~FMC2_PCR_ECCSS; 137762306a36Sopenharmony_ci pcr |= FIELD_PREP(FMC2_PCR_ECCSS, FMC2_PCR_ECCSS_2048); 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci /* Set default tclr/tar timings */ 138062306a36Sopenharmony_ci pcr &= ~FMC2_PCR_TCLR; 138162306a36Sopenharmony_ci pcr |= FIELD_PREP(FMC2_PCR_TCLR, FMC2_PCR_TCLR_DEFAULT); 138262306a36Sopenharmony_ci pcr &= ~FMC2_PCR_TAR; 138362306a36Sopenharmony_ci pcr |= FIELD_PREP(FMC2_PCR_TAR, FMC2_PCR_TAR_DEFAULT); 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci /* Enable FMC2 controller */ 138662306a36Sopenharmony_ci if (nfc->dev == nfc->cdev) 138762306a36Sopenharmony_ci regmap_update_bits(nfc->regmap, FMC2_BCR1, 138862306a36Sopenharmony_ci FMC2_BCR1_FMC2EN, FMC2_BCR1_FMC2EN); 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci regmap_write(nfc->regmap, FMC2_PCR, pcr); 139162306a36Sopenharmony_ci regmap_write(nfc->regmap, FMC2_PMEM, FMC2_PMEM_DEFAULT); 139262306a36Sopenharmony_ci regmap_write(nfc->regmap, FMC2_PATT, FMC2_PATT_DEFAULT); 139362306a36Sopenharmony_ci} 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_cistatic void stm32_fmc2_nfc_calc_timings(struct nand_chip *chip, 139662306a36Sopenharmony_ci const struct nand_sdr_timings *sdrt) 139762306a36Sopenharmony_ci{ 139862306a36Sopenharmony_ci struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); 139962306a36Sopenharmony_ci struct stm32_fmc2_nand *nand = to_fmc2_nand(chip); 140062306a36Sopenharmony_ci struct stm32_fmc2_timings *tims = &nand->timings; 140162306a36Sopenharmony_ci unsigned long hclk = clk_get_rate(nfc->clk); 140262306a36Sopenharmony_ci unsigned long hclkp = NSEC_PER_SEC / (hclk / 1000); 140362306a36Sopenharmony_ci unsigned long timing, tar, tclr, thiz, twait; 140462306a36Sopenharmony_ci unsigned long tset_mem, tset_att, thold_mem, thold_att; 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci tar = max_t(unsigned long, hclkp, sdrt->tAR_min); 140762306a36Sopenharmony_ci timing = DIV_ROUND_UP(tar, hclkp) - 1; 140862306a36Sopenharmony_ci tims->tar = min_t(unsigned long, timing, FMC2_PCR_TIMING_MASK); 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci tclr = max_t(unsigned long, hclkp, sdrt->tCLR_min); 141162306a36Sopenharmony_ci timing = DIV_ROUND_UP(tclr, hclkp) - 1; 141262306a36Sopenharmony_ci tims->tclr = min_t(unsigned long, timing, FMC2_PCR_TIMING_MASK); 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci tims->thiz = FMC2_THIZ; 141562306a36Sopenharmony_ci thiz = (tims->thiz + 1) * hclkp; 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci /* 141862306a36Sopenharmony_ci * tWAIT > tRP 141962306a36Sopenharmony_ci * tWAIT > tWP 142062306a36Sopenharmony_ci * tWAIT > tREA + tIO 142162306a36Sopenharmony_ci */ 142262306a36Sopenharmony_ci twait = max_t(unsigned long, hclkp, sdrt->tRP_min); 142362306a36Sopenharmony_ci twait = max_t(unsigned long, twait, sdrt->tWP_min); 142462306a36Sopenharmony_ci twait = max_t(unsigned long, twait, sdrt->tREA_max + FMC2_TIO); 142562306a36Sopenharmony_ci timing = DIV_ROUND_UP(twait, hclkp); 142662306a36Sopenharmony_ci tims->twait = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK); 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci /* 142962306a36Sopenharmony_ci * tSETUP_MEM > tCS - tWAIT 143062306a36Sopenharmony_ci * tSETUP_MEM > tALS - tWAIT 143162306a36Sopenharmony_ci * tSETUP_MEM > tDS - (tWAIT - tHIZ) 143262306a36Sopenharmony_ci */ 143362306a36Sopenharmony_ci tset_mem = hclkp; 143462306a36Sopenharmony_ci if (sdrt->tCS_min > twait && (tset_mem < sdrt->tCS_min - twait)) 143562306a36Sopenharmony_ci tset_mem = sdrt->tCS_min - twait; 143662306a36Sopenharmony_ci if (sdrt->tALS_min > twait && (tset_mem < sdrt->tALS_min - twait)) 143762306a36Sopenharmony_ci tset_mem = sdrt->tALS_min - twait; 143862306a36Sopenharmony_ci if (twait > thiz && (sdrt->tDS_min > twait - thiz) && 143962306a36Sopenharmony_ci (tset_mem < sdrt->tDS_min - (twait - thiz))) 144062306a36Sopenharmony_ci tset_mem = sdrt->tDS_min - (twait - thiz); 144162306a36Sopenharmony_ci timing = DIV_ROUND_UP(tset_mem, hclkp); 144262306a36Sopenharmony_ci tims->tset_mem = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK); 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci /* 144562306a36Sopenharmony_ci * tHOLD_MEM > tCH 144662306a36Sopenharmony_ci * tHOLD_MEM > tREH - tSETUP_MEM 144762306a36Sopenharmony_ci * tHOLD_MEM > max(tRC, tWC) - (tSETUP_MEM + tWAIT) 144862306a36Sopenharmony_ci */ 144962306a36Sopenharmony_ci thold_mem = max_t(unsigned long, hclkp, sdrt->tCH_min); 145062306a36Sopenharmony_ci if (sdrt->tREH_min > tset_mem && 145162306a36Sopenharmony_ci (thold_mem < sdrt->tREH_min - tset_mem)) 145262306a36Sopenharmony_ci thold_mem = sdrt->tREH_min - tset_mem; 145362306a36Sopenharmony_ci if ((sdrt->tRC_min > tset_mem + twait) && 145462306a36Sopenharmony_ci (thold_mem < sdrt->tRC_min - (tset_mem + twait))) 145562306a36Sopenharmony_ci thold_mem = sdrt->tRC_min - (tset_mem + twait); 145662306a36Sopenharmony_ci if ((sdrt->tWC_min > tset_mem + twait) && 145762306a36Sopenharmony_ci (thold_mem < sdrt->tWC_min - (tset_mem + twait))) 145862306a36Sopenharmony_ci thold_mem = sdrt->tWC_min - (tset_mem + twait); 145962306a36Sopenharmony_ci timing = DIV_ROUND_UP(thold_mem, hclkp); 146062306a36Sopenharmony_ci tims->thold_mem = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK); 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci /* 146362306a36Sopenharmony_ci * tSETUP_ATT > tCS - tWAIT 146462306a36Sopenharmony_ci * tSETUP_ATT > tCLS - tWAIT 146562306a36Sopenharmony_ci * tSETUP_ATT > tALS - tWAIT 146662306a36Sopenharmony_ci * tSETUP_ATT > tRHW - tHOLD_MEM 146762306a36Sopenharmony_ci * tSETUP_ATT > tDS - (tWAIT - tHIZ) 146862306a36Sopenharmony_ci */ 146962306a36Sopenharmony_ci tset_att = hclkp; 147062306a36Sopenharmony_ci if (sdrt->tCS_min > twait && (tset_att < sdrt->tCS_min - twait)) 147162306a36Sopenharmony_ci tset_att = sdrt->tCS_min - twait; 147262306a36Sopenharmony_ci if (sdrt->tCLS_min > twait && (tset_att < sdrt->tCLS_min - twait)) 147362306a36Sopenharmony_ci tset_att = sdrt->tCLS_min - twait; 147462306a36Sopenharmony_ci if (sdrt->tALS_min > twait && (tset_att < sdrt->tALS_min - twait)) 147562306a36Sopenharmony_ci tset_att = sdrt->tALS_min - twait; 147662306a36Sopenharmony_ci if (sdrt->tRHW_min > thold_mem && 147762306a36Sopenharmony_ci (tset_att < sdrt->tRHW_min - thold_mem)) 147862306a36Sopenharmony_ci tset_att = sdrt->tRHW_min - thold_mem; 147962306a36Sopenharmony_ci if (twait > thiz && (sdrt->tDS_min > twait - thiz) && 148062306a36Sopenharmony_ci (tset_att < sdrt->tDS_min - (twait - thiz))) 148162306a36Sopenharmony_ci tset_att = sdrt->tDS_min - (twait - thiz); 148262306a36Sopenharmony_ci timing = DIV_ROUND_UP(tset_att, hclkp); 148362306a36Sopenharmony_ci tims->tset_att = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK); 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci /* 148662306a36Sopenharmony_ci * tHOLD_ATT > tALH 148762306a36Sopenharmony_ci * tHOLD_ATT > tCH 148862306a36Sopenharmony_ci * tHOLD_ATT > tCLH 148962306a36Sopenharmony_ci * tHOLD_ATT > tCOH 149062306a36Sopenharmony_ci * tHOLD_ATT > tDH 149162306a36Sopenharmony_ci * tHOLD_ATT > tWB + tIO + tSYNC - tSETUP_MEM 149262306a36Sopenharmony_ci * tHOLD_ATT > tADL - tSETUP_MEM 149362306a36Sopenharmony_ci * tHOLD_ATT > tWH - tSETUP_MEM 149462306a36Sopenharmony_ci * tHOLD_ATT > tWHR - tSETUP_MEM 149562306a36Sopenharmony_ci * tHOLD_ATT > tRC - (tSETUP_ATT + tWAIT) 149662306a36Sopenharmony_ci * tHOLD_ATT > tWC - (tSETUP_ATT + tWAIT) 149762306a36Sopenharmony_ci */ 149862306a36Sopenharmony_ci thold_att = max_t(unsigned long, hclkp, sdrt->tALH_min); 149962306a36Sopenharmony_ci thold_att = max_t(unsigned long, thold_att, sdrt->tCH_min); 150062306a36Sopenharmony_ci thold_att = max_t(unsigned long, thold_att, sdrt->tCLH_min); 150162306a36Sopenharmony_ci thold_att = max_t(unsigned long, thold_att, sdrt->tCOH_min); 150262306a36Sopenharmony_ci thold_att = max_t(unsigned long, thold_att, sdrt->tDH_min); 150362306a36Sopenharmony_ci if ((sdrt->tWB_max + FMC2_TIO + FMC2_TSYNC > tset_mem) && 150462306a36Sopenharmony_ci (thold_att < sdrt->tWB_max + FMC2_TIO + FMC2_TSYNC - tset_mem)) 150562306a36Sopenharmony_ci thold_att = sdrt->tWB_max + FMC2_TIO + FMC2_TSYNC - tset_mem; 150662306a36Sopenharmony_ci if (sdrt->tADL_min > tset_mem && 150762306a36Sopenharmony_ci (thold_att < sdrt->tADL_min - tset_mem)) 150862306a36Sopenharmony_ci thold_att = sdrt->tADL_min - tset_mem; 150962306a36Sopenharmony_ci if (sdrt->tWH_min > tset_mem && 151062306a36Sopenharmony_ci (thold_att < sdrt->tWH_min - tset_mem)) 151162306a36Sopenharmony_ci thold_att = sdrt->tWH_min - tset_mem; 151262306a36Sopenharmony_ci if (sdrt->tWHR_min > tset_mem && 151362306a36Sopenharmony_ci (thold_att < sdrt->tWHR_min - tset_mem)) 151462306a36Sopenharmony_ci thold_att = sdrt->tWHR_min - tset_mem; 151562306a36Sopenharmony_ci if ((sdrt->tRC_min > tset_att + twait) && 151662306a36Sopenharmony_ci (thold_att < sdrt->tRC_min - (tset_att + twait))) 151762306a36Sopenharmony_ci thold_att = sdrt->tRC_min - (tset_att + twait); 151862306a36Sopenharmony_ci if ((sdrt->tWC_min > tset_att + twait) && 151962306a36Sopenharmony_ci (thold_att < sdrt->tWC_min - (tset_att + twait))) 152062306a36Sopenharmony_ci thold_att = sdrt->tWC_min - (tset_att + twait); 152162306a36Sopenharmony_ci timing = DIV_ROUND_UP(thold_att, hclkp); 152262306a36Sopenharmony_ci tims->thold_att = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK); 152362306a36Sopenharmony_ci} 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_cistatic int stm32_fmc2_nfc_setup_interface(struct nand_chip *chip, int chipnr, 152662306a36Sopenharmony_ci const struct nand_interface_config *conf) 152762306a36Sopenharmony_ci{ 152862306a36Sopenharmony_ci const struct nand_sdr_timings *sdrt; 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci sdrt = nand_get_sdr_timings(conf); 153162306a36Sopenharmony_ci if (IS_ERR(sdrt)) 153262306a36Sopenharmony_ci return PTR_ERR(sdrt); 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci if (conf->timings.mode > 3) 153562306a36Sopenharmony_ci return -EOPNOTSUPP; 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci if (chipnr == NAND_DATA_IFACE_CHECK_ONLY) 153862306a36Sopenharmony_ci return 0; 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci stm32_fmc2_nfc_calc_timings(chip, sdrt); 154162306a36Sopenharmony_ci stm32_fmc2_nfc_timings_init(chip); 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci return 0; 154462306a36Sopenharmony_ci} 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_cistatic int stm32_fmc2_nfc_dma_setup(struct stm32_fmc2_nfc *nfc) 154762306a36Sopenharmony_ci{ 154862306a36Sopenharmony_ci int ret = 0; 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci nfc->dma_tx_ch = dma_request_chan(nfc->dev, "tx"); 155162306a36Sopenharmony_ci if (IS_ERR(nfc->dma_tx_ch)) { 155262306a36Sopenharmony_ci ret = PTR_ERR(nfc->dma_tx_ch); 155362306a36Sopenharmony_ci if (ret != -ENODEV && ret != -EPROBE_DEFER) 155462306a36Sopenharmony_ci dev_err(nfc->dev, 155562306a36Sopenharmony_ci "failed to request tx DMA channel: %d\n", ret); 155662306a36Sopenharmony_ci nfc->dma_tx_ch = NULL; 155762306a36Sopenharmony_ci goto err_dma; 155862306a36Sopenharmony_ci } 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci nfc->dma_rx_ch = dma_request_chan(nfc->dev, "rx"); 156162306a36Sopenharmony_ci if (IS_ERR(nfc->dma_rx_ch)) { 156262306a36Sopenharmony_ci ret = PTR_ERR(nfc->dma_rx_ch); 156362306a36Sopenharmony_ci if (ret != -ENODEV && ret != -EPROBE_DEFER) 156462306a36Sopenharmony_ci dev_err(nfc->dev, 156562306a36Sopenharmony_ci "failed to request rx DMA channel: %d\n", ret); 156662306a36Sopenharmony_ci nfc->dma_rx_ch = NULL; 156762306a36Sopenharmony_ci goto err_dma; 156862306a36Sopenharmony_ci } 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci nfc->dma_ecc_ch = dma_request_chan(nfc->dev, "ecc"); 157162306a36Sopenharmony_ci if (IS_ERR(nfc->dma_ecc_ch)) { 157262306a36Sopenharmony_ci ret = PTR_ERR(nfc->dma_ecc_ch); 157362306a36Sopenharmony_ci if (ret != -ENODEV && ret != -EPROBE_DEFER) 157462306a36Sopenharmony_ci dev_err(nfc->dev, 157562306a36Sopenharmony_ci "failed to request ecc DMA channel: %d\n", ret); 157662306a36Sopenharmony_ci nfc->dma_ecc_ch = NULL; 157762306a36Sopenharmony_ci goto err_dma; 157862306a36Sopenharmony_ci } 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci ret = sg_alloc_table(&nfc->dma_ecc_sg, FMC2_MAX_SG, GFP_KERNEL); 158162306a36Sopenharmony_ci if (ret) 158262306a36Sopenharmony_ci return ret; 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci /* Allocate a buffer to store ECC status registers */ 158562306a36Sopenharmony_ci nfc->ecc_buf = devm_kzalloc(nfc->dev, FMC2_MAX_ECC_BUF_LEN, GFP_KERNEL); 158662306a36Sopenharmony_ci if (!nfc->ecc_buf) 158762306a36Sopenharmony_ci return -ENOMEM; 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci ret = sg_alloc_table(&nfc->dma_data_sg, FMC2_MAX_SG, GFP_KERNEL); 159062306a36Sopenharmony_ci if (ret) 159162306a36Sopenharmony_ci return ret; 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci init_completion(&nfc->dma_data_complete); 159462306a36Sopenharmony_ci init_completion(&nfc->dma_ecc_complete); 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci return 0; 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_cierr_dma: 159962306a36Sopenharmony_ci if (ret == -ENODEV) { 160062306a36Sopenharmony_ci dev_warn(nfc->dev, 160162306a36Sopenharmony_ci "DMAs not defined in the DT, polling mode is used\n"); 160262306a36Sopenharmony_ci ret = 0; 160362306a36Sopenharmony_ci } 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci return ret; 160662306a36Sopenharmony_ci} 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_cistatic void stm32_fmc2_nfc_nand_callbacks_setup(struct nand_chip *chip) 160962306a36Sopenharmony_ci{ 161062306a36Sopenharmony_ci struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci /* 161362306a36Sopenharmony_ci * Specific callbacks to read/write a page depending on 161462306a36Sopenharmony_ci * the mode (polling/sequencer) and the algo used (Hamming, BCH). 161562306a36Sopenharmony_ci */ 161662306a36Sopenharmony_ci if (nfc->dma_tx_ch && nfc->dma_rx_ch && nfc->dma_ecc_ch) { 161762306a36Sopenharmony_ci /* DMA => use sequencer mode callbacks */ 161862306a36Sopenharmony_ci chip->ecc.correct = stm32_fmc2_nfc_seq_correct; 161962306a36Sopenharmony_ci chip->ecc.write_page = stm32_fmc2_nfc_seq_write_page; 162062306a36Sopenharmony_ci chip->ecc.read_page = stm32_fmc2_nfc_seq_read_page; 162162306a36Sopenharmony_ci chip->ecc.write_page_raw = stm32_fmc2_nfc_seq_write_page_raw; 162262306a36Sopenharmony_ci chip->ecc.read_page_raw = stm32_fmc2_nfc_seq_read_page_raw; 162362306a36Sopenharmony_ci } else { 162462306a36Sopenharmony_ci /* No DMA => use polling mode callbacks */ 162562306a36Sopenharmony_ci chip->ecc.hwctl = stm32_fmc2_nfc_hwctl; 162662306a36Sopenharmony_ci if (chip->ecc.strength == FMC2_ECC_HAM) { 162762306a36Sopenharmony_ci /* Hamming is used */ 162862306a36Sopenharmony_ci chip->ecc.calculate = stm32_fmc2_nfc_ham_calculate; 162962306a36Sopenharmony_ci chip->ecc.correct = stm32_fmc2_nfc_ham_correct; 163062306a36Sopenharmony_ci chip->ecc.options |= NAND_ECC_GENERIC_ERASED_CHECK; 163162306a36Sopenharmony_ci } else { 163262306a36Sopenharmony_ci /* BCH is used */ 163362306a36Sopenharmony_ci chip->ecc.calculate = stm32_fmc2_nfc_bch_calculate; 163462306a36Sopenharmony_ci chip->ecc.correct = stm32_fmc2_nfc_bch_correct; 163562306a36Sopenharmony_ci chip->ecc.read_page = stm32_fmc2_nfc_read_page; 163662306a36Sopenharmony_ci } 163762306a36Sopenharmony_ci } 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci /* Specific configurations depending on the algo used */ 164062306a36Sopenharmony_ci if (chip->ecc.strength == FMC2_ECC_HAM) 164162306a36Sopenharmony_ci chip->ecc.bytes = chip->options & NAND_BUSWIDTH_16 ? 4 : 3; 164262306a36Sopenharmony_ci else if (chip->ecc.strength == FMC2_ECC_BCH8) 164362306a36Sopenharmony_ci chip->ecc.bytes = chip->options & NAND_BUSWIDTH_16 ? 14 : 13; 164462306a36Sopenharmony_ci else 164562306a36Sopenharmony_ci chip->ecc.bytes = chip->options & NAND_BUSWIDTH_16 ? 8 : 7; 164662306a36Sopenharmony_ci} 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_cistatic int stm32_fmc2_nfc_ooblayout_ecc(struct mtd_info *mtd, int section, 164962306a36Sopenharmony_ci struct mtd_oob_region *oobregion) 165062306a36Sopenharmony_ci{ 165162306a36Sopenharmony_ci struct nand_chip *chip = mtd_to_nand(mtd); 165262306a36Sopenharmony_ci struct nand_ecc_ctrl *ecc = &chip->ecc; 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci if (section) 165562306a36Sopenharmony_ci return -ERANGE; 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci oobregion->length = ecc->total; 165862306a36Sopenharmony_ci oobregion->offset = FMC2_BBM_LEN; 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_ci return 0; 166162306a36Sopenharmony_ci} 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_cistatic int stm32_fmc2_nfc_ooblayout_free(struct mtd_info *mtd, int section, 166462306a36Sopenharmony_ci struct mtd_oob_region *oobregion) 166562306a36Sopenharmony_ci{ 166662306a36Sopenharmony_ci struct nand_chip *chip = mtd_to_nand(mtd); 166762306a36Sopenharmony_ci struct nand_ecc_ctrl *ecc = &chip->ecc; 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_ci if (section) 167062306a36Sopenharmony_ci return -ERANGE; 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci oobregion->length = mtd->oobsize - ecc->total - FMC2_BBM_LEN; 167362306a36Sopenharmony_ci oobregion->offset = ecc->total + FMC2_BBM_LEN; 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci return 0; 167662306a36Sopenharmony_ci} 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_cistatic const struct mtd_ooblayout_ops stm32_fmc2_nfc_ooblayout_ops = { 167962306a36Sopenharmony_ci .ecc = stm32_fmc2_nfc_ooblayout_ecc, 168062306a36Sopenharmony_ci .free = stm32_fmc2_nfc_ooblayout_free, 168162306a36Sopenharmony_ci}; 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_cistatic int stm32_fmc2_nfc_calc_ecc_bytes(int step_size, int strength) 168462306a36Sopenharmony_ci{ 168562306a36Sopenharmony_ci /* Hamming */ 168662306a36Sopenharmony_ci if (strength == FMC2_ECC_HAM) 168762306a36Sopenharmony_ci return 4; 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ci /* BCH8 */ 169062306a36Sopenharmony_ci if (strength == FMC2_ECC_BCH8) 169162306a36Sopenharmony_ci return 14; 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci /* BCH4 */ 169462306a36Sopenharmony_ci return 8; 169562306a36Sopenharmony_ci} 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_ciNAND_ECC_CAPS_SINGLE(stm32_fmc2_nfc_ecc_caps, stm32_fmc2_nfc_calc_ecc_bytes, 169862306a36Sopenharmony_ci FMC2_ECC_STEP_SIZE, 169962306a36Sopenharmony_ci FMC2_ECC_HAM, FMC2_ECC_BCH4, FMC2_ECC_BCH8); 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_cistatic int stm32_fmc2_nfc_attach_chip(struct nand_chip *chip) 170262306a36Sopenharmony_ci{ 170362306a36Sopenharmony_ci struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); 170462306a36Sopenharmony_ci struct mtd_info *mtd = nand_to_mtd(chip); 170562306a36Sopenharmony_ci int ret; 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci /* 170862306a36Sopenharmony_ci * Only NAND_ECC_ENGINE_TYPE_ON_HOST mode is actually supported 170962306a36Sopenharmony_ci * Hamming => ecc.strength = 1 171062306a36Sopenharmony_ci * BCH4 => ecc.strength = 4 171162306a36Sopenharmony_ci * BCH8 => ecc.strength = 8 171262306a36Sopenharmony_ci * ECC sector size = 512 171362306a36Sopenharmony_ci */ 171462306a36Sopenharmony_ci if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST) { 171562306a36Sopenharmony_ci dev_err(nfc->dev, 171662306a36Sopenharmony_ci "nand_ecc_engine_type is not well defined in the DT\n"); 171762306a36Sopenharmony_ci return -EINVAL; 171862306a36Sopenharmony_ci } 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci /* Default ECC settings in case they are not set in the device tree */ 172162306a36Sopenharmony_ci if (!chip->ecc.size) 172262306a36Sopenharmony_ci chip->ecc.size = FMC2_ECC_STEP_SIZE; 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci if (!chip->ecc.strength) 172562306a36Sopenharmony_ci chip->ecc.strength = FMC2_ECC_BCH8; 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci ret = nand_ecc_choose_conf(chip, &stm32_fmc2_nfc_ecc_caps, 172862306a36Sopenharmony_ci mtd->oobsize - FMC2_BBM_LEN); 172962306a36Sopenharmony_ci if (ret) { 173062306a36Sopenharmony_ci dev_err(nfc->dev, "no valid ECC settings set\n"); 173162306a36Sopenharmony_ci return ret; 173262306a36Sopenharmony_ci } 173362306a36Sopenharmony_ci 173462306a36Sopenharmony_ci if (mtd->writesize / chip->ecc.size > FMC2_MAX_SG) { 173562306a36Sopenharmony_ci dev_err(nfc->dev, "nand page size is not supported\n"); 173662306a36Sopenharmony_ci return -EINVAL; 173762306a36Sopenharmony_ci } 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_ci if (chip->bbt_options & NAND_BBT_USE_FLASH) 174062306a36Sopenharmony_ci chip->bbt_options |= NAND_BBT_NO_OOB; 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ci stm32_fmc2_nfc_nand_callbacks_setup(chip); 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_ci mtd_set_ooblayout(mtd, &stm32_fmc2_nfc_ooblayout_ops); 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ci stm32_fmc2_nfc_setup(chip); 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ci return 0; 174962306a36Sopenharmony_ci} 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_cistatic const struct nand_controller_ops stm32_fmc2_nfc_controller_ops = { 175262306a36Sopenharmony_ci .attach_chip = stm32_fmc2_nfc_attach_chip, 175362306a36Sopenharmony_ci .exec_op = stm32_fmc2_nfc_exec_op, 175462306a36Sopenharmony_ci .setup_interface = stm32_fmc2_nfc_setup_interface, 175562306a36Sopenharmony_ci}; 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_cistatic void stm32_fmc2_nfc_wp_enable(struct stm32_fmc2_nand *nand) 175862306a36Sopenharmony_ci{ 175962306a36Sopenharmony_ci if (nand->wp_gpio) 176062306a36Sopenharmony_ci gpiod_set_value(nand->wp_gpio, 1); 176162306a36Sopenharmony_ci} 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_cistatic void stm32_fmc2_nfc_wp_disable(struct stm32_fmc2_nand *nand) 176462306a36Sopenharmony_ci{ 176562306a36Sopenharmony_ci if (nand->wp_gpio) 176662306a36Sopenharmony_ci gpiod_set_value(nand->wp_gpio, 0); 176762306a36Sopenharmony_ci} 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_cistatic int stm32_fmc2_nfc_parse_child(struct stm32_fmc2_nfc *nfc, 177062306a36Sopenharmony_ci struct device_node *dn) 177162306a36Sopenharmony_ci{ 177262306a36Sopenharmony_ci struct stm32_fmc2_nand *nand = &nfc->nand; 177362306a36Sopenharmony_ci u32 cs; 177462306a36Sopenharmony_ci int ret, i; 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci if (!of_get_property(dn, "reg", &nand->ncs)) 177762306a36Sopenharmony_ci return -EINVAL; 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci nand->ncs /= sizeof(u32); 178062306a36Sopenharmony_ci if (!nand->ncs) { 178162306a36Sopenharmony_ci dev_err(nfc->dev, "invalid reg property size\n"); 178262306a36Sopenharmony_ci return -EINVAL; 178362306a36Sopenharmony_ci } 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci for (i = 0; i < nand->ncs; i++) { 178662306a36Sopenharmony_ci ret = of_property_read_u32_index(dn, "reg", i, &cs); 178762306a36Sopenharmony_ci if (ret) { 178862306a36Sopenharmony_ci dev_err(nfc->dev, "could not retrieve reg property: %d\n", 178962306a36Sopenharmony_ci ret); 179062306a36Sopenharmony_ci return ret; 179162306a36Sopenharmony_ci } 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_ci if (cs >= FMC2_MAX_CE) { 179462306a36Sopenharmony_ci dev_err(nfc->dev, "invalid reg value: %d\n", cs); 179562306a36Sopenharmony_ci return -EINVAL; 179662306a36Sopenharmony_ci } 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci if (nfc->cs_assigned & BIT(cs)) { 179962306a36Sopenharmony_ci dev_err(nfc->dev, "cs already assigned: %d\n", cs); 180062306a36Sopenharmony_ci return -EINVAL; 180162306a36Sopenharmony_ci } 180262306a36Sopenharmony_ci 180362306a36Sopenharmony_ci nfc->cs_assigned |= BIT(cs); 180462306a36Sopenharmony_ci nand->cs_used[i] = cs; 180562306a36Sopenharmony_ci } 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci nand->wp_gpio = devm_fwnode_gpiod_get(nfc->dev, of_fwnode_handle(dn), 180862306a36Sopenharmony_ci "wp", GPIOD_OUT_HIGH, "wp"); 180962306a36Sopenharmony_ci if (IS_ERR(nand->wp_gpio)) { 181062306a36Sopenharmony_ci ret = PTR_ERR(nand->wp_gpio); 181162306a36Sopenharmony_ci if (ret != -ENOENT) 181262306a36Sopenharmony_ci return dev_err_probe(nfc->dev, ret, 181362306a36Sopenharmony_ci "failed to request WP GPIO\n"); 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_ci nand->wp_gpio = NULL; 181662306a36Sopenharmony_ci } 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci nand_set_flash_node(&nand->chip, dn); 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci return 0; 182162306a36Sopenharmony_ci} 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_cistatic int stm32_fmc2_nfc_parse_dt(struct stm32_fmc2_nfc *nfc) 182462306a36Sopenharmony_ci{ 182562306a36Sopenharmony_ci struct device_node *dn = nfc->dev->of_node; 182662306a36Sopenharmony_ci struct device_node *child; 182762306a36Sopenharmony_ci int nchips = of_get_child_count(dn); 182862306a36Sopenharmony_ci int ret = 0; 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci if (!nchips) { 183162306a36Sopenharmony_ci dev_err(nfc->dev, "NAND chip not defined\n"); 183262306a36Sopenharmony_ci return -EINVAL; 183362306a36Sopenharmony_ci } 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_ci if (nchips > 1) { 183662306a36Sopenharmony_ci dev_err(nfc->dev, "too many NAND chips defined\n"); 183762306a36Sopenharmony_ci return -EINVAL; 183862306a36Sopenharmony_ci } 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_ci for_each_child_of_node(dn, child) { 184162306a36Sopenharmony_ci ret = stm32_fmc2_nfc_parse_child(nfc, child); 184262306a36Sopenharmony_ci if (ret < 0) { 184362306a36Sopenharmony_ci of_node_put(child); 184462306a36Sopenharmony_ci return ret; 184562306a36Sopenharmony_ci } 184662306a36Sopenharmony_ci } 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci return ret; 184962306a36Sopenharmony_ci} 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_cistatic int stm32_fmc2_nfc_set_cdev(struct stm32_fmc2_nfc *nfc) 185262306a36Sopenharmony_ci{ 185362306a36Sopenharmony_ci struct device *dev = nfc->dev; 185462306a36Sopenharmony_ci bool ebi_found = false; 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci if (dev->parent && of_device_is_compatible(dev->parent->of_node, 185762306a36Sopenharmony_ci "st,stm32mp1-fmc2-ebi")) 185862306a36Sopenharmony_ci ebi_found = true; 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci if (of_device_is_compatible(dev->of_node, "st,stm32mp1-fmc2-nfc")) { 186162306a36Sopenharmony_ci if (ebi_found) { 186262306a36Sopenharmony_ci nfc->cdev = dev->parent; 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_ci return 0; 186562306a36Sopenharmony_ci } 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_ci return -EINVAL; 186862306a36Sopenharmony_ci } 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_ci if (ebi_found) 187162306a36Sopenharmony_ci return -EINVAL; 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci nfc->cdev = dev; 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_ci return 0; 187662306a36Sopenharmony_ci} 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_cistatic int stm32_fmc2_nfc_probe(struct platform_device *pdev) 187962306a36Sopenharmony_ci{ 188062306a36Sopenharmony_ci struct device *dev = &pdev->dev; 188162306a36Sopenharmony_ci struct reset_control *rstc; 188262306a36Sopenharmony_ci struct stm32_fmc2_nfc *nfc; 188362306a36Sopenharmony_ci struct stm32_fmc2_nand *nand; 188462306a36Sopenharmony_ci struct resource *res; 188562306a36Sopenharmony_ci struct mtd_info *mtd; 188662306a36Sopenharmony_ci struct nand_chip *chip; 188762306a36Sopenharmony_ci struct resource cres; 188862306a36Sopenharmony_ci int chip_cs, mem_region, ret, irq; 188962306a36Sopenharmony_ci int start_region = 0; 189062306a36Sopenharmony_ci 189162306a36Sopenharmony_ci nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL); 189262306a36Sopenharmony_ci if (!nfc) 189362306a36Sopenharmony_ci return -ENOMEM; 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci nfc->dev = dev; 189662306a36Sopenharmony_ci nand_controller_init(&nfc->base); 189762306a36Sopenharmony_ci nfc->base.ops = &stm32_fmc2_nfc_controller_ops; 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci ret = stm32_fmc2_nfc_set_cdev(nfc); 190062306a36Sopenharmony_ci if (ret) 190162306a36Sopenharmony_ci return ret; 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci ret = stm32_fmc2_nfc_parse_dt(nfc); 190462306a36Sopenharmony_ci if (ret) 190562306a36Sopenharmony_ci return ret; 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci ret = of_address_to_resource(nfc->cdev->of_node, 0, &cres); 190862306a36Sopenharmony_ci if (ret) 190962306a36Sopenharmony_ci return ret; 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_ci nfc->io_phys_addr = cres.start; 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci nfc->regmap = device_node_to_regmap(nfc->cdev->of_node); 191462306a36Sopenharmony_ci if (IS_ERR(nfc->regmap)) 191562306a36Sopenharmony_ci return PTR_ERR(nfc->regmap); 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_ci if (nfc->dev == nfc->cdev) 191862306a36Sopenharmony_ci start_region = 1; 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_ci for (chip_cs = 0, mem_region = start_region; chip_cs < FMC2_MAX_CE; 192162306a36Sopenharmony_ci chip_cs++, mem_region += 3) { 192262306a36Sopenharmony_ci if (!(nfc->cs_assigned & BIT(chip_cs))) 192362306a36Sopenharmony_ci continue; 192462306a36Sopenharmony_ci 192562306a36Sopenharmony_ci nfc->data_base[chip_cs] = devm_platform_get_and_ioremap_resource(pdev, 192662306a36Sopenharmony_ci mem_region, &res); 192762306a36Sopenharmony_ci if (IS_ERR(nfc->data_base[chip_cs])) 192862306a36Sopenharmony_ci return PTR_ERR(nfc->data_base[chip_cs]); 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci nfc->data_phys_addr[chip_cs] = res->start; 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci nfc->cmd_base[chip_cs] = devm_platform_ioremap_resource(pdev, mem_region + 1); 193362306a36Sopenharmony_ci if (IS_ERR(nfc->cmd_base[chip_cs])) 193462306a36Sopenharmony_ci return PTR_ERR(nfc->cmd_base[chip_cs]); 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci nfc->addr_base[chip_cs] = devm_platform_ioremap_resource(pdev, mem_region + 2); 193762306a36Sopenharmony_ci if (IS_ERR(nfc->addr_base[chip_cs])) 193862306a36Sopenharmony_ci return PTR_ERR(nfc->addr_base[chip_cs]); 193962306a36Sopenharmony_ci } 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 194262306a36Sopenharmony_ci if (irq < 0) 194362306a36Sopenharmony_ci return irq; 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_ci ret = devm_request_irq(dev, irq, stm32_fmc2_nfc_irq, 0, 194662306a36Sopenharmony_ci dev_name(dev), nfc); 194762306a36Sopenharmony_ci if (ret) { 194862306a36Sopenharmony_ci dev_err(dev, "failed to request irq\n"); 194962306a36Sopenharmony_ci return ret; 195062306a36Sopenharmony_ci } 195162306a36Sopenharmony_ci 195262306a36Sopenharmony_ci init_completion(&nfc->complete); 195362306a36Sopenharmony_ci 195462306a36Sopenharmony_ci nfc->clk = devm_clk_get_enabled(nfc->cdev, NULL); 195562306a36Sopenharmony_ci if (IS_ERR(nfc->clk)) { 195662306a36Sopenharmony_ci dev_err(dev, "can not get and enable the clock\n"); 195762306a36Sopenharmony_ci return PTR_ERR(nfc->clk); 195862306a36Sopenharmony_ci } 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_ci rstc = devm_reset_control_get(dev, NULL); 196162306a36Sopenharmony_ci if (IS_ERR(rstc)) { 196262306a36Sopenharmony_ci ret = PTR_ERR(rstc); 196362306a36Sopenharmony_ci if (ret == -EPROBE_DEFER) 196462306a36Sopenharmony_ci return ret; 196562306a36Sopenharmony_ci } else { 196662306a36Sopenharmony_ci reset_control_assert(rstc); 196762306a36Sopenharmony_ci reset_control_deassert(rstc); 196862306a36Sopenharmony_ci } 196962306a36Sopenharmony_ci 197062306a36Sopenharmony_ci ret = stm32_fmc2_nfc_dma_setup(nfc); 197162306a36Sopenharmony_ci if (ret) 197262306a36Sopenharmony_ci goto err_release_dma; 197362306a36Sopenharmony_ci 197462306a36Sopenharmony_ci stm32_fmc2_nfc_init(nfc); 197562306a36Sopenharmony_ci 197662306a36Sopenharmony_ci nand = &nfc->nand; 197762306a36Sopenharmony_ci chip = &nand->chip; 197862306a36Sopenharmony_ci mtd = nand_to_mtd(chip); 197962306a36Sopenharmony_ci mtd->dev.parent = dev; 198062306a36Sopenharmony_ci 198162306a36Sopenharmony_ci chip->controller = &nfc->base; 198262306a36Sopenharmony_ci chip->options |= NAND_BUSWIDTH_AUTO | NAND_NO_SUBPAGE_WRITE | 198362306a36Sopenharmony_ci NAND_USES_DMA; 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_ci stm32_fmc2_nfc_wp_disable(nand); 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci /* Scan to find existence of the device */ 198862306a36Sopenharmony_ci ret = nand_scan(chip, nand->ncs); 198962306a36Sopenharmony_ci if (ret) 199062306a36Sopenharmony_ci goto err_wp_enable; 199162306a36Sopenharmony_ci 199262306a36Sopenharmony_ci ret = mtd_device_register(mtd, NULL, 0); 199362306a36Sopenharmony_ci if (ret) 199462306a36Sopenharmony_ci goto err_nand_cleanup; 199562306a36Sopenharmony_ci 199662306a36Sopenharmony_ci platform_set_drvdata(pdev, nfc); 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_ci return 0; 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_cierr_nand_cleanup: 200162306a36Sopenharmony_ci nand_cleanup(chip); 200262306a36Sopenharmony_ci 200362306a36Sopenharmony_cierr_wp_enable: 200462306a36Sopenharmony_ci stm32_fmc2_nfc_wp_enable(nand); 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_cierr_release_dma: 200762306a36Sopenharmony_ci if (nfc->dma_ecc_ch) 200862306a36Sopenharmony_ci dma_release_channel(nfc->dma_ecc_ch); 200962306a36Sopenharmony_ci if (nfc->dma_tx_ch) 201062306a36Sopenharmony_ci dma_release_channel(nfc->dma_tx_ch); 201162306a36Sopenharmony_ci if (nfc->dma_rx_ch) 201262306a36Sopenharmony_ci dma_release_channel(nfc->dma_rx_ch); 201362306a36Sopenharmony_ci 201462306a36Sopenharmony_ci sg_free_table(&nfc->dma_data_sg); 201562306a36Sopenharmony_ci sg_free_table(&nfc->dma_ecc_sg); 201662306a36Sopenharmony_ci 201762306a36Sopenharmony_ci return ret; 201862306a36Sopenharmony_ci} 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_cistatic void stm32_fmc2_nfc_remove(struct platform_device *pdev) 202162306a36Sopenharmony_ci{ 202262306a36Sopenharmony_ci struct stm32_fmc2_nfc *nfc = platform_get_drvdata(pdev); 202362306a36Sopenharmony_ci struct stm32_fmc2_nand *nand = &nfc->nand; 202462306a36Sopenharmony_ci struct nand_chip *chip = &nand->chip; 202562306a36Sopenharmony_ci int ret; 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci ret = mtd_device_unregister(nand_to_mtd(chip)); 202862306a36Sopenharmony_ci WARN_ON(ret); 202962306a36Sopenharmony_ci nand_cleanup(chip); 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci if (nfc->dma_ecc_ch) 203262306a36Sopenharmony_ci dma_release_channel(nfc->dma_ecc_ch); 203362306a36Sopenharmony_ci if (nfc->dma_tx_ch) 203462306a36Sopenharmony_ci dma_release_channel(nfc->dma_tx_ch); 203562306a36Sopenharmony_ci if (nfc->dma_rx_ch) 203662306a36Sopenharmony_ci dma_release_channel(nfc->dma_rx_ch); 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_ci sg_free_table(&nfc->dma_data_sg); 203962306a36Sopenharmony_ci sg_free_table(&nfc->dma_ecc_sg); 204062306a36Sopenharmony_ci 204162306a36Sopenharmony_ci stm32_fmc2_nfc_wp_enable(nand); 204262306a36Sopenharmony_ci} 204362306a36Sopenharmony_ci 204462306a36Sopenharmony_cistatic int __maybe_unused stm32_fmc2_nfc_suspend(struct device *dev) 204562306a36Sopenharmony_ci{ 204662306a36Sopenharmony_ci struct stm32_fmc2_nfc *nfc = dev_get_drvdata(dev); 204762306a36Sopenharmony_ci struct stm32_fmc2_nand *nand = &nfc->nand; 204862306a36Sopenharmony_ci 204962306a36Sopenharmony_ci clk_disable_unprepare(nfc->clk); 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci stm32_fmc2_nfc_wp_enable(nand); 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_ci pinctrl_pm_select_sleep_state(dev); 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ci return 0; 205662306a36Sopenharmony_ci} 205762306a36Sopenharmony_ci 205862306a36Sopenharmony_cistatic int __maybe_unused stm32_fmc2_nfc_resume(struct device *dev) 205962306a36Sopenharmony_ci{ 206062306a36Sopenharmony_ci struct stm32_fmc2_nfc *nfc = dev_get_drvdata(dev); 206162306a36Sopenharmony_ci struct stm32_fmc2_nand *nand = &nfc->nand; 206262306a36Sopenharmony_ci int chip_cs, ret; 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_ci pinctrl_pm_select_default_state(dev); 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci ret = clk_prepare_enable(nfc->clk); 206762306a36Sopenharmony_ci if (ret) { 206862306a36Sopenharmony_ci dev_err(dev, "can not enable the clock\n"); 206962306a36Sopenharmony_ci return ret; 207062306a36Sopenharmony_ci } 207162306a36Sopenharmony_ci 207262306a36Sopenharmony_ci stm32_fmc2_nfc_init(nfc); 207362306a36Sopenharmony_ci 207462306a36Sopenharmony_ci stm32_fmc2_nfc_wp_disable(nand); 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_ci for (chip_cs = 0; chip_cs < FMC2_MAX_CE; chip_cs++) { 207762306a36Sopenharmony_ci if (!(nfc->cs_assigned & BIT(chip_cs))) 207862306a36Sopenharmony_ci continue; 207962306a36Sopenharmony_ci 208062306a36Sopenharmony_ci nand_reset(&nand->chip, chip_cs); 208162306a36Sopenharmony_ci } 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci return 0; 208462306a36Sopenharmony_ci} 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(stm32_fmc2_nfc_pm_ops, stm32_fmc2_nfc_suspend, 208762306a36Sopenharmony_ci stm32_fmc2_nfc_resume); 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_cistatic const struct of_device_id stm32_fmc2_nfc_match[] = { 209062306a36Sopenharmony_ci {.compatible = "st,stm32mp15-fmc2"}, 209162306a36Sopenharmony_ci {.compatible = "st,stm32mp1-fmc2-nfc"}, 209262306a36Sopenharmony_ci {} 209362306a36Sopenharmony_ci}; 209462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, stm32_fmc2_nfc_match); 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_cistatic struct platform_driver stm32_fmc2_nfc_driver = { 209762306a36Sopenharmony_ci .probe = stm32_fmc2_nfc_probe, 209862306a36Sopenharmony_ci .remove_new = stm32_fmc2_nfc_remove, 209962306a36Sopenharmony_ci .driver = { 210062306a36Sopenharmony_ci .name = "stm32_fmc2_nfc", 210162306a36Sopenharmony_ci .of_match_table = stm32_fmc2_nfc_match, 210262306a36Sopenharmony_ci .pm = &stm32_fmc2_nfc_pm_ops, 210362306a36Sopenharmony_ci }, 210462306a36Sopenharmony_ci}; 210562306a36Sopenharmony_cimodule_platform_driver(stm32_fmc2_nfc_driver); 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ciMODULE_ALIAS("platform:stm32_fmc2_nfc"); 210862306a36Sopenharmony_ciMODULE_AUTHOR("Christophe Kerello <christophe.kerello@st.com>"); 210962306a36Sopenharmony_ciMODULE_DESCRIPTION("STMicroelectronics STM32 FMC2 NFC driver"); 211062306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 2111