Hi Naga, > > > +/** > > > + * pl353_nand_read_data_op - read chip data into buffer > > > + * @chip: Pointer to the NAND chip info structure > > > + * @in: Pointer to the buffer to store read data > > > + * @len: Number of bytes to read > > > + * Return: Always return zero > > > + */ > > > +static int pl353_nand_read_data_op(struct nand_chip *chip, > > > + u8 *in, > > > + unsigned int len) > > > +{ > > > + int i; > > > + struct pl353_nand_info *xnfc = > > > + container_of(chip, struct pl353_nand_info, chip); > > > + > > > + if (IS_ALIGNED((uint32_t)in, sizeof(uint32_t)) && > > > + IS_ALIGNED(len, sizeof(uint32_t))) { > > > + u32 *ptr = (u32 *)in; > > > + > > > + len /= 4; > > > + for (i = 0; i < len; i++) > > > + ptr[i] = readl(xnfc->nandaddr); > > > + } else { > > > + for (i = 0; i < len; i++) > > > + in[i] = readb(xnfc->nandaddr); > > > + } > > > > What about reading 0-3 bytes with readb if the driver is not aligned, then > > doing aligned > > access with readl until readb must be used again for the last 0-3 bytes? > The else case is handling that right?
No it's not. The else case reads byte per byte, always. [...] > > > +static int pl353_nand_calculate_hwecc(struct mtd_info *mtd, > > > + const u8 *data, u8 *ecc) > > > +{ > > > + u32 ecc_value; > > > + u8 ecc_reg, ecc_byte, ecc_status; > > > + unsigned long timeout = jiffies + PL353_NAND_ECC_BUSY_TIMEOUT; > > > + > > > + /* Wait till the ECC operation is complete or timeout */ > > > + do { > > > + if (pl353_smc_ecc_is_busy()) > > > + cpu_relax(); > > > + else > > > + break; > > > + } while (!time_after_eq(jiffies, timeout)); > > > + > > > + if (time_after_eq(jiffies, timeout)) { > > > + pr_err("%s timed out\n", __func__); > > > + return -ETIMEDOUT; > > > + } > > > > All of this should be done by the function calling nand_calculate_hwecc(), > > not here. > Ok, I will update it. > > > > Plus, it should deserve a function on its own. > Ok, will add new one. > > > > > + > > > + for (ecc_reg = 0; ecc_reg < 4; ecc_reg++) { > > > + /* Read ECC value for each block */ > > > > So you assume here that there are 4, and only 4 "blocks" (I prefer "ECC > > chunks" or > > "subpages"). Is it always the case? Or is it just how it works in your > > situation? I would rather > > prefer a to define this value anyway. > Sure, I will define a macro as ECC chunks to represent 4. > And there are always 4 ECC registers as per the controller. And there is no > assumption here. What about smaller or larger NAND chips? Maybe there are some limitations in what chips are actually supported, then they should be rejected. [...] > > > +static void pl353_prepare_cmd(struct mtd_info *mtd, struct nand_chip *chip, > > > + int page, int column, int start_cmd, int end_cmd, > > > + bool read) > > > +{ > > > + unsigned long data_phase_addr; > > > + u32 end_cmd_valid = 0; > > > + unsigned long cmd_phase_addr = 0, cmd_data = 0; > > > + > > > + struct pl353_nand_info *xnfc = > > > + container_of(chip, struct pl353_nand_info, chip); > > > + > > > + end_cmd_valid = read ? 1 : 0; > > > + > > > + cmd_phase_addr = (unsigned long __force)xnfc->nand_base + > > > > do you really need this cast? > As I said above, during command and data phases, we have to update the AXI > Read/Write addresses with cycles, start command, end command > And some extra info. Hence I am converting it to a value and then adding the > above values and then again converting back as an > Address. > > > > > > + ((xnfc->addr_cycles > > > + << ADDR_CYCLES_SHIFT) | > > > + (end_cmd_valid << END_CMD_VALID_SHIFT) | > > > + (COMMAND_PHASE) | > > > + (end_cmd << END_CMD_SHIFT) | > > > + (start_cmd << START_CMD_SHIFT)); > > > > So the number of address cycles changes the address where you should write > > the address > > cycles? that's weird, no? > I agree, but the implementation of PL353 is like that. > As I pointed the spec above, for every transfer we have to frame AXI Write > address and Read address. > > > > > > + > > > + /* Get the data phase address */ > > > + data_phase_addr = (unsigned long __force)xnfc->nand_base + > > > + ((0x0 << CLEAR_CS_SHIFT) | > > > + (0 << END_CMD_VALID_SHIFT) | > > > + (DATA_PHASE) | > > > + (end_cmd << END_CMD_SHIFT) | > > > + (0x0 << ECC_LAST_SHIFT)); > > > + > > Same question here? > > > > > + xnfc->nandaddr = (void __iomem * __force)data_phase_addr; > > > > This should be done only once in the probe > No, as explained above, once we frame the Axi Write address/Read address with > valid data, then we > Are converting back as memory address with the casting. > Do you see any issues with that? > Let me know, is there an alternative to achieve the same. > All is about, constructing AXI Write address and Read address during command > and data phases. Ok, I'll ask Boris to also review your next version, once -rc1 is out. Thanks, Miquèl