Message ID | 20170613090249.6a247389@bbrezillon |
---|---|
State | Not Applicable |
Headers | show |
Hi Boris, 2017-06-13 16:02 GMT+09:00 Boris Brezillon <boris.brezillon@free-electrons.com>: > Le Tue, 13 Jun 2017 14:03:52 +0900, > Masahiro Yamada <yamada.masahiro@socionext.com> a écrit : > >> This patch series intends to solve various problems. >> >> [1] The driver just retrieves the OOB area as-is >> whereas the controller uses syndrome page layout. >> [2] ONFi devices are not working >> [3] It can not read Bad Block Marker >> >> Outstanding changes are: >> - Fix raw/oob callbacks for syndrome page layout >> - Implement setup_data_interface() callback >> - Fix/implement more commands for ONFi devices >> - Allow to skip the driver internal bounce buffer >> - Support PIO in case DMA is not supported >> - Switch from ->cmdfunc over to ->cmd_ctrl >> >> 18 patches were merged by v2. >> 11 patches were merged by v3. >> 2 patches were merged by v4. >> 5 patches were merged by v5. >> Here is the rest of the series. >> >> v1: https://lkml.org/lkml/2016/11/26/144 >> v2: https://lkml.org/lkml/2017/3/22/804 >> v3: https://lkml.org/lkml/2017/3/30/90 >> v4: https://lkml.org/lkml/2017/6/5/1005 >> >> Masahiro Yamada (18): >> mtd: nand: denali: set NAND_ECC_CUSTOM_PAGE_ACCESS >> mtd: nand: denali: remove unneeded find_valid_banks() >> mtd: nand: denali: handle timing parameters by setup_data_interface() >> mtd: nand: denali: rework interrupt handling >> mtd: nand: denali: fix NAND_CMD_STATUS handling >> mtd: nand: denali: fix NAND_CMD_PARAM handling > > AFAICT, patch 5 and 6 are unneeded... > >> mtd: nand: denali: switch over to cmd_ctrl instead of cmdfunc > > ... because you're anyway switching to ->cmd_ctrl() in patch 7, which > fixes the problem you were addressing in patch 5 and 6. > > Please squash those 3 patches into a single one and adjust your commit > message accordingly (explaining that it fixes STATUS and PARAM handling). > See below if you need an example. Squashing 3 patches is OK, but I did not get your additional implementation. > BTW, I also implemented ->read/write_buf_word() since the core may one > day call these functions, and the default implementations used by the > core when these hooks are NULL are not appropriate in your case. I implemented denali_read_buf() denali_write_buf() denali_read_buf16() denali_write_buf16() in 13/18 in a bit different way: http://patchwork.ozlabs.org/patch/774961/ If you like, I can modify 13/18 so that denali_read/write_byte() is implemented based on denali_read/write_buf(). > --->8--- > From 136727ba7b453ca1567c711037230aa6ec0f124a Mon Sep 17 00:00:00 2001 > From: Masahiro Yamada <yamada.masahiro@socionext.com> > Date: Tue, 13 Jun 2017 14:03:57 +0900 > Subject: [PATCH] mtd: nand: denali: switch over to cmd_ctrl instead of cmdfunc > > The NAND_CMD_SET_FEATURES support is missing from denali_cmdfunc(). > > Besides, we see /* TODO: Read OOB data */ comment line. > > It would be possible to add more commands along with the current > implementation, but having ->cmd_ctrl() seems a better approach from > the discussion with Boris [1]. > > Rely on the default ->cmdfunc() from the framework and implement the > driver's own ->cmd_ctrl(). We are also implementing > ->read/write_buf/byte/word(). > > Also add ->write_byte(), which is needed for write direction commands. > > Then, we can drop nand_onfi_get_set_features_notsupp from this driver. > > This transition also fixes NAND_CMD_STATUS and NAND_CMD_PARAM handling. > NAND_CMD_STATUS was just faked by the implementation, and the only valid > bit returned in this case was the WP bit. > NAND_CMD_PARAM was completely broken: not only the command sent on the > bus was NAND_CMD_STATUS instead of NAND_CMD_PARAM, but the driver was > only reading 8 bytes of data, while the parameter page is contains > several hundreds of bytes. Probably "... page contains" instead of "... page is contains".
Hi Boris, 2017-06-13 16:02 GMT+09:00 Boris Brezillon <boris.brezillon@free-electrons.com>: > > BTW, I also implemented ->read/write_buf_word() since the core may one > day call these functions, and the default implementations used by the > core when these hooks are NULL are not appropriate in your case. > BTW, why doesn't the default hook in the core do like this? static uint8_t nand_read_byte(struct mtd_info *mtd) { struct nand_chip *chip = mtd_to_nand(mtd); uint8_t byte; chip->read_buf(chip, &byte, 1); return byte; } ->read_byte() is a special case of ->read_buf() with length==1, so this should work.
On Tue, 13 Jun 2017 17:04:11 +0900 Masahiro Yamada <yamada.masahiro@socionext.com> wrote: > Hi Boris, > > > 2017-06-13 16:02 GMT+09:00 Boris Brezillon <boris.brezillon@free-electrons.com>: > > Le Tue, 13 Jun 2017 14:03:52 +0900, > > Masahiro Yamada <yamada.masahiro@socionext.com> a écrit : > > > >> This patch series intends to solve various problems. > >> > >> [1] The driver just retrieves the OOB area as-is > >> whereas the controller uses syndrome page layout. > >> [2] ONFi devices are not working > >> [3] It can not read Bad Block Marker > >> > >> Outstanding changes are: > >> - Fix raw/oob callbacks for syndrome page layout > >> - Implement setup_data_interface() callback > >> - Fix/implement more commands for ONFi devices > >> - Allow to skip the driver internal bounce buffer > >> - Support PIO in case DMA is not supported > >> - Switch from ->cmdfunc over to ->cmd_ctrl > >> > >> 18 patches were merged by v2. > >> 11 patches were merged by v3. > >> 2 patches were merged by v4. > >> 5 patches were merged by v5. > >> Here is the rest of the series. > >> > >> v1: https://lkml.org/lkml/2016/11/26/144 > >> v2: https://lkml.org/lkml/2017/3/22/804 > >> v3: https://lkml.org/lkml/2017/3/30/90 > >> v4: https://lkml.org/lkml/2017/6/5/1005 > >> > >> Masahiro Yamada (18): > >> mtd: nand: denali: set NAND_ECC_CUSTOM_PAGE_ACCESS > >> mtd: nand: denali: remove unneeded find_valid_banks() > >> mtd: nand: denali: handle timing parameters by setup_data_interface() > >> mtd: nand: denali: rework interrupt handling > >> mtd: nand: denali: fix NAND_CMD_STATUS handling > >> mtd: nand: denali: fix NAND_CMD_PARAM handling > > > > AFAICT, patch 5 and 6 are unneeded... > > > >> mtd: nand: denali: switch over to cmd_ctrl instead of cmdfunc > > > > ... because you're anyway switching to ->cmd_ctrl() in patch 7, which > > fixes the problem you were addressing in patch 5 and 6. > > > > Please squash those 3 patches into a single one and adjust your commit > > message accordingly (explaining that it fixes STATUS and PARAM handling). > > See below if you need an example. > > Squashing 3 patches is OK, but I did not get your additional implementation. > > > > BTW, I also implemented ->read/write_buf_word() since the core may one > > day call these functions, and the default implementations used by the > > core when these hooks are NULL are not appropriate in your case. > > I implemented > > denali_read_buf() > denali_write_buf() > denali_read_buf16() > denali_write_buf16() > > in 13/18 in a bit different way: > http://patchwork.ozlabs.org/patch/774961/ Your implementation is better (I didn't know if a single iowrite32(MODE_11 | BANK(denali->flash_bank) | 2, denali->flash_mem) was enough or if we needed to call it each time we read/write a byte/word). > > > If you like, I can modify 13/18 so that > denali_read/write_byte() is implemented based on denali_read/write_buf(). You can. Anyway, I'd prefer to have ->read/write_buf/byte/word() implemented in patch 7, even if you actually start using ->read/write_buf() in patch 13. > > > > > > > --->8--- > > From 136727ba7b453ca1567c711037230aa6ec0f124a Mon Sep 17 00:00:00 2001 > > From: Masahiro Yamada <yamada.masahiro@socionext.com> > > Date: Tue, 13 Jun 2017 14:03:57 +0900 > > Subject: [PATCH] mtd: nand: denali: switch over to cmd_ctrl instead of cmdfunc > > > > The NAND_CMD_SET_FEATURES support is missing from denali_cmdfunc(). > > > > Besides, we see /* TODO: Read OOB data */ comment line. > > > > It would be possible to add more commands along with the current > > implementation, but having ->cmd_ctrl() seems a better approach from > > the discussion with Boris [1]. > > > > Rely on the default ->cmdfunc() from the framework and implement the > > driver's own ->cmd_ctrl(). We are also implementing > > ->read/write_buf/byte/word(). > > > > Also add ->write_byte(), which is needed for write direction commands. > > > > Then, we can drop nand_onfi_get_set_features_notsupp from this driver. > > > > This transition also fixes NAND_CMD_STATUS and NAND_CMD_PARAM handling. > > NAND_CMD_STATUS was just faked by the implementation, and the only valid > > bit returned in this case was the WP bit. > > NAND_CMD_PARAM was completely broken: not only the command sent on the > > bus was NAND_CMD_STATUS instead of NAND_CMD_PARAM, but the driver was > > only reading 8 bytes of data, while the parameter page is contains > > several hundreds of bytes. > > Probably "... page contains" instead of "... page is contains". Yep. You can also reword the commit message if you want.
On Tue, 13 Jun 2017 17:17:41 +0900 Masahiro Yamada <yamada.masahiro@socionext.com> wrote: > Hi Boris, > > > 2017-06-13 16:02 GMT+09:00 Boris Brezillon <boris.brezillon@free-electrons.com>: > > > > > BTW, I also implemented ->read/write_buf_word() since the core may one > > day call these functions, and the default implementations used by the > > core when these hooks are NULL are not appropriate in your case. > > > > BTW, why doesn't the default hook in the core do like this? > > > static uint8_t nand_read_byte(struct mtd_info *mtd) > { > struct nand_chip *chip = mtd_to_nand(mtd); > uint8_t byte; > > chip->read_buf(chip, &byte, 1); > return byte; > } > > > ->read_byte() is a special case of ->read_buf() with length==1, > so this should work. Not sure it works for all implementation. ->read_byte() is expected to return the lower 8 bits when interacting with a 16-bits bus. If we do what you suggest, and ->read_buf() appears to be caching data in an intermediate buffer if the amount of data is not aligned on 2 bytes, you might retrieve data you don't care about when ->read_byte() is called several times.
Hi Boris, 2017-06-13 17:30 GMT+09:00 Boris Brezillon <boris.brezillon@free-electrons.com>: > On Tue, 13 Jun 2017 17:17:41 +0900 > Masahiro Yamada <yamada.masahiro@socionext.com> wrote: > >> Hi Boris, >> >> >> 2017-06-13 16:02 GMT+09:00 Boris Brezillon <boris.brezillon@free-electrons.com>: >> >> > >> > BTW, I also implemented ->read/write_buf_word() since the core may one >> > day call these functions, and the default implementations used by the >> > core when these hooks are NULL are not appropriate in your case. >> > >> >> BTW, why doesn't the default hook in the core do like this? >> >> >> static uint8_t nand_read_byte(struct mtd_info *mtd) >> { >> struct nand_chip *chip = mtd_to_nand(mtd); >> uint8_t byte; >> >> chip->read_buf(chip, &byte, 1); >> return byte; >> } >> >> >> ->read_byte() is a special case of ->read_buf() with length==1, >> so this should work. > > Not sure it works for all implementation. ->read_byte() is expected > to return the lower 8 bits when interacting with a 16-bits bus. If we do > what you suggest, and ->read_buf() appears to be caching data in an > intermediate buffer if the amount of data is not aligned on 2 bytes, > you might retrieve data you don't care about when ->read_byte() is > called several times. You are right. I missed the case where ->read_byte() is called repeatedly. Thanks!
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index d7e7555a3d73..633faf2da1f4 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -85,43 +85,6 @@ static void index_addr(struct denali_nand_info *denali, iowrite32(data, denali->flash_mem + 0x10); } -/* Perform an indexed read of the device */ -static void index_addr_read_data(struct denali_nand_info *denali, - uint32_t address, uint32_t *pdata) -{ - iowrite32(address, denali->flash_mem); - *pdata = ioread32(denali->flash_mem + 0x10); -} - -/* - * We need to buffer some data for some of the NAND core routines. - * The operations manage buffering that data. - */ -static void reset_buf(struct denali_nand_info *denali) -{ - denali->buf.head = denali->buf.tail = 0; -} - -static void write_byte_to_buf(struct denali_nand_info *denali, uint8_t byte) -{ - denali->buf.buf[denali->buf.tail++] = byte; -} - -/* reads the status of the device */ -static void read_status(struct denali_nand_info *denali) -{ - uint32_t cmd; - - /* initialize the data buffer to store status */ - reset_buf(denali); - - cmd = ioread32(denali->flash_reg + WRITE_PROTECT); - if (cmd) - write_byte_to_buf(denali, NAND_STATUS_WP); - else - write_byte_to_buf(denali, 0); -} - /* Reset the flash controller */ static uint16_t denali_nand_reset(struct denali_nand_info *denali) { @@ -267,20 +230,16 @@ static uint32_t denali_wait_for_irq(struct denali_nand_info *denali, return denali->irq_status; } -/* resets a specific device connected to the core */ -static void reset_bank(struct denali_nand_info *denali) +static uint32_t denali_check_irq(struct denali_nand_info *denali) { + unsigned long flags; uint32_t irq_status; - denali_reset_irq(denali); - - iowrite32(1 << denali->flash_bank, denali->flash_reg + DEVICE_RESET); - - irq_status = denali_wait_for_irq(denali, - INTR__RST_COMP | INTR__TIME_OUT); + spin_lock_irqsave(&denali->irq_lock, flags); + irq_status = denali->irq_status; + spin_unlock_irqrestore(&denali->irq_lock, flags); - if (!(irq_status & INTR__RST_COMP)) - dev_err(denali->dev, "reset bank failed.\n"); + return irq_status; } /* @@ -301,6 +260,82 @@ static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en, iowrite32(transfer_spare_flag, denali->flash_reg + TRANSFER_SPARE_REG); } +static void denali_read_buf(struct mtd_info *mtd, u8 *buf, int len) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + int i; + + for (i = 0; i < len; i++) { + iowrite32(MODE_11 | BANK(denali->flash_bank) | 2, + denali->flash_mem); + buf[i] = ioread32(denali->flash_mem + 0x10); + } +} + +static u8 denali_read_byte(struct mtd_info *mtd) +{ + u8 ret; + + denali_read_buf(mtd, &ret, 1); + + return ret; +} + +static u16 denali_read_word(struct mtd_info *mtd) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + + iowrite32(MODE_11 | BANK(denali->flash_bank) | 2, denali->flash_mem); + + return ioread32(denali->flash_mem + 0x10); +} + +static void denali_write_buf(struct mtd_info *mtd, const u8 *buf, int len) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + int i; + + for (i = 0; i < len; i++) { + iowrite32(MODE_11 | BANK(denali->flash_bank) | 2, + denali->flash_mem); + iowrite32(buf[i], denali->flash_mem + 0x10); + } +} + +static void denali_write_byte(struct mtd_info *mtd, uint8_t byte) +{ + denali_write_buf(mtd, &byte, 1); +} + +static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + uint32_t type; + + if (ctrl & NAND_CLE) + type = 0; + else if (ctrl & NAND_ALE) + type = 1; + else + return; + + /* + * Some commands are followed by chip->dev_ready or chip->waitfunc. + * irq_status must be cleared here to catch the R/B# interrupt later. + */ + if (ctrl & NAND_CTRL_CHANGE) + denali_reset_irq(denali); + + index_addr(denali, MODE_11 | BANK(denali->flash_bank) | type, dat); +} + +static int denali_dev_ready(struct mtd_info *mtd) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + + return !!(denali_check_irq(denali) & INTR__INT_ACT); +} + /* * sends a pipeline command operation to the controller. See the Denali NAND * controller's user guide for more information (section 4.2.3.6). @@ -843,17 +878,6 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, return 0; } -static uint8_t denali_read_byte(struct mtd_info *mtd) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - uint8_t result = 0xff; - - if (denali->buf.head < denali->buf.tail) - result = denali->buf.buf[denali->buf.head++]; - - return result; -} - static void denali_select_chip(struct mtd_info *mtd, int chip) { struct denali_nand_info *denali = mtd_to_denali(mtd); @@ -863,7 +887,13 @@ static void denali_select_chip(struct mtd_info *mtd, int chip) static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) { - return 0; + struct denali_nand_info *denali = mtd_to_denali(mtd); + uint32_t irq_status; + + /* R/B# pin transitioned from low to high? */ + irq_status = denali_wait_for_irq(denali, INTR__INT_ACT); + + return irq_status & INTR__INT_ACT ? 0 : NAND_STATUS_FAIL; } static int denali_erase(struct mtd_info *mtd, int page) @@ -884,45 +914,6 @@ static int denali_erase(struct mtd_info *mtd, int page) return irq_status & INTR__ERASE_COMP ? 0 : NAND_STATUS_FAIL; } -static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, - int page) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t addr, id; - int i; - - switch (cmd) { - case NAND_CMD_STATUS: - read_status(denali); - break; - case NAND_CMD_READID: - case NAND_CMD_PARAM: - reset_buf(denali); - /* - * sometimes ManufactureId read from register is not right - * e.g. some of Micron MT29F32G08QAA MLC NAND chips - * So here we send READID cmd to NAND insteand - */ - addr = MODE_11 | BANK(denali->flash_bank); - index_addr(denali, addr | 0, 0x90); - index_addr(denali, addr | 1, col); - for (i = 0; i < 8; i++) { - index_addr_read_data(denali, addr | 2, &id); - write_byte_to_buf(denali, id); - } - break; - case NAND_CMD_RESET: - reset_bank(denali); - break; - case NAND_CMD_READOOB: - /* TODO: Read OOB data */ - break; - default: - pr_err(": unsupported command received 0x%x\n", cmd); - break; - } -} - #define DIV_ROUND_DOWN_ULL(ll, d) \ ({ unsigned long long _tmp = (ll); do_div(_tmp, d); _tmp; }) @@ -1238,12 +1229,6 @@ int denali_init(struct denali_nand_info *denali) struct mtd_info *mtd = nand_to_mtd(chip); int ret; - /* allocate a temporary buffer for nand_scan_ident() */ - denali->buf.buf = devm_kzalloc(denali->dev, PAGE_SIZE, - GFP_DMA | GFP_KERNEL); - if (!denali->buf.buf) - return -ENOMEM; - mtd->dev.parent = denali->dev; denali_hw_init(denali); denali_drv_init(denali); @@ -1267,11 +1252,14 @@ int denali_init(struct denali_nand_info *denali) /* register the driver with the NAND core subsystem */ chip->select_chip = denali_select_chip; - chip->cmdfunc = denali_cmdfunc; chip->read_byte = denali_read_byte; + chip->read_word = denali_read_word; + chip->read_buf = denali_read_buf; + chip->write_byte = denali_write_byte; + chip->write_buf = denali_write_buf; + chip->cmd_ctrl = denali_cmd_ctrl; + chip->dev_ready = denali_dev_ready; chip->waitfunc = denali_waitfunc; - chip->onfi_set_features = nand_onfi_get_set_features_notsupp; - chip->onfi_get_features = nand_onfi_get_set_features_notsupp; /* clk rate info is needed for setup_data_interface */ if (denali->clk_x_rate) @@ -1286,8 +1274,6 @@ int denali_init(struct denali_nand_info *denali) if (ret) goto disable_irq; - /* allocate the right size buffer now */ - devm_kfree(denali->dev, denali->buf.buf); denali->buf.buf = devm_kzalloc(denali->dev, mtd->writesize + mtd->oobsize, GFP_KERNEL); diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index a0ac0f84f8b5..a84d8784ee98 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -306,8 +306,6 @@ #define MODE_11 0x0C000000 struct nand_buf { - int head; - int tail; uint8_t *buf; dma_addr_t dma_buf; };