Commit 98d4fda8 authored by Miquel Raynal's avatar Miquel Raynal

Merge tag 'nand/for-6.8' into mtd/next

* Raw NAND

The most meaningful change being the conversion of the brcmnand driver
to the ->exec_op() API, this series brought additional changes to the
core in order to help controller drivers to handle themselves the WP pin
during destructive operations when relevant.

As always, there is as well a whole bunch of miscellaneous W=1 fixes,
together with a few runtime fixes (double free, timeout value, OOB
layout, missing register initialization) and the usual load of remove
callbacks turned into void (which led to switch the txx9ndfmc driver to
use module_platform_driver()).
parents 67629667 023e6aad
...@@ -85,7 +85,7 @@ MODULE_DEVICE_TABLE(of, bcm63138_nand_of_match); ...@@ -85,7 +85,7 @@ MODULE_DEVICE_TABLE(of, bcm63138_nand_of_match);
static struct platform_driver bcm63138_nand_driver = { static struct platform_driver bcm63138_nand_driver = {
.probe = bcm63138_nand_probe, .probe = bcm63138_nand_probe,
.remove = brcmnand_remove, .remove_new = brcmnand_remove,
.driver = { .driver = {
.name = "bcm63138_nand", .name = "bcm63138_nand",
.pm = &brcmnand_pm_ops, .pm = &brcmnand_pm_ops,
......
...@@ -117,7 +117,7 @@ MODULE_DEVICE_TABLE(of, bcm6368_nand_of_match); ...@@ -117,7 +117,7 @@ MODULE_DEVICE_TABLE(of, bcm6368_nand_of_match);
static struct platform_driver bcm6368_nand_driver = { static struct platform_driver bcm6368_nand_driver = {
.probe = bcm6368_nand_probe, .probe = bcm6368_nand_probe,
.remove = brcmnand_remove, .remove_new = brcmnand_remove,
.driver = { .driver = {
.name = "bcm6368_nand", .name = "bcm6368_nand",
.pm = &brcmnand_pm_ops, .pm = &brcmnand_pm_ops,
......
...@@ -119,7 +119,7 @@ static int brcmnand_bcma_nand_probe(struct platform_device *pdev) ...@@ -119,7 +119,7 @@ static int brcmnand_bcma_nand_probe(struct platform_device *pdev)
static struct platform_driver brcmnand_bcma_nand_driver = { static struct platform_driver brcmnand_bcma_nand_driver = {
.probe = brcmnand_bcma_nand_probe, .probe = brcmnand_bcma_nand_probe,
.remove = brcmnand_remove, .remove_new = brcmnand_remove,
.driver = { .driver = {
.name = "bcma_brcmnand", .name = "bcma_brcmnand",
.pm = &brcmnand_pm_ops, .pm = &brcmnand_pm_ops,
......
This diff is collapsed.
...@@ -88,7 +88,7 @@ static inline void brcmnand_soc_write(struct brcmnand_soc *soc, u32 val, ...@@ -88,7 +88,7 @@ static inline void brcmnand_soc_write(struct brcmnand_soc *soc, u32 val,
} }
int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc); int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc);
int brcmnand_remove(struct platform_device *pdev); void brcmnand_remove(struct platform_device *pdev);
extern const struct dev_pm_ops brcmnand_pm_ops; extern const struct dev_pm_ops brcmnand_pm_ops;
......
...@@ -23,7 +23,7 @@ static int brcmstb_nand_probe(struct platform_device *pdev) ...@@ -23,7 +23,7 @@ static int brcmstb_nand_probe(struct platform_device *pdev)
static struct platform_driver brcmstb_nand_driver = { static struct platform_driver brcmstb_nand_driver = {
.probe = brcmstb_nand_probe, .probe = brcmstb_nand_probe,
.remove = brcmnand_remove, .remove_new = brcmnand_remove,
.driver = { .driver = {
.name = "brcmstb_nand", .name = "brcmstb_nand",
.pm = &brcmnand_pm_ops, .pm = &brcmnand_pm_ops,
......
...@@ -134,7 +134,7 @@ MODULE_DEVICE_TABLE(of, iproc_nand_of_match); ...@@ -134,7 +134,7 @@ MODULE_DEVICE_TABLE(of, iproc_nand_of_match);
static struct platform_driver iproc_nand_driver = { static struct platform_driver iproc_nand_driver = {
.probe = iproc_nand_probe, .probe = iproc_nand_probe,
.remove = brcmnand_remove, .remove_new = brcmnand_remove,
.driver = { .driver = {
.name = "iproc_nand", .name = "iproc_nand",
.pm = &brcmnand_pm_ops, .pm = &brcmnand_pm_ops,
......
...@@ -1491,10 +1491,12 @@ static int __init doc_probe(unsigned long physadr) ...@@ -1491,10 +1491,12 @@ static int __init doc_probe(unsigned long physadr)
else else
numchips = doc2001_init(mtd); numchips = doc2001_init(mtd);
if ((ret = nand_scan(nand, numchips)) || (ret = doc->late_init(mtd))) { ret = nand_scan(nand, numchips);
/* DBB note: i believe nand_cleanup is necessary here, as if (ret)
buffers may have been allocated in nand_base. Check with goto fail;
Thomas. FIX ME! */
ret = doc->late_init(mtd);
if (ret) {
nand_cleanup(nand); nand_cleanup(nand);
goto fail; goto fail;
} }
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
#define ERR_BYTE 0xFF /* Value returned for read #define ERR_BYTE 0xFF /* Value returned for read
bytes when read failed */ bytes when read failed */
#define IFC_TIMEOUT_MSECS 500 /* Maximum number of mSecs to wait #define IFC_TIMEOUT_MSECS 1000 /* Maximum timeout to wait
for IFC NAND Machine */ for IFC NAND Machine */
struct fsl_ifc_ctrl; struct fsl_ifc_ctrl;
......
...@@ -90,6 +90,8 @@ ...@@ -90,6 +90,8 @@
/* eMMC clock register, misc control */ /* eMMC clock register, misc control */
#define CLK_SELECT_NAND BIT(31) #define CLK_SELECT_NAND BIT(31)
#define CLK_ALWAYS_ON_NAND BIT(24)
#define CLK_SELECT_FIX_PLL2 BIT(6)
#define NFC_CLK_CYCLE 6 #define NFC_CLK_CYCLE 6
...@@ -509,7 +511,7 @@ static void meson_nfc_set_user_byte(struct nand_chip *nand, u8 *oob_buf) ...@@ -509,7 +511,7 @@ static void meson_nfc_set_user_byte(struct nand_chip *nand, u8 *oob_buf)
__le64 *info; __le64 *info;
int i, count; int i, count;
for (i = 0, count = 0; i < nand->ecc.steps; i++, count += 2) { for (i = 0, count = 0; i < nand->ecc.steps; i++, count += (2 + nand->ecc.bytes)) {
info = &meson_chip->info_buf[i]; info = &meson_chip->info_buf[i];
*info |= oob_buf[count]; *info |= oob_buf[count];
*info |= oob_buf[count + 1] << 8; *info |= oob_buf[count + 1] << 8;
...@@ -522,7 +524,7 @@ static void meson_nfc_get_user_byte(struct nand_chip *nand, u8 *oob_buf) ...@@ -522,7 +524,7 @@ static void meson_nfc_get_user_byte(struct nand_chip *nand, u8 *oob_buf)
__le64 *info; __le64 *info;
int i, count; int i, count;
for (i = 0, count = 0; i < nand->ecc.steps; i++, count += 2) { for (i = 0, count = 0; i < nand->ecc.steps; i++, count += (2 + nand->ecc.bytes)) {
info = &meson_chip->info_buf[i]; info = &meson_chip->info_buf[i];
oob_buf[count] = *info; oob_buf[count] = *info;
oob_buf[count + 1] = *info >> 8; oob_buf[count + 1] = *info >> 8;
...@@ -1154,7 +1156,7 @@ static int meson_nfc_clk_init(struct meson_nfc *nfc) ...@@ -1154,7 +1156,7 @@ static int meson_nfc_clk_init(struct meson_nfc *nfc)
return PTR_ERR(nfc->nand_clk); return PTR_ERR(nfc->nand_clk);
/* init SD_EMMC_CLOCK to sane defaults w/min clock rate */ /* init SD_EMMC_CLOCK to sane defaults w/min clock rate */
writel(CLK_SELECT_NAND | readl(nfc->reg_clk), writel(CLK_ALWAYS_ON_NAND | CLK_SELECT_NAND | CLK_SELECT_FIX_PLL2,
nfc->reg_clk); nfc->reg_clk);
ret = clk_prepare_enable(nfc->core_clk); ret = clk_prepare_enable(nfc->core_clk);
......
...@@ -366,6 +366,10 @@ static int nand_check_wp(struct nand_chip *chip) ...@@ -366,6 +366,10 @@ static int nand_check_wp(struct nand_chip *chip)
if (chip->options & NAND_BROKEN_XD) if (chip->options & NAND_BROKEN_XD)
return 0; return 0;
/* controller responsible for NAND write protect */
if (chip->controller->controller_wp)
return 0;
/* Check the WP bit */ /* Check the WP bit */
ret = nand_status_op(chip, &status); ret = nand_status_op(chip, &status);
if (ret) if (ret)
...@@ -1523,7 +1527,8 @@ static int nand_exec_prog_page_op(struct nand_chip *chip, unsigned int page, ...@@ -1523,7 +1527,8 @@ static int nand_exec_prog_page_op(struct nand_chip *chip, unsigned int page,
NAND_COMMON_TIMING_NS(conf, tWB_max)), NAND_COMMON_TIMING_NS(conf, tWB_max)),
NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tPROG_max), 0), NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tPROG_max), 0),
}; };
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); struct nand_operation op = NAND_DESTRUCTIVE_OPERATION(chip->cur_cs,
instrs);
int naddrs = nand_fill_column_cycles(chip, addrs, offset_in_page); int naddrs = nand_fill_column_cycles(chip, addrs, offset_in_page);
if (naddrs < 0) if (naddrs < 0)
...@@ -1946,7 +1951,8 @@ int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock) ...@@ -1946,7 +1951,8 @@ int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock)
NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tBERS_max), NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tBERS_max),
0), 0),
}; };
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); struct nand_operation op = NAND_DESTRUCTIVE_OPERATION(chip->cur_cs,
instrs);
if (chip->options & NAND_ROW_ADDR_3) if (chip->options & NAND_ROW_ADDR_3)
instrs[1].ctx.addr.naddrs++; instrs[1].ctx.addr.naddrs++;
......
...@@ -128,7 +128,7 @@ struct pl35x_nand { ...@@ -128,7 +128,7 @@ struct pl35x_nand {
* @conf_regs: SMC configuration registers for command phase * @conf_regs: SMC configuration registers for command phase
* @io_regs: NAND data registers for data phase * @io_regs: NAND data registers for data phase
* @controller: Core NAND controller structure * @controller: Core NAND controller structure
* @chip: NAND chip information structure * @chips: List of connected NAND chips
* @selected_chip: NAND chip currently selected by the controller * @selected_chip: NAND chip currently selected by the controller
* @assigned_cs: List of assigned CS * @assigned_cs: List of assigned CS
* @ecc_buf: Temporary buffer to extract ECC bytes * @ecc_buf: Temporary buffer to extract ECC bytes
......
...@@ -98,7 +98,7 @@ enum nfc_type { ...@@ -98,7 +98,7 @@ enum nfc_type {
* @high: ECC count high bit index at register. * @high: ECC count high bit index at register.
* @high_mask: mask bit * @high_mask: mask bit
*/ */
struct ecc_cnt_status { struct rk_ecc_cnt_status {
u8 err_flag_bit; u8 err_flag_bit;
u8 low; u8 low;
u8 low_mask; u8 low_mask;
...@@ -108,6 +108,7 @@ struct ecc_cnt_status { ...@@ -108,6 +108,7 @@ struct ecc_cnt_status {
}; };
/** /**
* struct nfc_cfg: Rockchip NAND controller configuration
* @type: NFC version * @type: NFC version
* @ecc_strengths: ECC strengths * @ecc_strengths: ECC strengths
* @ecc_cfgs: ECC config values * @ecc_cfgs: ECC config values
...@@ -144,8 +145,8 @@ struct nfc_cfg { ...@@ -144,8 +145,8 @@ struct nfc_cfg {
u32 int_st_off; u32 int_st_off;
u32 oob0_off; u32 oob0_off;
u32 oob1_off; u32 oob1_off;
struct ecc_cnt_status ecc0; struct rk_ecc_cnt_status ecc0;
struct ecc_cnt_status ecc1; struct rk_ecc_cnt_status ecc1;
}; };
struct rk_nfc_nand_chip { struct rk_nfc_nand_chip {
......
...@@ -105,7 +105,6 @@ struct s3c2410_nand_info; ...@@ -105,7 +105,6 @@ struct s3c2410_nand_info;
/** /**
* struct s3c2410_nand_mtd - driver MTD structure * struct s3c2410_nand_mtd - driver MTD structure
* @mtd: The MTD instance to pass to the MTD layer.
* @chip: The NAND chip information. * @chip: The NAND chip information.
* @set: The platform information supplied for this set of NAND chips. * @set: The platform information supplied for this set of NAND chips.
* @info: Link back to the hardware information. * @info: Link back to the hardware information.
...@@ -145,7 +144,6 @@ enum s3c_nand_clk_state { ...@@ -145,7 +144,6 @@ enum s3c_nand_clk_state {
* @clk_rate: The clock rate from @clk. * @clk_rate: The clock rate from @clk.
* @clk_state: The current clock state. * @clk_state: The current clock state.
* @cpu_type: The exact type of this controller. * @cpu_type: The exact type of this controller.
* @freq_transition: CPUFreq notifier block
*/ */
struct s3c2410_nand_info { struct s3c2410_nand_info {
/* mtd info */ /* mtd info */
......
...@@ -276,7 +276,7 @@ static const struct nand_controller_ops txx9ndfmc_controller_ops = { ...@@ -276,7 +276,7 @@ static const struct nand_controller_ops txx9ndfmc_controller_ops = {
.attach_chip = txx9ndfmc_attach_chip, .attach_chip = txx9ndfmc_attach_chip,
}; };
static int __init txx9ndfmc_probe(struct platform_device *dev) static int txx9ndfmc_probe(struct platform_device *dev)
{ {
struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev); struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
int hold, spw; int hold, spw;
...@@ -369,13 +369,11 @@ static int __init txx9ndfmc_probe(struct platform_device *dev) ...@@ -369,13 +369,11 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
return 0; return 0;
} }
static int __exit txx9ndfmc_remove(struct platform_device *dev) static void txx9ndfmc_remove(struct platform_device *dev)
{ {
struct txx9ndfmc_drvdata *drvdata = platform_get_drvdata(dev); struct txx9ndfmc_drvdata *drvdata = platform_get_drvdata(dev);
int ret, i; int ret, i;
if (!drvdata)
return 0;
for (i = 0; i < MAX_TXX9NDFMC_DEV; i++) { for (i = 0; i < MAX_TXX9NDFMC_DEV; i++) {
struct mtd_info *mtd = drvdata->mtds[i]; struct mtd_info *mtd = drvdata->mtds[i];
struct nand_chip *chip; struct nand_chip *chip;
...@@ -392,7 +390,6 @@ static int __exit txx9ndfmc_remove(struct platform_device *dev) ...@@ -392,7 +390,6 @@ static int __exit txx9ndfmc_remove(struct platform_device *dev)
kfree(txx9_priv->mtdname); kfree(txx9_priv->mtdname);
kfree(txx9_priv); kfree(txx9_priv);
} }
return 0;
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
...@@ -407,14 +404,14 @@ static int txx9ndfmc_resume(struct platform_device *dev) ...@@ -407,14 +404,14 @@ static int txx9ndfmc_resume(struct platform_device *dev)
#endif #endif
static struct platform_driver txx9ndfmc_driver = { static struct platform_driver txx9ndfmc_driver = {
.remove = __exit_p(txx9ndfmc_remove), .probe = txx9ndfmc_probe,
.remove_new = txx9ndfmc_remove,
.resume = txx9ndfmc_resume, .resume = txx9ndfmc_resume,
.driver = { .driver = {
.name = "txx9ndfmc", .name = "txx9ndfmc",
}, },
}; };
module_platform_driver(txx9ndfmc_driver);
module_platform_driver_probe(txx9ndfmc_driver, txx9ndfmc_probe);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("TXx9 SoC NAND flash controller driver"); MODULE_DESCRIPTION("TXx9 SoC NAND flash controller driver");
......
...@@ -1003,6 +1003,8 @@ struct nand_op_parser { ...@@ -1003,6 +1003,8 @@ struct nand_op_parser {
/** /**
* struct nand_operation - NAND operation descriptor * struct nand_operation - NAND operation descriptor
* @cs: the CS line to select for this NAND operation * @cs: the CS line to select for this NAND operation
* @deassert_wp: set to true when the operation requires the WP pin to be
* de-asserted (ERASE, PROG, ...)
* @instrs: array of instructions to execute * @instrs: array of instructions to execute
* @ninstrs: length of the @instrs array * @ninstrs: length of the @instrs array
* *
...@@ -1010,6 +1012,7 @@ struct nand_op_parser { ...@@ -1010,6 +1012,7 @@ struct nand_op_parser {
*/ */
struct nand_operation { struct nand_operation {
unsigned int cs; unsigned int cs;
bool deassert_wp;
const struct nand_op_instr *instrs; const struct nand_op_instr *instrs;
unsigned int ninstrs; unsigned int ninstrs;
}; };
...@@ -1021,6 +1024,14 @@ struct nand_operation { ...@@ -1021,6 +1024,14 @@ struct nand_operation {
.ninstrs = ARRAY_SIZE(_instrs), \ .ninstrs = ARRAY_SIZE(_instrs), \
} }
#define NAND_DESTRUCTIVE_OPERATION(_cs, _instrs) \
{ \
.cs = _cs, \
.deassert_wp = true, \
.instrs = _instrs, \
.ninstrs = ARRAY_SIZE(_instrs), \
}
int nand_op_parser_exec_op(struct nand_chip *chip, int nand_op_parser_exec_op(struct nand_chip *chip,
const struct nand_op_parser *parser, const struct nand_op_parser *parser,
const struct nand_operation *op, bool check_only); const struct nand_operation *op, bool check_only);
...@@ -1104,6 +1115,7 @@ struct nand_controller_ops { ...@@ -1104,6 +1115,7 @@ struct nand_controller_ops {
* the bus without restarting an entire read operation nor * the bus without restarting an entire read operation nor
* changing the column. * changing the column.
* @supported_op.cont_read: The controller supports sequential cache reads. * @supported_op.cont_read: The controller supports sequential cache reads.
* @controller_wp: the controller is in charge of handling the WP pin.
*/ */
struct nand_controller { struct nand_controller {
struct mutex lock; struct mutex lock;
...@@ -1112,6 +1124,7 @@ struct nand_controller { ...@@ -1112,6 +1124,7 @@ struct nand_controller {
unsigned int data_only_read: 1; unsigned int data_only_read: 1;
unsigned int cont_read: 1; unsigned int cont_read: 1;
} supported_op; } supported_op;
bool controller_wp;
}; };
static inline void nand_controller_init(struct nand_controller *nfc) static inline void nand_controller_init(struct nand_controller *nfc)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment