diff options
Diffstat (limited to 'drivers')
42 files changed, 1864 insertions, 344 deletions
diff --git a/drivers/bus/omap-gpmc.c b/drivers/bus/omap-gpmc.c index a3fccb2182..8fd7a91740 100644 --- a/drivers/bus/omap-gpmc.c +++ b/drivers/bus/omap-gpmc.c @@ -448,6 +448,9 @@ static struct dt_eccmode modes[] = { }, { .name = "bch8", .mode = OMAP_ECC_BCH8_CODE_HW_ROMCODE, + }, { + .name = "bch16", + .mode = OMAP_ECC_BCH16_CODE_HW, }, }; diff --git a/drivers/clk/zynqmp/clk-mux-zynqmp.c b/drivers/clk/zynqmp/clk-mux-zynqmp.c index 4003267bd1..4c15223980 100644 --- a/drivers/clk/zynqmp/clk-mux-zynqmp.c +++ b/drivers/clk/zynqmp/clk-mux-zynqmp.c @@ -15,7 +15,7 @@ #include "clk-zynqmp.h" -#define CLK_MUX_READ_ONLY BIT(3) +#define ZYNQMP_CLK_MUX_READ_ONLY BIT(3) struct zynqmp_clk_mux { struct clk clk; @@ -83,7 +83,7 @@ struct clk *zynqmp_clk_register_mux(const char *name, mux->ops = zynqmp_pm_get_eemi_ops(); mux->clk.name = strdup(name); - if (nodes->type_flag & CLK_MUX_READ_ONLY) + if (nodes->type_flag & ZYNQMP_CLK_MUX_READ_ONLY) mux->clk.ops = &zynqmp_clk_mux_ro_ops; else mux->clk.ops = &zynqmp_clk_mux_ops; diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig index 0e36c824ec..6844480b07 100644 --- a/drivers/eeprom/Kconfig +++ b/drivers/eeprom/Kconfig @@ -9,6 +9,7 @@ config EEPROM_AT25 on your target board. config EEPROM_AT24 + select NVMEM bool "at24 based eeprom" depends on I2C help diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index d397e803b1..42bde5ed1c 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -177,7 +177,7 @@ static int pca954x_probe(struct device_d *dev) { struct i2c_client *client = to_i2c_client(dev); struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); - int num, force; + int num; struct pca954x *data; uintptr_t tmp; int ret = -ENODEV; @@ -195,10 +195,11 @@ static int pca954x_probe(struct device_d *dev) if (gpio_is_valid(gpio)) gpio_direction_output(gpio, 1); - /* Read the mux register at addr to verify - * that the mux is in fact present. + /* Write the mux register at addr to verify + * that the mux is in fact present. This also + * initializes the mux to disconnected state. */ - if (i2c_smbus_read_byte(client) < 0) { + if (i2c_smbus_write_byte(client, 0) < 0) { dev_warn(&client->dev, "probe failed\n"); goto exit_free; } @@ -220,8 +221,8 @@ static int pca954x_probe(struct device_d *dev) if (data->virt_adaps[num] == NULL) { ret = -ENODEV; dev_err(&client->dev, - "failed to register multiplexed adapter" - " %d as bus %d\n", num, force); + "failed to register multiplexed adapter%d\n", + num); goto virt_reg_failed; } } diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 1f89ae3892..be061683fb 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -64,4 +64,10 @@ config KEYBOARD_USB help This driver implements support for usb keyboard. +config INPUT_SPECIALKEYS + bool "Special keys handler" + select INPUT + help + Say Y here to handle key events like KEY_RESTART and KEY_POWER. + endmenu diff --git a/drivers/input/Makefile b/drivers/input/Makefile index e694a98d10..36a4204d53 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o obj-$(CONFIG_KEYBOARD_TWL6030) += twl6030_pwrbtn.o obj-$(CONFIG_KEYBOARD_IMX_KEYPAD) += imx_keypad.o obj-$(CONFIG_KEYBOARD_QT1070) += qt1070.o +obj-$(CONFIG_INPUT_SPECIALKEYS) += specialkeys.o diff --git a/drivers/input/specialkeys.c b/drivers/input/specialkeys.c new file mode 100644 index 0000000000..ff29b8455d --- /dev/null +++ b/drivers/input/specialkeys.c @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2019 Ahmad Fatoum, Pengutronix + +#include <common.h> +#include <restart.h> +#include <poweroff.h> +#include <init.h> +#include <input/input.h> +#include <dt-bindings/input/linux-event-codes.h> + +static void input_specialkeys_notify(struct input_notifier *in, + struct input_event *ev) +{ + switch (ev->code) { + case KEY_RESTART: + pr_info("Triggering reset due to special key.\n", ev->code); + restart_machine(); + break; + + case KEY_POWER: + pr_info("Triggering poweroff due to special key.\n", ev->code); + poweroff_machine(); + break; + } + + pr_debug("ignoring code: %d\n", ev->code); +} + +static struct input_notifier notifier; + +static int input_specialkeys_init(void) +{ + notifier.notify = input_specialkeys_notify; + return input_register_notfier(¬ifier); +} +late_initcall(input_specialkeys_init); diff --git a/drivers/mfd/rave-sp.c b/drivers/mfd/rave-sp.c index 1448c4143f..67f7d4c654 100644 --- a/drivers/mfd/rave-sp.c +++ b/drivers/mfd/rave-sp.c @@ -640,6 +640,7 @@ static int rave_sp_emulated_get_status(struct rave_sp *sp, [0] = RAVE_SP_CMD_GET_FIRMWARE_VERSION, [1] = 0, }; + u8 firmware_mode; int ret; ret = rave_sp_exec(sp, cmd, sizeof(cmd), &status->firmware_version, @@ -648,8 +649,21 @@ static int rave_sp_emulated_get_status(struct rave_sp *sp, return ret; cmd[0] = RAVE_SP_CMD_GET_BOOTLOADER_VERSION; - return rave_sp_exec(sp, cmd, sizeof(cmd), &status->bootloader_version, - sizeof(status->bootloader_version)); + ret = rave_sp_exec(sp, cmd, sizeof(cmd), &status->bootloader_version, + sizeof(status->bootloader_version)); + if (ret) + return ret; + + cmd[0] = RAVE_SP_CMD_GET_OPERATIONAL_MODE; + ret = rave_sp_exec(sp, cmd, sizeof(cmd), &firmware_mode, + sizeof(firmware_mode)); + if (ret) + return ret; + + status->general_status = + firmware_mode ? RAVE_SP_STATUS_GS_FIRMWARE_MODE : 0; + + return 0; } static int rave_sp_get_status(struct rave_sp *sp) diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 2b4a478a03..fadfe1f99b 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -90,6 +90,16 @@ config NAND_OMAP_GPMC Support for NAND flash using GPMC. GPMC is a common memory interface found on Texas Instrument's OMAP platforms +config MTD_NAND_OMAP_ELM + bool "Support for ELM (Error Location Module) on OMAP platforms" + depends on NAND_OMAP_GPMC + help + This config enables the ELM hardware engine, which can be used to + locate and correct errors when using BCH ECC scheme. This offloads + the cpu from doing ECC error searching and correction. However some + legacy OMAP families like OMAP2xxx, OMAP3xxx do not have ELM engine + so this is optional for them. + config NAND_ORION bool prompt "Marvell Orion NAND driver" diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 6088512745..a4066ba778 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_MTD_NAND_NOMADIK) += nomadik_nand.o obj-$(CONFIG_NAND_IMX) += nand_imx.o obj-$(CONFIG_NAND_IMX_BBM) += nand_imx_bbm.o obj-$(CONFIG_NAND_OMAP_GPMC) += nand_omap_gpmc.o nand_omap_bch_decoder.o +obj-$(CONFIG_MTD_NAND_OMAP_ELM) += omap_elm.o obj-$(CONFIG_NAND_ORION) += nand_orion.o obj-$(CONFIG_NAND_MRVL_NFC) += nand_mrvl_nfc.o obj-$(CONFIG_NAND_ATMEL) += atmel_nand.o diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index b4d4e79d91..f3875a5648 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -77,7 +77,6 @@ static struct nand_ecclayout atmel_oobinfo_small = { struct atmel_nand_host { struct nand_chip nand_chip; - struct mtd_info mtd; void __iomem *io_base; struct atmel_nand_data *board; struct device_d *dev; @@ -130,7 +129,7 @@ static void atmel_nand_disable(struct atmel_nand_host *host) */ static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); struct atmel_nand_host *host = nand_chip->priv; if (ctrl & NAND_CTRL_CHANGE) { @@ -153,7 +152,7 @@ static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl */ static int atmel_nand_device_ready(struct mtd_info *mtd) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); struct atmel_nand_host *host = nand_chip->priv; return gpio_get_value(host->board->rdy_pin); @@ -164,28 +163,28 @@ static int atmel_nand_device_ready(struct mtd_info *mtd) */ static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); readsb(nand_chip->IO_ADDR_R, buf, len); } static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); readsw(nand_chip->IO_ADDR_R, buf, len / 2); } static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); writesb(nand_chip->IO_ADDR_W, buf, len); } static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); writesw(nand_chip->IO_ADDR_W, buf, len / 2); } @@ -277,7 +276,7 @@ static int pmecc_data_alloc(struct atmel_nand_host *host) static void pmecc_gen_syndrome(struct mtd_info *mtd, int sector) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); struct atmel_nand_host *host = nand_chip->priv; int i; uint32_t value; @@ -294,7 +293,7 @@ static void pmecc_gen_syndrome(struct mtd_info *mtd, int sector) static void pmecc_substitute(struct mtd_info *mtd) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); struct atmel_nand_host *host = nand_chip->priv; int16_t __iomem *alpha_to = host->pmecc_alpha_to; int16_t __iomem *index_of = host->pmecc_index_of; @@ -336,7 +335,7 @@ static void pmecc_substitute(struct mtd_info *mtd) static void pmecc_get_sigma(struct mtd_info *mtd) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); struct atmel_nand_host *host = nand_chip->priv; int16_t *lmu = host->pmecc_lmu; @@ -494,7 +493,7 @@ static void pmecc_get_sigma(struct mtd_info *mtd) static int pmecc_err_location(struct mtd_info *mtd) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); struct atmel_nand_host *host = nand_chip->priv; const int cap = host->board->pmecc_corr_cap; const int num = 2 * cap + 1; @@ -543,7 +542,7 @@ static int pmecc_err_location(struct mtd_info *mtd) static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc, int sector_num, int extra_bytes, int err_nbr) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); struct atmel_nand_host *host = nand_chip->priv; int i = 0; int byte_pos, bit_pos, sector_size, pos; @@ -589,7 +588,7 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc, static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf, u8 *ecc) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); struct atmel_nand_host *host = nand_chip->priv; int i, err_nbr, eccbytes; uint8_t *buf_pos; @@ -706,7 +705,7 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, static void atmel_pmecc_core_init(struct mtd_info *mtd) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); struct atmel_nand_host *host = nand_chip->priv; uint32_t val = 0; struct nand_ecclayout *ecc_layout; @@ -862,8 +861,8 @@ static int __init atmel_pmecc_nand_init_params(struct device_d *dev, struct atmel_nand_host *host) { struct resource *iores; - struct mtd_info *mtd = &host->mtd; struct nand_chip *nand_chip = &host->nand_chip; + struct mtd_info *mtd = &nand_chip->mtd; int cap, sector_size, err_no; int ret; @@ -983,7 +982,7 @@ static int __init atmel_pmecc_nand_init_params(struct device_d *dev, static int atmel_nand_calculate(struct mtd_info *mtd, const u_char *dat, unsigned char *ecc_code) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); struct atmel_nand_host *host = nand_chip->priv; unsigned int ecc_value; @@ -1086,7 +1085,7 @@ static int atmel_nand_read_page(struct mtd_info *mtd, static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *isnull) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); struct atmel_nand_host *host = nand_chip->priv; unsigned int ecc_status; unsigned int ecc_word, ecc_bit; @@ -1154,7 +1153,7 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) { #if 0 if (cpu_is_at32ap7000()) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); struct atmel_nand_host *host = nand_chip->priv; ecc_writel(host->ecc, CR, ATMEL_ECC_RST); } @@ -1251,8 +1250,8 @@ static int atmel_hw_nand_init_params(struct device_d *dev, struct atmel_nand_host *host) { struct resource *iores; - struct mtd_info *mtd = &host->mtd; struct nand_chip *nand_chip = &host->nand_chip; + struct mtd_info *mtd = &nand_chip->mtd; iores = dev_request_mem_resource(dev, 1); if (IS_ERR(iores)) @@ -1328,8 +1327,8 @@ static int __init atmel_nand_probe(struct device_d *dev) return PTR_ERR(iores); host->io_base = IOMEM(iores->start); - mtd = &host->mtd; nand_chip = &host->nand_chip; + mtd = &nand_chip->mtd; host->board = pdata; host->dev = dev; @@ -1342,7 +1341,6 @@ static int __init atmel_nand_probe(struct device_d *dev) } nand_chip->priv = host; /* link the private data structures */ - mtd->priv = nand_chip; mtd->parent = dev; /* Set address of NAND IO lines */ diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index 515353e277..7698b59720 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -464,7 +464,6 @@ struct nand_buf { #define DT 3 struct denali_nand_info { - struct mtd_info mtd; struct nand_chip nand; int flash_bank; /* currently selected chip */ int status; diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 9c0c01694a..6b7d01919c 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -97,7 +97,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, static int check_offs_len(struct mtd_info *mtd, loff_t ofs, uint64_t len) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); int ret = 0; /* Start address must align on block boundary */ @@ -123,7 +123,7 @@ static int check_offs_len(struct mtd_info *mtd, */ static void nand_release_device(struct mtd_info *mtd) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); /* Release the controller and the chip */ chip->controller->active = NULL; @@ -138,7 +138,7 @@ static void nand_release_device(struct mtd_info *mtd) */ static uint8_t nand_read_byte(struct mtd_info *mtd) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); return readb(chip->IO_ADDR_R); } @@ -152,7 +152,7 @@ static uint8_t nand_read_byte(struct mtd_info *mtd) */ static uint8_t nand_read_byte16(struct mtd_info *mtd) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R)); } @@ -164,7 +164,7 @@ static uint8_t nand_read_byte16(struct mtd_info *mtd) */ static u16 nand_read_word(struct mtd_info *mtd) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); return readw(chip->IO_ADDR_R); } @@ -177,7 +177,7 @@ static u16 nand_read_word(struct mtd_info *mtd) */ static void nand_select_chip(struct mtd_info *mtd, int chipnr) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); switch (chipnr) { case -1: @@ -203,7 +203,7 @@ static __maybe_unused void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) { int i; - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); for (i = 0; i < len; i++) writeb(buf[i], chip->IO_ADDR_W); @@ -220,7 +220,7 @@ static __maybe_unused void nand_write_buf(struct mtd_info *mtd, static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) { int i; - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); for (i = 0; i < len; i++) buf[i] = readb(chip->IO_ADDR_R); @@ -238,7 +238,7 @@ static __maybe_unused void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) { int i; - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); u16 *p = (u16 *) buf; len >>= 1; @@ -258,7 +258,7 @@ static __maybe_unused void nand_write_buf16(struct mtd_info *mtd, static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) { int i; - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); u16 *p = (u16 *) buf; len >>= 1; @@ -277,7 +277,7 @@ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) { int page, chipnr, res = 0, i = 0; - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); u16 bad; if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) @@ -337,7 +337,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) */ static __maybe_unused int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); struct mtd_oob_ops ops; uint8_t buf[2] = { 0, 0 }; int ret = 0, res, i = 0; @@ -387,7 +387,7 @@ static __maybe_unused int nand_default_block_markbad(struct mtd_info *mtd, loff_ */ static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); int res, ret = 0; if (!(chip->bbt_options & NAND_BBT_NO_OOB_BBM)) { @@ -431,7 +431,7 @@ static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs) */ static int nand_block_markgood_lowlevel(struct mtd_info *mtd, loff_t ofs) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); bool allow_erasebad; int ret; @@ -479,7 +479,7 @@ static int nand_block_markgood_lowlevel(struct mtd_info *mtd, loff_t ofs) */ static int nand_check_wp(struct mtd_info *mtd) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); /* Broken xD cards report WP despite being writable */ if (chip->options & NAND_BROKEN_XD) @@ -503,7 +503,7 @@ static int nand_check_wp(struct mtd_info *mtd) static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); if (IS_ENABLED(CONFIG_NAND_BBT) && chip->bbt) { /* Return info from the table */ @@ -516,7 +516,7 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, /* Wait for the ready pin, after a command. The timeout is caught later. */ void nand_wait_ready(struct mtd_info *mtd) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); uint64_t start = get_time_ns(); /* wait until command is processed or timeout occures */ @@ -539,7 +539,7 @@ void nand_wait_ready(struct mtd_info *mtd) static void nand_command(struct mtd_info *mtd, unsigned int command, int column, int page_addr) { - register struct nand_chip *chip = mtd->priv; + register struct nand_chip *chip = mtd_to_nand(mtd); int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE; /* Write out the command to the device */ @@ -641,7 +641,7 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, static void nand_command_lp(struct mtd_info *mtd, unsigned int command, int column, int page_addr) { - register struct nand_chip *chip = mtd->priv; + register struct nand_chip *chip = mtd_to_nand(mtd); /* Emulate NAND_CMD_READOOB */ if (command == NAND_CMD_READOOB) { @@ -748,7 +748,7 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, static int nand_get_device(struct mtd_info *mtd, int new_state) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); retry: /* Hardware controller shared among independent devices */ @@ -826,7 +826,7 @@ static int __nand_unlock(struct mtd_info *mtd, loff_t ofs, { int ret = 0; int status, page; - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); /* Submit address of first page to unlock */ page = ofs >> chip->page_shift; @@ -861,7 +861,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { int ret = 0; int chipnr; - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); pr_debug("%s: start = 0x%012llx, len = %llu\n", __func__, (unsigned long long)ofs, len); @@ -924,7 +924,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { int ret = 0; int chipnr, status, page; - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); pr_debug("%s: start = 0x%012llx, len = %llu\n", __func__, (unsigned long long)ofs, len); @@ -1537,7 +1537,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { int chipnr, page, realpage, col, bytes, aligned, oob_required; - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); struct mtd_ecc_stats stats; int ret = 0; uint32_t readlen = ops->len; @@ -1854,7 +1854,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { int page, realpage, chipnr; - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); struct mtd_ecc_stats stats; int readlen = ops->ooblen; int len; @@ -2317,7 +2317,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len, struct mtd_oob_ops *ops) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); /* * Initialise to all 0xFF, to avoid the possibility of left over OOB @@ -2377,7 +2377,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) { int chipnr, realpage, page, blockmask, column; - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); uint32_t writelen = ops->len; uint32_t oobwritelen = ops->ooblen; @@ -2522,7 +2522,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) { int chipnr, page, status, len; - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); if (!IS_ENABLED(CONFIG_MTD_WRITE)) return -ENOTSUPP; @@ -2653,7 +2653,7 @@ out: */ static void single_erase_cmd(struct mtd_info *mtd, int page) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); if (!IS_ENABLED(CONFIG_MTD_WRITE)) return; @@ -2690,7 +2690,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, int allowbbt) { int page, status, pages_per_block, ret, chipnr; - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); loff_t len; if (!IS_ENABLED(CONFIG_MTD_WRITE)) @@ -3517,7 +3517,7 @@ ident_done: */ void nand_of_parse_node(struct mtd_info *mtd, struct device_node *np) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); int ecc_strength, ecc_size; if (!IS_ENABLED(CONFIG_OFDEVICE)) @@ -3548,7 +3548,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, struct nand_flash_dev *table) { int i, busw, nand_maf_id, nand_dev_id; - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); struct nand_flash_dev *type; /* Get buswidth to select the correct functions */ @@ -3607,7 +3607,7 @@ EXPORT_SYMBOL(nand_scan_ident); int nand_scan_tail(struct mtd_info *mtd) { int i; - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); /* New bad blocks should be marked in OOB, flash-based BBT, or both */ BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) && @@ -3908,7 +3908,7 @@ EXPORT_SYMBOL(nand_scan); */ void nand_release(struct mtd_info *mtd) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); if (chip->ecc.mode == NAND_ECC_SOFT_BCH) nand_bch_free((struct nand_bch_control *)chip->ecc.priv); @@ -3960,7 +3960,7 @@ static const char *bbt_type_strings[] = { static int mtd_get_bbt_type(struct param_d *p, void *priv) { struct mtd_info *mtd = priv; - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); enum bbt_type type; if (!chip->bbt) @@ -3978,7 +3978,7 @@ static int mtd_get_bbt_type(struct param_d *p, void *priv) int add_mtd_nand_device(struct mtd_info *mtd, char *devname) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); int ret; ret = add_mtd_device(mtd, devname, DEVICE_ID_DYNAMIC); diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index a908a36544..ed4104629a 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -177,7 +177,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, struct nand_bbt_descr *td, int offs) { int res, ret = 0, i, j, act = 0; - struct nand_chip *this = mtd->priv; + struct nand_chip *this = mtd_to_nand(mtd); size_t retlen, len, totlen; loff_t from; int bits = td->options & NAND_BBT_NRBITS_MSK; @@ -264,7 +264,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, */ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip) { - struct nand_chip *this = mtd->priv; + struct nand_chip *this = mtd_to_nand(mtd); int res = 0, i; if (td->options & NAND_BBT_PERCHIP) { @@ -389,7 +389,7 @@ static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td) static void read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md) { - struct nand_chip *this = mtd->priv; + struct nand_chip *this = mtd_to_nand(mtd); /* Read the primary version, if available */ if (td->options & NAND_BBT_VERSION) { @@ -455,7 +455,7 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip) { - struct nand_chip *this = mtd->priv; + struct nand_chip *this = mtd_to_nand(mtd); int i, numblocks, numpages; int startblock; loff_t from; @@ -524,7 +524,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, */ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td) { - struct nand_chip *this = mtd->priv; + struct nand_chip *this = mtd_to_nand(mtd); int i, chips; int startblock, block, dir; int scanlen = mtd->writesize + mtd->oobsize; @@ -684,7 +684,7 @@ static void mark_bbt_block_bad(struct mtd_info *mtd, struct nand_bbt_descr *td, int chip, int block) { - struct nand_chip *this = mtd->priv; + struct nand_chip *this = mtd_to_nand(mtd); loff_t to; int res; @@ -713,7 +713,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel) { - struct nand_chip *this = mtd->priv; + struct nand_chip *this = mtd_to_nand(mtd); struct erase_info einfo; int i, res, chip = 0; int bits, page, offs, numblocks, sft, sftmsk; @@ -897,7 +897,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, */ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) { - struct nand_chip *this = mtd->priv; + struct nand_chip *this = mtd_to_nand(mtd); return create_bbt(mtd, this->buffers->databuf, bd, -1); } @@ -916,7 +916,7 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd) { int i, chips, writeops, create, chipsel, res, res2; - struct nand_chip *this = mtd->priv; + struct nand_chip *this = mtd_to_nand(mtd); struct nand_bbt_descr *td = this->bbt_td; struct nand_bbt_descr *md = this->bbt_md; struct nand_bbt_descr *rd, *rd2; @@ -1040,7 +1040,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc */ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) { - struct nand_chip *this = mtd->priv; + struct nand_chip *this = mtd_to_nand(mtd); int i, j, chips, block, nrblocks, update; uint8_t oldval; @@ -1100,7 +1100,7 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) */ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) { - struct nand_chip *this = mtd->priv; + struct nand_chip *this = mtd_to_nand(mtd); u32 pattern_len; u32 bits; u32 table_size; @@ -1152,7 +1152,7 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) */ static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) { - struct nand_chip *this = mtd->priv; + struct nand_chip *this = mtd_to_nand(mtd); int len, res; uint8_t *buf; struct nand_bbt_descr *td = this->bbt_td; @@ -1225,7 +1225,7 @@ err: */ int nand_update_bbt(struct mtd_info *mtd, loff_t offs) { - struct nand_chip *this = mtd->priv; + struct nand_chip *this = mtd_to_nand(mtd); int len, res = 0; int chip, chipsel; uint8_t *buf; @@ -1359,7 +1359,7 @@ static int nand_create_badblock_pattern(struct nand_chip *this) */ int nand_default_bbt(struct mtd_info *mtd) { - struct nand_chip *this = mtd->priv; + struct nand_chip *this = mtd_to_nand(mtd); int ret; /* Is a flash based bad block table requested? */ @@ -1396,7 +1396,7 @@ int nand_default_bbt(struct mtd_info *mtd) */ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) { - struct nand_chip *this = mtd->priv; + struct nand_chip *this = mtd_to_nand(mtd); int block; uint8_t res; @@ -1419,7 +1419,7 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) static int nand_mark_bbt(struct mtd_info *mtd, loff_t offs, uint8_t mark) { - struct nand_chip *this = mtd->priv; + struct nand_chip *this = mtd_to_nand(mtd); int block, ret = 0; block = (int)(offs >> this->bbt_erase_shift); diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c index d4f2a8cbe4..b94ecdf8d9 100644 --- a/drivers/mtd/nand/nand_bch.c +++ b/drivers/mtd/nand/nand_bch.c @@ -49,7 +49,7 @@ struct nand_bch_control { int nand_bch_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf, unsigned char *code) { - const struct nand_chip *chip = mtd->priv; + const struct nand_chip *chip = mtd_to_nand(mtd); struct nand_bch_control *nbc = chip->ecc.priv; unsigned int i; @@ -76,7 +76,7 @@ EXPORT_SYMBOL(nand_bch_calculate_ecc); int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf, unsigned char *read_ecc, unsigned char *calc_ecc) { - const struct nand_chip *chip = mtd->priv; + const struct nand_chip *chip = mtd_to_nand(mtd); struct nand_bch_control *nbc = chip->ecc.priv; unsigned int *errloc = nbc->errloc; int i, count; @@ -119,7 +119,7 @@ EXPORT_SYMBOL(nand_bch_correct_data); */ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd) { - struct nand_chip *nand = mtd->priv; + struct nand_chip *nand = mtd_to_nand(mtd); unsigned int m, t, eccsteps, i; struct nand_ecclayout *layout = nand->ecc.layout; struct nand_bch_control *nbc = NULL; diff --git a/drivers/mtd/nand/nand_denali.c b/drivers/mtd/nand/nand_denali.c index 2561966243..ddb03813fe 100644 --- a/drivers/mtd/nand/nand_denali.c +++ b/drivers/mtd/nand/nand_denali.c @@ -76,7 +76,12 @@ static uint32_t denali_irq_mask = DENALI_IRQ_ALL; * this macro allows us to convert from an MTD structure to our own * device context (denali) structure. */ -#define mtd_to_denali(m) container_of(m, struct denali_nand_info, mtd) +static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd) +{ + struct nand_chip *nand = mtd_to_nand(mtd); + + return container_of(nand, struct denali_nand_info, nand); +} /* * These constants are defined by the driver to enable common driver @@ -929,7 +934,7 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, err_device; /* correct the ECC error */ buf[offset] ^= err_correction_value; - denali->mtd.ecc_stats.corrected++; + denali->nand.mtd.ecc_stats.corrected++; bitflips++; } } else { @@ -997,7 +1002,7 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, { struct denali_nand_info *denali = mtd_to_denali(mtd); dma_addr_t addr = (unsigned long)denali->buf.buf; - size_t size = denali->mtd.writesize + denali->mtd.oobsize; + size_t size = mtd->writesize + mtd->oobsize; uint32_t irq_status; uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP | INTR_STATUS__PROGRAM_FAIL; @@ -1094,7 +1099,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, struct denali_nand_info *denali = mtd_to_denali(mtd); dma_addr_t addr = (unsigned long)denali->buf.buf; - size_t size = denali->mtd.writesize + denali->mtd.oobsize; + size_t size = mtd->writesize + mtd->oobsize; uint32_t irq_status; uint32_t irq_mask = denali->have_hw_ecc_fixup ? @@ -1132,19 +1137,19 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, /* When we have hw ecc fixup, don't check oob. * That code below looks jacked up anyway. I mean, * look at it, wtf? */ - if (!is_erased(buf, denali->mtd.writesize)) - denali->mtd.ecc_stats.failed++; + if (!is_erased(buf, mtd->writesize)) + mtd->ecc_stats.failed++; } else { - read_oob_data(&denali->mtd, chip->oob_poi, + read_oob_data(&denali->nand.mtd, chip->oob_poi, denali->page); /* check ECC failures that may have occurred on * erased pages */ if (check_erased_page) { - if (!is_erased(buf, denali->mtd.writesize)) - denali->mtd.ecc_stats.failed++; - if (!is_erased(buf, denali->mtd.oobsize)) - denali->mtd.ecc_stats.failed++; + if (!is_erased(buf, mtd->writesize)) + mtd->ecc_stats.failed++; + if (!is_erased(buf, mtd->oobsize)) + mtd->ecc_stats.failed++; } } } @@ -1156,7 +1161,7 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, { struct denali_nand_info *denali = mtd_to_denali(mtd); dma_addr_t addr = (unsigned long)denali->buf.buf; - size_t size = denali->mtd.writesize + denali->mtd.oobsize; + size_t size = mtd->writesize + mtd->oobsize; uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP; if (page != denali->page) { @@ -1372,6 +1377,8 @@ static void denali_drv_init(struct denali_nand_info *denali) int denali_init(struct denali_nand_info *denali) { + struct nand_chip *nand = &denali->nand; + struct mtd_info *mtd = &nand->mtd; int ret = 0; uint32_t val; @@ -1391,34 +1398,33 @@ int denali_init(struct denali_nand_info *denali) if (!denali->buf.buf) return -ENOMEM; - denali->mtd.parent = denali->dev; + mtd->parent = denali->dev; denali_hw_init(denali); denali_drv_init(denali); denali_set_intr_modes(denali, true); - denali->mtd.name = "denali-nand"; - denali->mtd.priv = &denali->nand; + mtd->name = "denali-nand"; /* register the driver with the NAND core subsystem */ - denali->nand.read_buf = denali_read_buf; - denali->nand.select_chip = denali_select_chip; - denali->nand.cmdfunc = denali_cmdfunc; - denali->nand.read_byte = denali_read_byte; - denali->nand.waitfunc = denali_waitfunc; + nand->read_buf = denali_read_buf; + nand->select_chip = denali_select_chip; + nand->cmdfunc = denali_cmdfunc; + nand->read_byte = denali_read_byte; + nand->waitfunc = denali_waitfunc; /* * scan for NAND devices attached to the controller * this is the first stage in a two step process to register * with the nand subsystem */ - if (nand_scan_ident(&denali->mtd, denali->max_banks, NULL)) { + if (nand_scan_ident(mtd, denali->max_banks, NULL)) { ret = -ENXIO; goto failed_req_irq; } /* allocate the right size buffer now */ kfree(denali->buf.buf); - denali->buf.buf = kzalloc(denali->mtd.writesize + denali->mtd.oobsize, + denali->buf.buf = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); if (!denali->buf.buf) { ret = -ENOMEM; @@ -1431,17 +1437,16 @@ int denali_init(struct denali_nand_info *denali) * the real pagesize and anything necessery */ denali->devnum = ioread32(denali->flash_reg + DEVICES_CONNECTED); - denali->nand.chipsize <<= (denali->devnum - 1); - denali->nand.page_shift += (denali->devnum - 1); - denali->nand.pagemask = (denali->nand.chipsize >> - denali->nand.page_shift) - 1; - denali->nand.bbt_erase_shift += (denali->devnum - 1); - denali->nand.phys_erase_shift = denali->nand.bbt_erase_shift; - denali->nand.chip_shift += (denali->devnum - 1); - denali->mtd.writesize <<= (denali->devnum - 1); - denali->mtd.oobsize <<= (denali->devnum - 1); - denali->mtd.erasesize <<= (denali->devnum - 1); - denali->mtd.size = denali->nand.numchips * denali->nand.chipsize; + nand->chipsize <<= (denali->devnum - 1); + nand->page_shift += (denali->devnum - 1); + nand->pagemask = (nand->chipsize >> nand->page_shift) - 1; + nand->bbt_erase_shift += (denali->devnum - 1); + nand->phys_erase_shift = nand->bbt_erase_shift; + nand->chip_shift += (denali->devnum - 1); + mtd->writesize <<= (denali->devnum - 1); + mtd->oobsize <<= (denali->devnum - 1); + mtd->erasesize <<= (denali->devnum - 1); + mtd->size = nand->numchips * nand->chipsize; denali->bbtskipbytes *= denali->devnum; /* @@ -1453,19 +1458,19 @@ int denali_init(struct denali_nand_info *denali) /* Bad block table description is set by nand framework, see nand_bbt.c */ - denali->nand.bbt_options |= NAND_BBT_USE_FLASH; - denali->nand.ecc.mode = NAND_ECC_HW_SYNDROME; + nand->bbt_options |= NAND_BBT_USE_FLASH; + nand->ecc.mode = NAND_ECC_HW_SYNDROME; if (denali->have_hw_ecc_fixup) { /* We have OOB support, so allow scan of BBT and leave the OOB alone */ - denali->nand.bbt_options |= NAND_BBT_NO_OOB; + nand->bbt_options |= NAND_BBT_NO_OOB; } else { /* skip the scan for now until we have OOB read and write support */ - denali->nand.options |= NAND_SKIP_BBTSCAN; + nand->options |= NAND_SKIP_BBTSCAN; } /* no subpage writes on denali */ - denali->nand.options |= NAND_NO_SUBPAGE_WRITE; + nand->options |= NAND_NO_SUBPAGE_WRITE; /* * Denali Controller only support 15bit and 8bit ECC in MRST, @@ -1473,34 +1478,34 @@ int denali_init(struct denali_nand_info *denali) * SLC if possible. * */ if (!nand_is_slc(&denali->nand) && - (denali->mtd.oobsize > (denali->bbtskipbytes + - ECC_15BITS * (denali->mtd.writesize / + (mtd->oobsize > (denali->bbtskipbytes + + ECC_15BITS * (mtd->writesize / ECC_SECTOR_SIZE)))) { /* if MLC OOB size is large enough, use 15bit ECC*/ - denali->nand.ecc.strength = 15; - denali->nand.ecc.layout = &nand_15bit_oob; - denali->nand.ecc.bytes = ECC_15BITS; + nand->ecc.strength = 15; + nand->ecc.layout = &nand_15bit_oob; + nand->ecc.bytes = ECC_15BITS; iowrite32(15, denali->flash_reg + ECC_CORRECTION); - } else if (denali->mtd.oobsize < (denali->bbtskipbytes + - ECC_8BITS * (denali->mtd.writesize / + } else if (mtd->oobsize < (denali->bbtskipbytes + + ECC_8BITS * (mtd->writesize / ECC_SECTOR_SIZE))) { pr_err("Your NAND chip OOB is not large enough to contain 8bit ECC correction codes"); goto failed_req_irq; } else { - denali->nand.ecc.strength = 8; - denali->nand.ecc.layout = &nand_8bit_oob; - denali->nand.ecc.bytes = ECC_8BITS; + nand->ecc.strength = 8; + nand->ecc.layout = &nand_8bit_oob; + nand->ecc.bytes = ECC_8BITS; iowrite32(8, denali->flash_reg + ECC_CORRECTION); } - denali->nand.ecc.bytes *= denali->devnum; - denali->nand.ecc.strength *= denali->devnum; - denali->nand.ecc.layout->eccbytes *= - denali->mtd.writesize / ECC_SECTOR_SIZE; - denali->nand.ecc.layout->oobfree[0].offset = - denali->bbtskipbytes + denali->nand.ecc.layout->eccbytes; - denali->nand.ecc.layout->oobfree[0].length = - denali->mtd.oobsize - denali->nand.ecc.layout->eccbytes - + nand->ecc.bytes *= denali->devnum; + nand->ecc.strength *= denali->devnum; + nand->ecc.layout->eccbytes *= + mtd->writesize / ECC_SECTOR_SIZE; + nand->ecc.layout->oobfree[0].offset = + denali->bbtskipbytes + nand->ecc.layout->eccbytes; + nand->ecc.layout->oobfree[0].length = + mtd->oobsize - nand->ecc.layout->eccbytes - denali->bbtskipbytes; /* @@ -1508,17 +1513,17 @@ int denali_init(struct denali_nand_info *denali) * contained by each nand chip. blksperchip will help driver to * know how many blocks is taken by FW. */ - denali->totalblks = denali->mtd.size >> denali->nand.phys_erase_shift; - denali->blksperchip = denali->totalblks / denali->nand.numchips; + denali->totalblks = mtd->size >> nand->phys_erase_shift; + denali->blksperchip = denali->totalblks / nand->numchips; /* override the default read operations */ - denali->nand.ecc.size = ECC_SECTOR_SIZE * denali->devnum; - denali->nand.ecc.read_page = denali_read_page; - denali->nand.ecc.read_page_raw = denali_read_page_raw; - denali->nand.ecc.write_page = denali_write_page; - denali->nand.ecc.write_page_raw = denali_write_page_raw; - denali->nand.ecc.read_oob = denali_read_oob; - denali->nand.ecc.write_oob = denali_write_oob; + nand->ecc.size = ECC_SECTOR_SIZE * denali->devnum; + nand->ecc.read_page = denali_read_page; + nand->ecc.read_page_raw = denali_read_page_raw; + nand->ecc.write_page = denali_write_page; + nand->ecc.write_page_raw = denali_write_page_raw; + nand->ecc.read_oob = denali_read_oob; + nand->ecc.write_oob = denali_write_oob; /* Occasionally the controller is in SPARE or MAIN+SPARE mode upon startup, and we want it to be MAIN only */ @@ -1534,12 +1539,12 @@ int denali_init(struct denali_nand_info *denali) MAIN_ACCESS); } - if (nand_scan_tail(&denali->mtd)) { + if (nand_scan_tail(mtd)) { ret = -ENXIO; goto failed_req_irq; } - return add_mtd_nand_device(&denali->mtd, "nand"); + return add_mtd_nand_device(mtd, "nand"); failed_req_irq: denali_irq_cleanup(denali->irq, denali); diff --git a/drivers/mtd/nand/nand_imx.c b/drivers/mtd/nand/nand_imx.c index e0d840b14e..1a065cb46f 100644 --- a/drivers/mtd/nand/nand_imx.c +++ b/drivers/mtd/nand/nand_imx.c @@ -32,7 +32,6 @@ #include <errno.h> struct imx_nand_host { - struct mtd_info mtd; struct nand_chip nand; struct mtd_partition *parts; struct device_d *dev; @@ -478,7 +477,7 @@ static void imx_nand_enable_hwecc_v3(struct nand_chip *chip, bool enable) static int imx_nand_correct_data_v1(struct mtd_info *mtd) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); struct imx_nand_host *host = nand_chip->priv; if (host->eccstatus_v1 < 0) @@ -494,7 +493,7 @@ static int imx_nand_correct_data_v1(struct mtd_info *mtd) static int imx_nand_correct_data_v2_v3(struct mtd_info *mtd) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); struct imx_nand_host *host = nand_chip->priv; u32 ecc_stat, err; int no_subpages; @@ -537,7 +536,7 @@ static int imx_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, */ static u_char imx_nand_read_byte(struct mtd_info *mtd) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); struct imx_nand_host *host = nand_chip->priv; u_char ret; @@ -568,7 +567,7 @@ static u_char imx_nand_read_byte(struct mtd_info *mtd) */ static u16 imx_nand_read_word(struct mtd_info *mtd) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); struct imx_nand_host *host = nand_chip->priv; uint16_t ret; @@ -590,7 +589,7 @@ static u16 imx_nand_read_word(struct mtd_info *mtd) static void imx_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); struct imx_nand_host *host = nand_chip->priv; u16 col = host->buf_start; int n = mtd->oobsize + mtd->writesize - col; @@ -613,7 +612,7 @@ static void imx_nand_write_buf(struct mtd_info *mtd, */ static void imx_nand_read_buf(struct mtd_info *mtd, u_char * buf, int len) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); struct imx_nand_host *host = nand_chip->priv; u16 col = host->buf_start; int n = mtd->oobsize + mtd->writesize - col; @@ -634,7 +633,7 @@ static void imx_nand_read_buf(struct mtd_info *mtd, u_char * buf, int len) */ static void copy_spare(struct mtd_info *mtd, int bfrom, void *buf) { - struct nand_chip *this = mtd->priv; + struct nand_chip *this = mtd_to_nand(mtd); struct imx_nand_host *host = this->priv; u16 i, j; u16 n = mtd->writesize >> 9; @@ -672,7 +671,7 @@ static void imx_nand_select_chip(struct mtd_info *mtd, int chip) static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); struct imx_nand_host *host = nand_chip->priv; /* @@ -738,7 +737,7 @@ static int get_eccsize(struct mtd_info *mtd) static void preset_v1(struct mtd_info *mtd) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); struct imx_nand_host *host = nand_chip->priv; uint16_t config1 = 0; @@ -760,7 +759,7 @@ static void preset_v1(struct mtd_info *mtd) static void preset_v2(struct mtd_info *mtd) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); struct imx_nand_host *host = nand_chip->priv; uint16_t config1 = 0; int mode; @@ -820,7 +819,7 @@ static void preset_v2(struct mtd_info *mtd) static void preset_v3(struct mtd_info *mtd) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); struct imx_nand_host *host = chip->priv; uint32_t config2, config3; int i, addr_phases; @@ -962,7 +961,7 @@ static int imx_nand_read_page_raw(struct mtd_info *mtd, static void imx_nand_command(struct mtd_info *mtd, unsigned command, int column, int page_addr) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); struct imx_nand_host *host = nand_chip->priv; dev_dbg(host->dev, @@ -1237,8 +1236,7 @@ static int __init imxnd_probe(struct device_d *dev) /* structures must be linked */ this = &host->nand; - mtd = &host->mtd; - mtd->priv = this; + mtd = &this->mtd; mtd->parent = dev; mtd->name = "imx_nand"; diff --git a/drivers/mtd/nand/nand_imx_bbm.c b/drivers/mtd/nand/nand_imx_bbm.c index 23722a9064..c005482b06 100644 --- a/drivers/mtd/nand/nand_imx_bbm.c +++ b/drivers/mtd/nand/nand_imx_bbm.c @@ -77,7 +77,7 @@ static int checkbad(struct mtd_info *mtd, loff_t ofs) static void *create_bbt(struct mtd_info *mtd) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); int len, i, numblocks, ret; loff_t from = 0; uint8_t *bbt; @@ -122,7 +122,7 @@ out: static int attach_bbt(struct mtd_info *mtd, void *bbt) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); chip->bbt_td->options |= NAND_BBT_WRITE | NAND_BBT_CREATE; chip->bbt_md->options |= NAND_BBT_WRITE | NAND_BBT_CREATE; diff --git a/drivers/mtd/nand/nand_mrvl_nfc.c b/drivers/mtd/nand/nand_mrvl_nfc.c index f48403da70..15d052b5a4 100644 --- a/drivers/mtd/nand/nand_mrvl_nfc.c +++ b/drivers/mtd/nand/nand_mrvl_nfc.c @@ -137,7 +137,6 @@ struct mrvl_nand_variant { }; struct mrvl_nand_host { - struct mtd_info mtd; struct nand_chip chip; struct mtd_partition *parts; struct device_d *dev; @@ -342,7 +341,7 @@ static struct mrvl_nand_timing timings[] = { static void mrvl_nand_set_timing(struct mrvl_nand_host *host, bool use_default) { - struct mtd_info *mtd = &host->mtd; + struct mtd_info *mtd = &host->chip.mtd; unsigned long nand_clk = clk_get_rate(host->core_clk); struct mrvl_nand_timing *t; uint32_t ndtr0, ndtr1; @@ -420,7 +419,7 @@ static unsigned int mrvl_datasize(struct mrvl_nand_host *host) { unsigned int datasize; - datasize = host->mtd.writesize; + datasize = host->chip.mtd.writesize; if (host->use_spare) { datasize += host->spare_size; if (!host->use_ecc) @@ -572,7 +571,7 @@ static void prepare_start_command(struct mrvl_nand_host *host, int command) if (command == NAND_CMD_READ0 || command == NAND_CMD_READOOB || command == NAND_CMD_SEQIN) { - host->buf_count = host->mtd.writesize + host->mtd.oobsize; + host->buf_count = host->chip.mtd.writesize + host->chip.mtd.oobsize; memset(host->data_buff, 0xFF, host->buf_count); } @@ -592,7 +591,7 @@ static int prepare_set_command(struct mrvl_nand_host *host, int command, int addr_cycle, exec_cmd; struct mtd_info *mtd; - mtd = &host->mtd; + mtd = &host->chip.mtd; exec_cmd = 1; if (host->cs != 0) @@ -878,7 +877,7 @@ static void mrvl_nand_write_buf(struct mtd_info *mtd, static void mrvl_nand_config_flash(struct mrvl_nand_host *host) { struct nand_chip *chip = &host->chip; - struct mtd_info *mtd = &host->mtd; + struct mtd_info *mtd = &host->chip.mtd; uint32_t ndcr = host->reg_ndcr; /* calculate flash information */ @@ -1036,7 +1035,7 @@ static int pxa_ecc_init(struct mrvl_nand_host *host, static int mrvl_nand_scan(struct mtd_info *mtd) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); struct mrvl_nand_host *host = chip->priv; int ret; unsigned int ndcr; @@ -1115,8 +1114,7 @@ static struct mrvl_nand_host *alloc_nand_resource(struct device_d *dev) host = xzalloc(sizeof(*host)); host->num_cs = 1; host->cs = 0; - mtd = &host->mtd; - mtd->priv = &host->chip; + mtd = &host->chip.mtd; mtd->parent = dev; mtd->name = "mrvl_nand"; @@ -1216,14 +1214,14 @@ static int mrvl_nand_probe(struct device_d *dev) return ret; host->chip.controller = &host->chip.hwcontrol; - ret = mrvl_nand_scan(&host->mtd); + ret = mrvl_nand_scan(&host->chip.mtd); if (ret) { dev_warn(dev, "failed to scan nand at cs %d\n", host->cs); return -ENODEV; } - ret = add_mtd_nand_device(&host->mtd, "nand"); + ret = add_mtd_nand_device(&host->chip.mtd, "nand"); return ret; } diff --git a/drivers/mtd/nand/nand_mxs.c b/drivers/mtd/nand/nand_mxs.c index b016c5bff0..36b6e7ac22 100644 --- a/drivers/mtd/nand/nand_mxs.c +++ b/drivers/mtd/nand/nand_mxs.c @@ -200,7 +200,6 @@ struct mxs_nand_info { void __iomem *io_base; void __iomem *bch_base; struct clk *clk; - struct mtd_info mtd; enum gpmi_type type; int dma_channel_base; u32 version; @@ -284,7 +283,7 @@ static uint32_t mxs_nand_aux_status_offset(void) static uint32_t mxs_nand_get_mark_offset(struct mtd_info *mtd) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); uint32_t chunk_data_size_in_bits; uint32_t chunk_ecc_size_in_bits; uint32_t chunk_total_size_in_bits; @@ -333,7 +332,7 @@ static uint32_t mxs_nand_get_mark_offset(struct mtd_info *mtd) static int mxs_nand_calc_geo(struct mtd_info *mtd) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); struct mxs_nand_info *nand_info = chip->priv; int ecc_chunk_count = mxs_nand_ecc_chunk_cnt(mtd->writesize); int gf_len = 13; /* length of Galois Field for non-DDR nand */ @@ -380,7 +379,7 @@ int mxs_nand_get_geo(int *ecc_strength, int *bb_mark_bit_offset) if (!mxs_nand_mtd) return -ENODEV; - chip = mxs_nand_mtd->priv; + chip = mtd_to_nand(mxs_nand_mtd); nand_info = chip->priv; *ecc_strength = chip->ecc.strength; @@ -423,7 +422,7 @@ static int mxs_nand_wait_for_bch_complete(struct mxs_nand_info *nand_info) */ static void mxs_nand_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); struct mxs_nand_info *nand_info = chip->priv; struct mxs_dma_desc *d; uint32_t channel = nand_info->dma_channel_base + nand_info->cur_chip; @@ -499,7 +498,7 @@ static void mxs_nand_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl) */ static int mxs_nand_device_ready(struct mtd_info *mtd) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); struct mxs_nand_info *nand_info = chip->priv; void __iomem *gpmi_regs = nand_info->io_base; uint32_t tmp; @@ -525,7 +524,7 @@ static int mxs_nand_device_ready(struct mtd_info *mtd) */ static void mxs_nand_select_chip(struct mtd_info *mtd, int chipnum) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); struct mxs_nand_info *nand_info = chip->priv; nand_info->cur_chip = chipnum; @@ -541,7 +540,7 @@ static void mxs_nand_select_chip(struct mtd_info *mtd, int chipnum) static void mxs_nand_swap_block_mark(struct mtd_info *mtd, uint8_t *data_buf, uint8_t *oob_buf) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); struct mxs_nand_info *nand_info = chip->priv; uint32_t bit_offset; @@ -582,7 +581,7 @@ static void mxs_nand_swap_block_mark(struct mtd_info *mtd, */ static void mxs_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int length) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); struct mxs_nand_info *nand_info = chip->priv; struct mxs_dma_desc *d; uint32_t channel = nand_info->dma_channel_base + nand_info->cur_chip; @@ -660,7 +659,7 @@ rtn: static void mxs_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int length) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); struct mxs_nand_info *nand_info = chip->priv; struct mxs_dma_desc *d; uint32_t channel = nand_info->dma_channel_base + nand_info->cur_chip; @@ -717,7 +716,7 @@ static uint8_t mxs_nand_read_byte(struct mtd_info *mtd) static void mxs_nand_config_bch(struct mtd_info *mtd, int readlen) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); struct mxs_nand_info *nand_info = chip->priv; int chunk_size; void __iomem *bch_regs = nand_info->bch_base; @@ -1031,7 +1030,7 @@ rtn: static int mxs_nand_hook_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); struct mxs_nand_info *nand_info = chip->priv; int ret; @@ -1056,7 +1055,7 @@ static int mxs_nand_hook_read_oob(struct mtd_info *mtd, loff_t from, static int mxs_nand_hook_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); struct mxs_nand_info *nand_info = chip->priv; int ret; @@ -1080,7 +1079,7 @@ static int mxs_nand_hook_write_oob(struct mtd_info *mtd, loff_t to, */ static int mxs_nand_hook_block_markbad(struct mtd_info *mtd, loff_t ofs) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); struct mxs_nand_info *nand_info = chip->priv; int ret; @@ -1242,7 +1241,7 @@ static int mxs_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) */ static int mxs_nand_scan_bbt(struct mtd_info *mtd) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); struct mxs_nand_info *nand_info = chip->priv; void __iomem *bch_regs = nand_info->bch_base; int ret; @@ -2030,7 +2029,7 @@ static void mxs_nand_compute_edo_timing(struct mxs_nand_info *info, static int mxs_nand_enable_edo_mode(struct mxs_nand_info *info) { struct nand_chip *chip = &info->nand_chip; - struct mtd_info *mtd = &info->mtd; + struct mtd_info *mtd = &chip->mtd; uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {}; int ret, mode; @@ -2196,8 +2195,7 @@ static int mxs_nand_probe(struct device_d *dev) /* structures must be linked */ chip = &nand_info->nand_chip; - mtd = &nand_info->mtd; - mtd->priv = chip; + mtd = &nand_info->nand_chip.mtd; mtd->parent = dev; chip->priv = nand_info; diff --git a/drivers/mtd/nand/nand_omap_gpmc.c b/drivers/mtd/nand/nand_omap_gpmc.c index 2dcf7e723b..c4d0cdfb57 100644 --- a/drivers/mtd/nand/nand_omap_gpmc.c +++ b/drivers/mtd/nand/nand_omap_gpmc.c @@ -70,6 +70,7 @@ #include <io.h> #include <mach/gpmc.h> #include <mach/gpmc_nand.h> +#include <platform_data/elm.h> #include "nand_omap_bch_decoder.h" @@ -91,6 +92,10 @@ static const uint8_t bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc, 0xac, 0x6b, 0xff, 0x99, 0x7b}; +static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55, + 0x2e, 0x2c, 0x86, 0xa3, 0xed, 0x36, 0x1b, 0x78, + 0x48, 0x76, 0xa9, 0x3b, 0x97, 0xd1, 0x7a, 0x93, + 0x07, 0x0e}; static const char *ecc_mode_strings[] = { "software", @@ -139,7 +144,7 @@ static struct nand_bbt_descr bb_descrip_flashbased = { */ static int omap_dev_ready(struct mtd_info *mtd) { - struct nand_chip *nand = (struct nand_chip *)(mtd->priv); + struct nand_chip *nand = mtd_to_nand(mtd); struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv); if (readl(oinfo->gpmc_base + GPMC_STATUS) & oinfo->wait_mon_mask) @@ -185,7 +190,7 @@ static void gpmc_nand_wp(struct gpmc_nand_info *oinfo, int mode) */ static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) { - struct nand_chip *nand = (struct nand_chip *)(mtd->priv); + struct nand_chip *nand = mtd_to_nand(mtd); struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv); switch (ctrl) { @@ -230,9 +235,9 @@ static unsigned int gen_true_ecc(u8 *ecc_buf) static int __omap_calculate_ecc(struct mtd_info *mtd, uint8_t *ecc_code, int sblock) { - struct nand_chip *nand = (struct nand_chip *)(mtd->priv); + struct nand_chip *nand = mtd_to_nand(mtd); struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv); - unsigned int reg; + unsigned int reg, reg1, val; unsigned int val1 = 0x0, val2 = 0x0; unsigned int val3 = 0x0, val4 = 0x0; int ecc_size = 8; @@ -274,6 +279,45 @@ static int __omap_calculate_ecc(struct mtd_info *mtd, uint8_t *ecc_code, /* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */ *ecc_code++ = ((val1 >> 8) & 0x0f) | ((val1 >> 20) & 0xf0); break; + + case OMAP_ECC_BCH16_CODE_HW: + reg = GPMC_ECC_BCH_RESULT_0 + (0x10 * sblock); + reg1 = 0x300 + (0x10 * sblock); + + val = readl(oinfo->gpmc_base + reg1 + 0x8); + ecc_code[0] = ((val >> 8) & 0xFF); + ecc_code[1] = ((val >> 0) & 0xFF); + val = readl(oinfo->gpmc_base + reg1 + 0x4); + ecc_code[2] = ((val >> 24) & 0xFF); + ecc_code[3] = ((val >> 16) & 0xFF); + ecc_code[4] = ((val >> 8) & 0xFF); + ecc_code[5] = ((val >> 0) & 0xFF); + val = readl(oinfo->gpmc_base + reg1 + 0x0); + ecc_code[6] = ((val >> 24) & 0xFF); + ecc_code[7] = ((val >> 16) & 0xFF); + ecc_code[8] = ((val >> 8) & 0xFF); + ecc_code[9] = ((val >> 0) & 0xFF); + val = readl(oinfo->gpmc_base + reg + 0xc); + ecc_code[10] = ((val >> 24) & 0xFF); + ecc_code[11] = ((val >> 16) & 0xFF); + ecc_code[12] = ((val >> 8) & 0xFF); + ecc_code[13] = ((val >> 0) & 0xFF); + val = readl(oinfo->gpmc_base + reg + 0x8); + ecc_code[14] = ((val >> 24) & 0xFF); + ecc_code[15] = ((val >> 16) & 0xFF); + ecc_code[16] = ((val >> 8) & 0xFF); + ecc_code[17] = ((val >> 0) & 0xFF); + val = readl(oinfo->gpmc_base + reg + 0x4); + ecc_code[18] = ((val >> 24) & 0xFF); + ecc_code[19] = ((val >> 16) & 0xFF); + ecc_code[20] = ((val >> 8) & 0xFF); + ecc_code[21] = ((val >> 0) & 0xFF); + val = readl(oinfo->gpmc_base + reg + 0x0); + ecc_code[22] = ((val >> 24) & 0xFF); + ecc_code[23] = ((val >> 16) & 0xFF); + ecc_code[24] = ((val >> 8) & 0xFF); + ecc_code[25] = ((val >> 0) & 0xFF); + break; default: return -EINVAL; } @@ -290,11 +334,11 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat, static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc) { - struct nand_chip *nand = (struct nand_chip *)(mtd->priv); + struct nand_chip *nand = mtd_to_nand(mtd); struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv); int j, actual_eccsize; const uint8_t *erased_ecc_vec; - unsigned int err_loc[8]; + unsigned int err_loc[16]; int bch_max_err; int bitflip_count = 0; bool eccflag = 0; @@ -311,6 +355,11 @@ static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat, erased_ecc_vec = bch8_vector; bch_max_err = BCH8_MAX_ERROR; break; + case OMAP_ECC_BCH16_CODE_HW: + actual_eccsize = eccsize; + erased_ecc_vec = bch16_vector; + bch_max_err = 16; + break; default: dev_err(oinfo->pdev, "invalid driver configuration\n"); return -EINVAL; @@ -362,7 +411,7 @@ static int omap_correct_hamming(struct mtd_info *mtd, uint8_t *dat, unsigned int orig_ecc, new_ecc, res, hm; unsigned short parity_bits, byte; unsigned char bit; - struct nand_chip *nand = (struct nand_chip *)(mtd->priv); + struct nand_chip *nand = mtd_to_nand(mtd); struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv); if (read_ecc[0] == 0xff && read_ecc[1] == 0xff && @@ -416,7 +465,7 @@ static int omap_correct_hamming(struct mtd_info *mtd, uint8_t *dat, static int omap_correct_data(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc) { - struct nand_chip *nand = (struct nand_chip *)(mtd->priv); + struct nand_chip *nand = mtd_to_nand(mtd); struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv); if (oinfo->ecc_mode != OMAP_ECC_HAMMING_CODE_HW_ROMCODE) @@ -429,7 +478,7 @@ static int omap_correct_data(struct mtd_info *mtd, uint8_t *dat, static void omap_enable_hwecc(struct mtd_info *mtd, int mode) { - struct nand_chip *nand = (struct nand_chip *)(mtd->priv); + struct nand_chip *nand = mtd_to_nand(mtd); struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv); unsigned int bch_mod = 0, bch_wrapmode = 0, eccsize1 = 0, eccsize0 = 0; unsigned int ecc_conf_val = 0, ecc_size_conf_val = 0; @@ -441,13 +490,27 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode) case OMAP_ECC_BCH8_CODE_HW: case OMAP_ECC_BCH8_CODE_HW_ROMCODE: if (mode == NAND_ECC_READ) { - eccsize1 = 0x1A; eccsize0 = 0x18; + eccsize0 = 24; + eccsize1 = 26; bch_mod = 1; - bch_wrapmode = 0x04; + bch_wrapmode = 4; } else { - eccsize1 = 0x20; eccsize0 = 0x00; + eccsize0 = 0; + eccsize1 = 32; bch_mod = 1; - bch_wrapmode = 0x06; + bch_wrapmode = 6; + } + break; + case OMAP_ECC_BCH16_CODE_HW: + bch_mod = 2; + if (mode == NAND_ECC_READ) { + bch_wrapmode = 4; + eccsize0 = 4; /* ECC bits in nibbles per sector */ + eccsize1 = 52; /* non-ECC bits in nibbles per sector */ + } else { + bch_wrapmode = 4; + eccsize0 = 4; /* extra bits in nibbles per sector */ + eccsize1 = 52; /* OOB bits in nibbles per sector */ } break; case OMAP_ECC_HAMMING_CODE_HW_ROMCODE: @@ -483,7 +546,7 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode) GPMC_ECC_CONFIG_ECCBCHTSEL(bch_mod) | GPMC_ECC_CONFIG_ECCWRAPMODE(bch_wrapmode) | dev_width | - GPMC_ECC_CONFIG_ECCTOPSECTOR(3) | + GPMC_ECC_CONFIG_ECCTOPSECTOR(nand->ecc.steps - 1) | GPMC_ECC_CONFIG_ECCCS(cs) | GPMC_ECC_CONFIG_ECCENABLE); } @@ -689,6 +752,234 @@ static int omap_gpmc_read_page_bch_rom_mode(struct mtd_info *mtd, return max_bitflips; } +/** + * erased_sector_bitflips - count bit flips + * @data: data sector buffer + * @oob: oob buffer + * oinfo: gpmc_nand_info + * + * Check the bit flips in erased page falls below correctable level. + * If falls below, report the page as erased with correctable bit + * flip, else report as uncorrectable page. + */ +static int erased_sector_bitflips(u_char *data, u_char *oob, + struct gpmc_nand_info *oinfo) +{ + int flip_bits = 0, i; + + for (i = 0; i < oinfo->nand.ecc.size; i++) { + flip_bits += hweight8(~data[i]); + if (flip_bits > oinfo->nand.ecc.strength) + return 0; + } + + for (i = 0; i < oinfo->nand.ecc.bytes - 1; i++) { + flip_bits += hweight8(~oob[i]); + if (flip_bits > oinfo->nand.ecc.strength) + return 0; + } + + /* + * Bit flips falls in correctable level. + * Fill data area with 0xFF + */ + if (flip_bits) { + memset(data, 0xFF, oinfo->nand.ecc.size); + memset(oob, 0xFF, oinfo->nand.ecc.bytes); + } + + return flip_bits; +} + +/** + * omap_elm_correct_data - corrects page data area in case error reported + * @chip: NAND chip object + * @data: page data + * @read_ecc: ecc read from nand flash + * @calc_ecc: ecc read from HW ECC registers + * + * Calculated ecc vector reported as zero in case of non-error pages. + * In case of non-zero ecc vector, first filter out erased-pages, and + * then process data via ELM to detect bit-flips. + */ +static int omap_elm_correct_data(struct nand_chip *chip, u_char *data, + u_char *read_ecc, u_char *calc_ecc) +{ + struct gpmc_nand_info *oinfo = chip->priv; + struct nand_ecc_ctrl *ecc = &oinfo->nand.ecc; + int eccsteps = oinfo->nand.ecc.steps; + int i , j, stat = 0; + int eccflag, actual_eccbytes; + struct elm_errorvec err_vec[ERROR_VECTOR_MAX]; + u_char *ecc_vec = calc_ecc; + u_char *spare_ecc = read_ecc; + const u_char *erased_ecc_vec; + u_char *buf; + int bitflip_count; + bool is_error_reported = false; + u32 bit_pos, byte_pos, error_max, pos; + int err; + + switch (oinfo->ecc_mode) { + case OMAP_ECC_BCH8_CODE_HW: + /* omit 14th ECC byte reserved for ROM code compatibility */ + actual_eccbytes = ecc->bytes - 1; + erased_ecc_vec = bch8_vector; + break; + case OMAP_ECC_BCH16_CODE_HW: + actual_eccbytes = ecc->bytes; + erased_ecc_vec = bch16_vector; + break; + default: + dev_err(oinfo->pdev, "invalid driver configuration\n"); + return -EINVAL; + } + + /* Initialize elm error vector to zero */ + memset(err_vec, 0, sizeof(err_vec)); + + for (i = 0; i < eccsteps ; i++) { + eccflag = 0; /* initialize eccflag */ + + /* + * Check any error reported, + * In case of error, non zero ecc reported. + */ + for (j = 0; j < actual_eccbytes; j++) { + if (calc_ecc[j] != 0) { + eccflag = 1; /* non zero ecc, error present */ + break; + } + } + + if (eccflag == 1) { + if (memcmp(calc_ecc, erased_ecc_vec, + actual_eccbytes) == 0) { + /* + * calc_ecc[] matches pattern for ECC(all 0xff) + * so this is definitely an erased-page + */ + } else { + buf = &data[oinfo->nand.ecc.size * i]; + /* + * count number of 0-bits in read_buf. + * This check can be removed once a similar + * check is introduced in generic NAND driver + */ + bitflip_count = erased_sector_bitflips( + buf, read_ecc, oinfo); + if (bitflip_count) { + /* + * number of 0-bits within ECC limits + * So this may be an erased-page + */ + stat += bitflip_count; + } else { + /* + * Too many 0-bits. It may be a + * - programmed-page, OR + * - erased-page with many bit-flips + * So this page requires check by ELM + */ + err_vec[i].error_reported = true; + is_error_reported = true; + } + } + } + + /* Update the ecc vector */ + calc_ecc += ecc->bytes; + read_ecc += ecc->bytes; + } + + /* Check if any error reported */ + if (!is_error_reported) + return stat; + + /* Decode BCH error using ELM module */ + elm_decode_bch_error_page(ecc_vec, err_vec); + + err = 0; + for (i = 0; i < eccsteps; i++) { + if (err_vec[i].error_uncorrectable) { + dev_err(oinfo->pdev, + "uncorrectable bit-flips found\n"); + err = -EBADMSG; + } else if (err_vec[i].error_reported) { + for (j = 0; j < err_vec[i].error_count; j++) { + switch (oinfo->ecc_mode) { + case OMAP_ECC_BCH8_CODE_HW: + case OMAP_ECC_BCH16_CODE_HW: + pos = err_vec[i].error_loc[j]; + break; + default: + return -EINVAL; + } + error_max = (ecc->size + actual_eccbytes) * 8; + /* Calculate bit position of error */ + bit_pos = pos % 8; + + /* Calculate byte position of error */ + byte_pos = (error_max - pos - 1) / 8; + + if (pos < error_max) { + if (byte_pos < 512) { + pr_debug("bitflip@dat[%d]=%x\n", + byte_pos, data[byte_pos]); + data[byte_pos] ^= 1 << bit_pos; + } else { + pr_debug("bitflip@oob[%d]=%x\n", + (byte_pos - 512), + spare_ecc[byte_pos - 512]); + spare_ecc[byte_pos - 512] ^= + 1 << bit_pos; + } + } else { + dev_err(oinfo->pdev, + "invalid bit-flip @ %d:%d\n", + byte_pos, bit_pos); + err = -EBADMSG; + } + } + } + + /* Update number of correctable errors */ + stat = max_t(unsigned int, stat, err_vec[i].error_count); + + /* Update page data with sector size */ + data += ecc->size; + spare_ecc += ecc->bytes; + } + + return (err) ? err : stat; +} + +static int gpmc_read_page_hwecc_elm(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) +{ + int i; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + uint8_t *ecc_calc = chip->buffers->ecccalc; + uint8_t *ecc_code = chip->buffers->ecccode; + uint32_t *eccpos = chip->ecc.layout->eccpos; + + chip->ecc.hwctl(mtd, NAND_ECC_READ); + chip->read_buf(mtd, buf, mtd->writesize); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + + for (i = 0; i < chip->ecc.total; i++) + ecc_code[i] = chip->oob_poi[eccpos[i]]; + + eccsteps = chip->ecc.steps; + + for (i = 0; eccsteps; eccsteps--, i++) + __omap_calculate_ecc(mtd, &ecc_calc[i * eccbytes], i); + + return omap_elm_correct_data(chip, buf, ecc_code, ecc_calc); +} + static int gpmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int oob_required, int page) @@ -732,7 +1023,7 @@ static int omap_gpmc_eccmode(struct gpmc_nand_info *oinfo, { struct mtd_info *minfo = &oinfo->minfo; struct nand_chip *nand = &oinfo->nand; - int offset; + int offset, err; int i, j; if (nand->options & NAND_BUSWIDTH_16) @@ -807,6 +1098,32 @@ static int omap_gpmc_eccmode(struct gpmc_nand_info *oinfo, for (i = 2; i < 58; i++) omap_oobinfo.eccpos[j++] = i; break; + case OMAP_ECC_BCH16_CODE_HW: + oinfo->nand.ecc.size = 512; + oinfo->nand.ecc.bytes = 26; + oinfo->nand.ecc.strength = 16; + oinfo->nand.ecc.steps = + minfo->writesize / oinfo->nand.ecc.size; + oinfo->nand.ecc.total = + oinfo->nand.ecc.steps * oinfo->nand.ecc.bytes; + omap_oobinfo.eccbytes = oinfo->nand.ecc.total; + + for (i = 0; i < oinfo->nand.ecc.total; i++) + omap_oobinfo.eccpos[i] = i + 2; + + /* reserved marker already included in ecclayout->eccbytes */ + omap_oobinfo.oobfree->offset = + omap_oobinfo.eccpos[oinfo->nand.ecc.total - 1] + 1; + + err = elm_config(BCH16_ECC, + oinfo->minfo.writesize / nand->ecc.size, + nand->ecc.size, nand->ecc.bytes); + if (err < 0) + return err; + + nand->ecc.read_page = gpmc_read_page_hwecc_elm; + + break; case OMAP_ECC_SOFT: nand->ecc.layout = NULL; nand->ecc.mode = NAND_ECC_SOFT; @@ -883,7 +1200,6 @@ static int gpmc_nand_probe(struct device_d *pdev) nand->priv = (void *)oinfo; minfo = &oinfo->minfo; - minfo->priv = (void *)nand; minfo->parent = pdev; if (pdata->cs >= GPMC_NUM_CS) { diff --git a/drivers/mtd/nand/nand_orion.c b/drivers/mtd/nand/nand_orion.c index 881ffeec05..c8b89cd03c 100644 --- a/drivers/mtd/nand/nand_orion.c +++ b/drivers/mtd/nand/nand_orion.c @@ -21,7 +21,6 @@ #include <linux/clk.h> struct orion_nand { - struct mtd_info mtd; struct nand_chip chip; u8 ale; /* address line number connected to ALE */ @@ -30,7 +29,7 @@ struct orion_nand { static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); struct orion_nand *priv = chip->priv; u32 offs; @@ -52,7 +51,7 @@ static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl static void orion_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); void __iomem *io_base = chip->IO_ADDR_R; uint64_t *buf64; int i = 0; @@ -91,7 +90,7 @@ static int orion_nand_probe(struct device_d *dev) u32 val = 0; priv = xzalloc(sizeof(struct orion_nand)); - mtd = &priv->mtd; + mtd = &priv->chip.mtd; chip = &priv->chip; iores = dev_request_mem_resource(dev, 0); @@ -118,7 +117,6 @@ static int orion_nand_probe(struct device_d *dev) chip->chip_delay = (u8)val; mtd->parent = dev; - mtd->priv = chip; chip->priv = priv; chip->IO_ADDR_R = chip->IO_ADDR_W = io_base; chip->cmd_ctrl = orion_nand_cmd_ctrl; diff --git a/drivers/mtd/nand/nand_s3c24xx.c b/drivers/mtd/nand/nand_s3c24xx.c index df22735488..9fbc0f90d3 100644 --- a/drivers/mtd/nand/nand_s3c24xx.c +++ b/drivers/mtd/nand/nand_s3c24xx.c @@ -88,7 +88,6 @@ struct s3c24x0_nand_host { - struct mtd_info mtd; struct nand_chip nand; struct mtd_partition *parts; struct device_d *dev; @@ -203,7 +202,7 @@ static void __nand_boot_init disable_nand_controller(void __iomem *host) */ static void s3c2440_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); struct s3c24x0_nand_host *host = nand_chip->priv; readsl(host->base + NFDATA, buf, len >> 2); @@ -228,7 +227,7 @@ static void s3c2440_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) static void s3c2440_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); struct s3c24x0_nand_host *host = nand_chip->priv; writesl(host->base + NFDATA, buf, len >> 2); @@ -316,7 +315,7 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, uint8_t *dat, static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); struct s3c24x0_nand_host *host = nand_chip->priv; #ifdef CONFIG_CPU_S3C2410 @@ -329,7 +328,7 @@ static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode) static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat, uint8_t *ecc_code) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); struct s3c24x0_nand_host *host = nand_chip->priv; #ifdef CONFIG_CPU_S3C2410 @@ -349,7 +348,7 @@ static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat, static void s3c24x0_nand_select_chip(struct mtd_info *mtd, int chip) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); struct s3c24x0_nand_host *host = nand_chip->priv; if (chip == -1) @@ -360,7 +359,7 @@ static void s3c24x0_nand_select_chip(struct mtd_info *mtd, int chip) static int s3c24x0_nand_devready(struct mtd_info *mtd) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); struct s3c24x0_nand_host *host = nand_chip->priv; return readw(host->base + NFSTAT) & NFSTAT_BUSY; @@ -369,7 +368,7 @@ static int s3c24x0_nand_devready(struct mtd_info *mtd) static void s3c24x0_nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); struct s3c24x0_nand_host *host = nand_chip->priv; if (cmd == NAND_CMD_NONE) @@ -428,8 +427,7 @@ static int s3c24x0_nand_probe(struct device_d *dev) /* structures must be linked */ chip = &host->nand; - mtd = &host->mtd; - mtd->priv = chip; + mtd = &chip->mtd; mtd->parent = dev; /* init the default settings */ diff --git a/drivers/mtd/nand/nomadik_nand.c b/drivers/mtd/nand/nomadik_nand.c index 8f37345bce..31bc2efc40 100644 --- a/drivers/mtd/nand/nomadik_nand.c +++ b/drivers/mtd/nand/nomadik_nand.c @@ -38,7 +38,6 @@ #include <errno.h> struct nomadik_nand_host { - struct mtd_info mtd; struct nand_chip nand; void __iomem *cmd_va; void __iomem *addr_va; @@ -105,7 +104,7 @@ static int nomadik_ecc512_calc(struct mtd_info *mtd, const u_char *data, static int nomadik_ecc512_correct(struct mtd_info *mtd, uint8_t *dat, uint8_t *r_ecc, uint8_t *c_ecc) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); uint32_t r, c, d, diff; /*read, calculated, xor of them */ if (!memcmp(r_ecc, c_ecc, chip->ecc.bytes)) @@ -157,7 +156,7 @@ static void nomadik_ecc_control(struct mtd_info *mtd, int mode) static void nomadik_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) { - struct nand_chip *nand = mtd->priv; + struct nand_chip *nand = mtd_to_nand(mtd); struct nomadik_nand_host *host = nand->priv; if (cmd == NAND_CMD_NONE) @@ -198,9 +197,8 @@ static int nomadik_nand_probe(struct device_d *dev) return PTR_ERR(host->addr_va); /* Link all private pointers */ - mtd = &host->mtd; nand = &host->nand; - mtd->priv = nand; + mtd = &nand->mtd; nand->priv = host; mtd->parent = dev; @@ -223,7 +221,7 @@ static int nomadik_nand_probe(struct device_d *dev) /* * Scan to find existance of the device */ - if (nand_scan(&host->mtd, 1)) { + if (nand_scan(mtd, 1)) { ret = -ENXIO; goto err; } diff --git a/drivers/mtd/nand/omap_elm.c b/drivers/mtd/nand/omap_elm.c new file mode 100644 index 0000000000..583235fc78 --- /dev/null +++ b/drivers/mtd/nand/omap_elm.c @@ -0,0 +1,413 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Error Location Module + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ + */ + +#define DRIVER_NAME "omap-elm" + +#include <common.h> +#include <driver.h> +#include <init.h> +#include <platform_data/elm.h> + +#define ELM_SYSCONFIG 0x010 +#define ELM_IRQSTATUS 0x018 +#define ELM_IRQENABLE 0x01c +#define ELM_LOCATION_CONFIG 0x020 +#define ELM_PAGE_CTRL 0x080 +#define ELM_SYNDROME_FRAGMENT_0 0x400 +#define ELM_SYNDROME_FRAGMENT_1 0x404 +#define ELM_SYNDROME_FRAGMENT_2 0x408 +#define ELM_SYNDROME_FRAGMENT_3 0x40c +#define ELM_SYNDROME_FRAGMENT_4 0x410 +#define ELM_SYNDROME_FRAGMENT_5 0x414 +#define ELM_SYNDROME_FRAGMENT_6 0x418 +#define ELM_LOCATION_STATUS 0x800 +#define ELM_ERROR_LOCATION_0 0x880 + +/* ELM Interrupt Status Register */ +#define INTR_STATUS_PAGE_VALID BIT(8) + +/* ELM Interrupt Enable Register */ +#define INTR_EN_PAGE_MASK BIT(8) + +/* ELM Location Configuration Register */ +#define ECC_BCH_LEVEL_MASK 0x3 + +/* ELM syndrome */ +#define ELM_SYNDROME_VALID BIT(16) + +/* ELM_LOCATION_STATUS Register */ +#define ECC_CORRECTABLE_MASK BIT(8) +#define ECC_NB_ERRORS_MASK 0x1f + +/* ELM_ERROR_LOCATION_0-15 Registers */ +#define ECC_ERROR_LOCATION_MASK 0x1fff + +#define ELM_ECC_SIZE 0x7ff + +#define SYNDROME_FRAGMENT_REG_SIZE 0x40 +#define ERROR_LOCATION_SIZE 0x100 + +struct elm_registers { + u32 elm_irqenable; + u32 elm_sysconfig; + u32 elm_location_config; + u32 elm_page_ctrl; + u32 elm_syndrome_fragment_6[ERROR_VECTOR_MAX]; + u32 elm_syndrome_fragment_5[ERROR_VECTOR_MAX]; + u32 elm_syndrome_fragment_4[ERROR_VECTOR_MAX]; + u32 elm_syndrome_fragment_3[ERROR_VECTOR_MAX]; + u32 elm_syndrome_fragment_2[ERROR_VECTOR_MAX]; + u32 elm_syndrome_fragment_1[ERROR_VECTOR_MAX]; + u32 elm_syndrome_fragment_0[ERROR_VECTOR_MAX]; +}; + +struct elm_info { + struct device_d *dev; + void __iomem *elm_base; + struct list_head list; + enum bch_ecc bch_type; + struct elm_registers elm_regs; + int ecc_steps; + int ecc_syndrome_size; +}; + +static struct elm_info *ginfo; + +static void elm_write_reg(struct elm_info *info, int offset, u32 val) +{ + writel(val, info->elm_base + offset); +} + +static u32 elm_read_reg(struct elm_info *info, int offset) +{ + return readl(info->elm_base + offset); +} + +/** + * elm_config - Configure ELM module + * @dev: ELM device + * @bch_type: Type of BCH ecc + */ +int elm_config(enum bch_ecc bch_type, int ecc_steps, int ecc_step_size, + int ecc_syndrome_size) +{ + struct elm_info *info = ginfo; + u32 reg_val; + + if (!info) + return -ENODEV; + /* ELM cannot detect ECC errors for chunks > 1KB */ + if (ecc_step_size > ((ELM_ECC_SIZE + 1) / 2)) { + dev_err(info->dev, "unsupported config ecc-size=%d\n", ecc_step_size); + return -EINVAL; + } + /* ELM support 8 error syndrome process */ + if (ecc_steps > ERROR_VECTOR_MAX) { + dev_err(info->dev, "unsupported config ecc-step=%d\n", ecc_steps); + return -EINVAL; + } + + reg_val = (bch_type & ECC_BCH_LEVEL_MASK) | (ELM_ECC_SIZE << 16); + elm_write_reg(info, ELM_LOCATION_CONFIG, reg_val); + info->bch_type = bch_type; + info->ecc_steps = ecc_steps; + info->ecc_syndrome_size = ecc_syndrome_size; + + return 0; +} + +/** + * elm_configure_page_mode - Enable/Disable page mode + * @info: elm info + * @index: index number of syndrome fragment vector + * @enable: enable/disable flag for page mode + * + * Enable page mode for syndrome fragment index + */ +static void elm_configure_page_mode(struct elm_info *info, int index, + bool enable) +{ + u32 reg_val; + + reg_val = elm_read_reg(info, ELM_PAGE_CTRL); + if (enable) + reg_val |= BIT(index); /* enable page mode */ + else + reg_val &= ~BIT(index); /* disable page mode */ + + elm_write_reg(info, ELM_PAGE_CTRL, reg_val); +} + +/** + * elm_load_syndrome - Load ELM syndrome reg + * @info: elm info + * @err_vec: elm error vectors + * @ecc: buffer with calculated ecc + * + * Load syndrome fragment registers with calculated ecc in reverse order. + */ +static void elm_load_syndrome(struct elm_info *info, + struct elm_errorvec *err_vec, u8 *ecc) +{ + int i, offset; + u32 val; + + for (i = 0; i < info->ecc_steps; i++) { + + /* Check error reported */ + if (err_vec[i].error_reported) { + elm_configure_page_mode(info, i, true); + offset = ELM_SYNDROME_FRAGMENT_0 + + SYNDROME_FRAGMENT_REG_SIZE * i; + switch (info->bch_type) { + case BCH8_ECC: + /* syndrome fragment 0 = ecc[9-12B] */ + val = cpu_to_be32(*(u32 *) &ecc[9]); + elm_write_reg(info, offset, val); + + /* syndrome fragment 1 = ecc[5-8B] */ + offset += 4; + val = cpu_to_be32(*(u32 *) &ecc[5]); + elm_write_reg(info, offset, val); + + /* syndrome fragment 2 = ecc[1-4B] */ + offset += 4; + val = cpu_to_be32(*(u32 *) &ecc[1]); + elm_write_reg(info, offset, val); + + /* syndrome fragment 3 = ecc[0B] */ + offset += 4; + val = ecc[0]; + elm_write_reg(info, offset, val); + break; + case BCH4_ECC: + /* syndrome fragment 0 = ecc[20-52b] bits */ + val = (cpu_to_be32(*(u32 *) &ecc[3]) >> 4) | + ((ecc[2] & 0xf) << 28); + elm_write_reg(info, offset, val); + + /* syndrome fragment 1 = ecc[0-20b] bits */ + offset += 4; + val = cpu_to_be32(*(u32 *) &ecc[0]) >> 12; + elm_write_reg(info, offset, val); + break; + case BCH16_ECC: + val = cpu_to_be32(*(u32 *) &ecc[22]); + elm_write_reg(info, offset, val); + offset += 4; + val = cpu_to_be32(*(u32 *) &ecc[18]); + elm_write_reg(info, offset, val); + offset += 4; + val = cpu_to_be32(*(u32 *) &ecc[14]); + elm_write_reg(info, offset, val); + offset += 4; + val = cpu_to_be32(*(u32 *) &ecc[10]); + elm_write_reg(info, offset, val); + offset += 4; + val = cpu_to_be32(*(u32 *) &ecc[6]); + elm_write_reg(info, offset, val); + offset += 4; + val = cpu_to_be32(*(u32 *) &ecc[2]); + elm_write_reg(info, offset, val); + offset += 4; + val = cpu_to_be32(*(u32 *) &ecc[0]) >> 16; + elm_write_reg(info, offset, val); + break; + default: + pr_err("invalid config bch_type\n"); + } + } + + /* Update ecc pointer with ecc byte size */ + ecc += info->ecc_syndrome_size; + } +} + +/** + * elm_start_processing - start elm syndrome processing + * @info: elm info + * @err_vec: elm error vectors + * + * Set syndrome valid bit for syndrome fragment registers for which + * elm syndrome fragment registers are loaded. This enables elm module + * to start processing syndrome vectors. + */ +static void elm_start_processing(struct elm_info *info, + struct elm_errorvec *err_vec) +{ + int i, offset; + u32 reg_val; + + /* + * Set syndrome vector valid, so that ELM module + * will process it for vectors error is reported + */ + for (i = 0; i < info->ecc_steps; i++) { + if (err_vec[i].error_reported) { + offset = ELM_SYNDROME_FRAGMENT_6 + + SYNDROME_FRAGMENT_REG_SIZE * i; + reg_val = elm_read_reg(info, offset); + reg_val |= ELM_SYNDROME_VALID; + elm_write_reg(info, offset, reg_val); + } + } +} + +/** + * elm_error_correction - locate correctable error position + * @info: elm info + * @err_vec: elm error vectors + * + * On completion of processing by elm module, error location status + * register updated with correctable/uncorrectable error information. + * In case of correctable errors, number of errors located from + * elm location status register & read the positions from + * elm error location register. + */ +static void elm_error_correction(struct elm_info *info, + struct elm_errorvec *err_vec) +{ + int i, j, errors = 0; + int offset; + u32 reg_val; + + for (i = 0; i < info->ecc_steps; i++) { + + /* Check error reported */ + if (err_vec[i].error_reported) { + offset = ELM_LOCATION_STATUS + ERROR_LOCATION_SIZE * i; + reg_val = elm_read_reg(info, offset); + + /* Check correctable error or not */ + if (reg_val & ECC_CORRECTABLE_MASK) { + offset = ELM_ERROR_LOCATION_0 + + ERROR_LOCATION_SIZE * i; + + /* Read count of correctable errors */ + err_vec[i].error_count = reg_val & + ECC_NB_ERRORS_MASK; + + /* Update the error locations in error vector */ + for (j = 0; j < err_vec[i].error_count; j++) { + + reg_val = elm_read_reg(info, offset); + err_vec[i].error_loc[j] = reg_val & + ECC_ERROR_LOCATION_MASK; + + /* Update error location register */ + offset += 4; + } + + errors += err_vec[i].error_count; + } else { + err_vec[i].error_uncorrectable = true; + } + + /* Clearing interrupts for processed error vectors */ + elm_write_reg(info, ELM_IRQSTATUS, BIT(i)); + + /* Disable page mode */ + elm_configure_page_mode(info, i, false); + } + } +} + +static int elm_poll(struct elm_info *info) +{ + u32 reg_val; + + reg_val = elm_read_reg(info, ELM_IRQSTATUS); + + /* All error vectors processed */ + if (reg_val & INTR_STATUS_PAGE_VALID) { + elm_write_reg(info, ELM_IRQSTATUS, + reg_val & INTR_STATUS_PAGE_VALID); + return 0; + } + + return -EINPROGRESS; +} + +/** + * elm_decode_bch_error_page - Locate error position + * @dev: device pointer + * @ecc_calc: calculated ECC bytes from GPMC + * @err_vec: elm error vectors + * + * Called with one or more error reported vectors & vectors with + * error reported is updated in err_vec[].error_reported + */ +int elm_decode_bch_error_page(u8 *ecc_calc, struct elm_errorvec *err_vec) +{ + struct elm_info *info = ginfo; + u32 reg_val; + uint64_t start; + + if (!info) + return -ENODEV; + + /* Enable page mode interrupt */ + reg_val = elm_read_reg(info, ELM_IRQSTATUS); + elm_write_reg(info, ELM_IRQSTATUS, reg_val & INTR_STATUS_PAGE_VALID); + elm_write_reg(info, ELM_IRQENABLE, INTR_EN_PAGE_MASK); + + /* Load valid ecc byte to syndrome fragment register */ + elm_load_syndrome(info, err_vec, ecc_calc); + + /* Enable syndrome processing for which syndrome fragment is updated */ + elm_start_processing(info, err_vec); + + /* Wait for ELM module to finish locating error correction */ + start = get_time_ns(); + while (elm_poll(info) < 0) { + if (is_timeout(start, SECOND)) + return -ETIMEDOUT; + } + + /* Disable page mode interrupt */ + reg_val = elm_read_reg(info, ELM_IRQENABLE); + elm_write_reg(info, ELM_IRQENABLE, reg_val & ~INTR_EN_PAGE_MASK); + elm_error_correction(info, err_vec); + + return 0; +} + +static int elm_probe(struct device_d *dev) +{ + struct resource *res; + struct elm_info *info; + + info = xzalloc(sizeof(*info)); + + info->dev = dev; + + res = dev_request_mem_resource(dev, 0); + if (IS_ERR(res)) + return PTR_ERR(res); + info->elm_base = IOMEM(res->start); + + dev->priv = info; + + ginfo = info; + + return 0; +} + +static struct of_device_id elm_compatible[] = { + { + .compatible = "ti,am3352-elm", + }, { + /* sentinel */ + } +}; + +static struct driver_d omap_elm_driver = { + .name = "omap-elm", + .probe = elm_probe, + .of_compatible = DRV_OF_COMPAT(elm_compatible) +}; +coredevice_platform_driver(omap_elm_driver); diff --git a/drivers/mtd/peb.c b/drivers/mtd/peb.c index c82b3e8bba..d10a8a024d 100644 --- a/drivers/mtd/peb.c +++ b/drivers/mtd/peb.c @@ -438,6 +438,90 @@ int mtd_peb_write(struct mtd_info *mtd, const void *buf, int pnum, int offset, } /** + * mtd_peb_write_file - write data into a mtd device + * @mtd: mtd device + * @peb_start: The first PEB where to start writing + * @max_pebs: Maximum number of PEBs we have space to write to + * @buf: buffer with the data to write + * @len: how many bytes to write + * + * This function writes @len bytes of data from buffer @buf to the mtd device + * @mtd starting at @peb_start. At maxmimum @max_pebs are used. We always write + * full pebs. If the buffer is not peb size aligned the last peb will be padded + * with zeroes. This function skips all bad blocks and returns 0 on success or a + * negative error code otherwise. + */ +int mtd_peb_write_file(struct mtd_info *mtd, int peb_start, int max_pebs, + const void *buf, size_t len) +{ + int ret, pnum; + size_t left; + + pnum = peb_start; + left = len; + + /* First pass: Check if file will fit into remaining space */ + while (1) { + if ((uint64_t)pnum * mtd->erasesize >= mtd->size) + return -ENOSPC; + + if (pnum >= peb_start + max_pebs) + return -ENOSPC; + + if (mtd_peb_is_bad(mtd, pnum)) { + pnum++; + continue; + } + + if (left <= mtd->erasesize) + break; + + left -= mtd->erasesize; + pnum++; + } + + pnum = peb_start; + left = len; + + /* Second pass: actually write file */ + while (left) { + size_t now = min_t(size_t, mtd->erasesize, left); + + if (mtd_peb_is_bad(mtd, pnum)) { + pnum++; + continue; + } + + ret = mtd_peb_erase(mtd, pnum); + if (ret) + goto out; + + if (now < mtd->erasesize) { + void *wrbuf = xzalloc(mtd->erasesize); + + memcpy(wrbuf, buf, now); + + ret = mtd_peb_write(mtd, wrbuf, pnum, 0, mtd->erasesize); + + free(wrbuf); + } else { + ret = mtd_peb_write(mtd, buf, pnum, 0, mtd->erasesize); + } + + if (ret) + goto out; + + left -= now; + pnum++; + buf += now; + } + + ret = 0; +out: + return ret; +} + +/** * mtd_peb_erase - erase a physical eraseblock. * @mtd: mtd device * @pnum: physical eraseblock number to erase diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 9dbc8302ed..b251035982 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -57,7 +57,7 @@ struct flash_info { u16 page_size; u16 addr_width; - u16 flags; + u32 flags; #define SECT_4K BIT(0) /* SPINOR_OP_BE_4K works uniformly */ #define SPI_NOR_NO_ERASE BIT(1) /* No erase command needed */ #define SST_WRITE BIT(2) /* use SST byte programming */ @@ -86,6 +86,7 @@ struct flash_info { #define SPI_NOR_SKIP_SFDP BIT(13) /* Skip parsing of SFDP tables */ #define USE_CLSR BIT(14) /* use CLSR command */ #define SPI_NOR_OCTAL_READ BIT(15) /* Flash supports Octal Read */ +#define UNLOCK_GLOBAL_BLOCK BIT(16) /* Unlock global block protection */ }; enum spi_nor_read_command_index { @@ -725,6 +726,9 @@ static const struct spi_device_id spi_nor_ids[] = { { "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, { "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, { "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, + { "n25q00a", INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, + { "mt25qu02g", INFO(0x20bb22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, + { "mt25ql02g", INFO(0x20ba22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, /* PMC */ { "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) }, @@ -736,6 +740,10 @@ static const struct spi_device_id spi_nor_ids[] = { */ { "s25sl032p", INFO(0x010215, 0x4d00, 64 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "s25sl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "s25fl128s0", INFO6(0x012018, 0x4d0080, 256 * 1024, 64, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { "s25fl128s1", INFO6(0x012018, 0x4d0180, 64 * 1024, 256, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) }, { "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, @@ -773,6 +781,31 @@ static const struct spi_device_id spi_nor_ids[] = { { "sst25wf040b", INFO(0x621613, 0, 64 * 1024, 8, SECT_4K) }, { "sst25wf040", INFO(0xbf2504, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, { "sst25wf080", INFO(0xbf2505, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) }, + { + "sst26vf016b", INFO(0xbf2641, 0, 64 * 1024, 32, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + UNLOCK_GLOBAL_BLOCK) + }, + { + "sst26vf032b", INFO(0xbf2642, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + UNLOCK_GLOBAL_BLOCK) + }, + { + "sst26vf064b", INFO(0xbf2643, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + UNLOCK_GLOBAL_BLOCK) + }, + { + "sst26vf040b", INFO(0xbf2654, 0, 64 * 1024, 8, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + UNLOCK_GLOBAL_BLOCK) + }, + { + "sst26vf080b", INFO(0xbf2658, 0, 64 * 1024, 16, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + UNLOCK_GLOBAL_BLOCK) + }, /* ST Microelectronics -- newer production may have feature updates */ { "m25p05", INFO(0x202010, 0, 32 * 1024, 2, 0) }, @@ -1067,6 +1100,17 @@ spi_nor_set_pp_settings(struct spi_nor_pp_command *pp, pp->proto = proto; } +static int spi_nor_unlock_global_block_protection(struct spi_nor *nor) +{ + int ret; + + write_enable(nor); + ret = nor->write_reg(nor, SPINOR_OP_GBULK, NULL, 0); + if (ret < 0) + return ret; + return spi_nor_wait_till_ready(nor); +} + static int spi_nor_init_params(struct spi_nor *nor, const struct flash_info *info, struct spi_nor_flash_parameter *params) @@ -1110,6 +1154,17 @@ static int spi_nor_init_params(struct spi_nor *nor, spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP], SPINOR_OP_PP, SNOR_PROTO_1_1_1); + if (info->flags & UNLOCK_GLOBAL_BLOCK) { + int err; + + err = spi_nor_unlock_global_block_protection(nor); + if (err) { + dev_err(nor->dev, + "Cannot unlock the global block protection\n"); + return err; + } + } + /* Select the procedure to set the Quad Enable bit. */ if (params->hwcaps.mask & (SNOR_HWCAPS_READ_QUAD | SNOR_HWCAPS_PP_QUAD)) diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c index df8981d02e..b9a6575009 100644 --- a/drivers/net/cpsw.c +++ b/drivers/net/cpsw.c @@ -191,7 +191,6 @@ struct cpdma_chan { struct cpsw_priv { struct device_d *dev; - struct mii_bus miibus; u32 version; struct cpsw_platform_data data; @@ -199,7 +198,6 @@ struct cpsw_priv { uint8_t mac_addr[6]; struct cpsw_regs *regs; - struct cpsw_mdio_regs *mdio_regs; void *dma_regs; struct cpsw_host_regs *host_port_regs; void *ale_regs; @@ -219,6 +217,12 @@ struct cpsw_priv { struct cpsw_slave *slaves; }; +struct cpsw_mdio_priv { + struct device_d *dev; + struct mii_bus miibus; + struct cpsw_mdio_regs *mdio_regs; +}; + static int cpsw_ale_get_field(u32 *ale_entry, u32 start, u32 bits) { int idx; @@ -450,7 +454,7 @@ static inline void cpsw_ale_port_state(struct cpsw_priv *priv, int port, } /* wait until hardware is ready for another user access */ -static u32 wait_for_user_access(struct cpsw_priv *priv) +static u32 wait_for_user_access(struct cpsw_mdio_priv *priv) { struct cpsw_mdio_regs *mdio_regs = priv->mdio_regs; u32 tmp; @@ -473,7 +477,7 @@ static u32 wait_for_user_access(struct cpsw_priv *priv) static int cpsw_mdio_read(struct mii_bus *bus, int phy_id, int phy_reg) { - struct cpsw_priv *priv = bus->priv; + struct cpsw_mdio_priv *priv = bus->priv; struct cpsw_mdio_regs *mdio_regs = priv->mdio_regs; u32 tmp; @@ -494,7 +498,7 @@ static int cpsw_mdio_read(struct mii_bus *bus, int phy_id, int phy_reg) static int cpsw_mdio_write(struct mii_bus *bus, int phy_id, int phy_reg, u16 value) { - struct cpsw_priv *priv = bus->priv; + struct cpsw_mdio_priv *priv = bus->priv; struct cpsw_mdio_regs *mdio_regs = priv->mdio_regs; u32 tmp; @@ -510,6 +514,81 @@ static int cpsw_mdio_write(struct mii_bus *bus, int phy_id, int phy_reg, u16 val return 0; } +static int cpsw_mdio_probe(struct device_d *dev) +{ + struct resource *iores; + struct cpsw_mdio_priv *priv; + uint64_t start; + uint32_t phy_mask; + int ret; + + priv = xzalloc(sizeof(*priv)); + + iores = dev_request_mem_resource(dev, 0); + if (IS_ERR(iores)) + return PTR_ERR(iores); + priv->mdio_regs = IOMEM(iores->start); + priv->miibus.read = cpsw_mdio_read; + priv->miibus.write = cpsw_mdio_write; + priv->miibus.priv = priv; + priv->miibus.parent = dev; + + /* + * set enable and clock divider + * + * FIXME: Use a clock to calculate the divider + */ + writel(0xff | CONTROL_ENABLE, &priv->mdio_regs->control); + + /* + * wait for scan logic to settle: + * the scan time consists of (a) a large fixed component, and (b) a + * small component that varies with the mii bus frequency. These + * were estimated using measurements at 1.1 and 2.2 MHz on tnetv107x + * silicon. Since the effect of (b) was found to be largely + * negligible, we keep things simple here. + */ + udelay(1000); + + start = get_time_ns(); + while (1) { + phy_mask = readl(&priv->mdio_regs->alive); + if (phy_mask) { + dev_info(dev, "detected phy mask 0x%x\n", phy_mask); + phy_mask = ~phy_mask; + break; + } + if (is_timeout(start, 256 * MSECOND)) { + dev_err(dev, "no live phy, scanning all\n"); + phy_mask = 0; + break; + } + } + + priv->miibus.phy_mask = phy_mask; + + ret = mdiobus_register(&priv->miibus); + if (ret) + return ret; + + return 0; +} + +static __maybe_unused struct of_device_id cpsw_mdio_dt_ids[] = { + { + .compatible = "ti,cpsw-mdio", + }, { + /* sentinel */ + } +}; + +static struct driver_d cpsw_mdio_driver = { + .name = "cpsw-mdio", + .probe = cpsw_mdio_probe, + .of_compatible = DRV_OF_COMPAT(cpsw_mdio_dt_ids), +}; +coredevice_platform_driver(cpsw_mdio_driver); + static inline void soft_reset(struct cpsw_priv *priv, void *reg) { int ret; @@ -549,9 +628,9 @@ static int cpsw_set_hwaddr(struct eth_device *edev, const unsigned char *mac) return 0; } -static void cpsw_slave_update_link(struct cpsw_slave *slave, - struct cpsw_priv *priv, int *link) +static void cpsw_adjust_link(struct eth_device *edev) { + struct cpsw_slave *slave = edev->priv; struct phy_device *phydev = slave->edev.phydev; u32 mac_control = 0; @@ -561,7 +640,6 @@ static void cpsw_slave_update_link(struct cpsw_slave *slave, return; if (phydev->link) { - *link = 1; mac_control = BIT(5); /* MIIEN */ if (phydev->speed == SPEED_10) mac_control |= BIT(18); /* In Band mode */ @@ -584,27 +662,6 @@ static void cpsw_slave_update_link(struct cpsw_slave *slave, writel(mac_control, &slave->sliver->mac_control); } -static int cpsw_update_link(struct cpsw_slave *slave, struct cpsw_priv *priv) -{ - int link = 0; - - dev_dbg(&slave->dev, "* %s\n", __func__); - - cpsw_slave_update_link(slave, priv, &link); - - return link; -} - -static void cpsw_adjust_link(struct eth_device *edev) -{ - struct cpsw_slave *slave = edev->priv; - struct cpsw_priv *priv = slave->cpsw; - - dev_dbg(&slave->dev, "* %s\n", __func__); - - cpsw_update_link(slave, priv); -} - static inline u32 cpsw_get_slave_port(struct cpsw_priv *priv, u32 slave_num) { if (priv->host_port == 0) @@ -748,6 +805,11 @@ static int cpsw_open(struct eth_device *edev) dev_dbg(&slave->dev, "* %s\n", __func__); + ret = phy_device_connect(edev, NULL, slave->phy_id, + cpsw_adjust_link, 0, slave->phy_if); + if (ret) + return ret; + /* soft reset the controller and initialize priv */ soft_reset(priv, &priv->regs->soft_reset); @@ -774,7 +836,6 @@ static int cpsw_open(struct eth_device *edev) cpsw_ale_add_mcast(priv, ethbdaddr, 1 << priv->host_port); cpsw_slave_init(slave, priv); - cpsw_update_link(slave, priv); /* init descriptor pool */ for (i = 0; i < NUM_DESCS; i++) { @@ -898,11 +959,6 @@ static int cpsw_slave_setup(struct cpsw_slave *slave, int slave_num, edev->parent = dev; - ret = phy_device_connect(edev, &priv->miibus, slave->phy_id, - cpsw_adjust_link, 0, slave->phy_if); - if (ret) - goto err_out; - dev_set_name(dev, "cpsw-slave"); dev->id = slave->slave_num; dev->parent = priv->dev; @@ -936,7 +992,7 @@ err_register_dev: phy_unregister_device(edev->phydev); err_register_edev: unregister_device(dev); -err_out: + slave->slave_num = -1; return ret; @@ -1117,13 +1173,15 @@ static int cpsw_probe(struct device_d *dev) struct cpsw_platform_data *data = (struct cpsw_platform_data *)dev->platform_data; struct cpsw_priv *priv; void __iomem *regs; - uint64_t start; - uint32_t phy_mask; struct cpsw_data *cpsw_data; int i, ret; dev_dbg(dev, "* %s\n", __func__); + ret = of_platform_populate(dev->device_node, NULL, dev); + if (ret) + return ret; + iores = dev_request_mem_resource(dev, 0); if (IS_ERR(iores)) return PTR_ERR(iores); @@ -1168,53 +1226,11 @@ static int cpsw_probe(struct device_d *dev) priv->dma_regs = regs + cpsw_data->cpdma_reg_ofs; priv->ale_regs = regs + cpsw_data->ale_reg_ofs; priv->state_ram = regs + cpsw_data->state_ram_ofs; - priv->mdio_regs = regs + cpsw_data->mdio_reg_ofs; priv->slave_ofs = cpsw_data->slave_ofs; priv->slave_size = cpsw_data->slave_size; priv->sliver_ofs = cpsw_data->sliver_ofs; - priv->miibus.read = cpsw_mdio_read; - priv->miibus.write = cpsw_mdio_write; - priv->miibus.priv = priv; - priv->miibus.parent = dev; - - /* - * set enable and clock divider - * - * FIXME: Use a clock to calculate the divider - */ - writel(0xff | CONTROL_ENABLE, &priv->mdio_regs->control); - - /* - * wait for scan logic to settle: - * the scan time consists of (a) a large fixed component, and (b) a - * small component that varies with the mii bus frequency. These - * were estimated using measurements at 1.1 and 2.2 MHz on tnetv107x - * silicon. Since the effect of (b) was found to be largely - * negligible, we keep things simple here. - */ - udelay(1000); - - start = get_time_ns(); - while (1) { - phy_mask = readl(&priv->mdio_regs->alive); - if (phy_mask) { - dev_info(dev, "detected phy mask 0x%x\n", phy_mask); - phy_mask = ~phy_mask; - break; - } - if (is_timeout(start, 256 * MSECOND)) { - dev_err(dev, "no live phy, scanning all\n"); - phy_mask = 0; - break; - } - } - - priv->miibus.phy_mask = phy_mask; - - mdiobus_register(&priv->miibus); - for (i = 0; i < priv->num_slaves; i++) { ret = cpsw_slave_setup(&priv->slaves[i], i, priv); if (ret) { @@ -1245,8 +1261,6 @@ static void cpsw_remove(struct device_d *dev) eth_unregister(&slave->edev); } - - mdiobus_unregister(&priv->miibus); } static __maybe_unused struct of_device_id cpsw_dt_ids[] = { diff --git a/drivers/net/macb.c b/drivers/net/macb.c index a0411d6e4b..c4ab9efb63 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -322,6 +322,29 @@ static void macb_configure_dma(struct macb_device *bp) } } +static int gmac_init_dummy_tx_queues(struct macb_device *macb) +{ + int i, num_queues = 1; + u32 queue_mask; + + /* bit 0 is never set but queue 0 always exists */ + queue_mask = gem_readl(macb, DCFG6) & 0xff; + queue_mask |= 0x1; + + for (i = 1; i < MACB_MAX_QUEUES; i++) + if (queue_mask & (1 << i)) + num_queues++; + + macb->gem_q1_descs[0].addr = 0; + macb->gem_q1_descs[0].ctrl = MACB_BIT(TX_WRAP) | + MACB_BIT(TX_LAST) | MACB_BIT(TX_USED); + + for (i = 1; i < num_queues; i++) + gem_writel_queue_TBQP(macb, &macb->gem_q1_descs[0], i - 1); + + return 0; +} + static void macb_init(struct macb_device *macb) { unsigned long paddr, val = 0; @@ -357,16 +380,13 @@ static void macb_init(struct macb_device *macb) macb_writel(macb, TBQP, (ulong)macb->tx_ring); if (macb->is_gem && macb->gem_q1_descs) { - /* Disable the second priority queue */ - macb->gem_q1_descs[0].addr = 0; - macb->gem_q1_descs[0].ctrl = MACB_BIT(TX_WRAP) | - MACB_BIT(TX_LAST) | - MACB_BIT(TX_USED); + gmac_init_dummy_tx_queues(macb); + + /* Disable the second priority rx queue */ macb->gem_q1_descs[1].addr = MACB_BIT(RX_USED) | MACB_BIT(RX_WRAP); macb->gem_q1_descs[1].ctrl = 0; - gem_writel(macb, TQ1, (ulong)&macb->gem_q1_descs[0]); gem_writel(macb, RQ1, (ulong)&macb->gem_q1_descs[1]); } @@ -750,6 +770,7 @@ static void macb_remove(struct device_d *dev) static const struct of_device_id macb_dt_ids[] = { { .compatible = "cdns,at91sam9260-macb",}, + { .compatible = "atmel,sama5d2-gem",}, { .compatible = "atmel,sama5d3-gem",}, { .compatible = "cdns,zynqmp-gem",}, { /* sentinel */ } diff --git a/drivers/net/macb.h b/drivers/net/macb.h index fda4d08663..2e5b64e5e9 100644 --- a/drivers/net/macb.h +++ b/drivers/net/macb.h @@ -5,6 +5,8 @@ #ifndef __DRIVERS_MACB_H__ #define __DRIVERS_MACB_H__ +#define MACB_MAX_QUEUES 8 + /* MACB register offsets */ #define MACB_NCR 0x0000 #define MACB_NCFGR 0x0004 @@ -75,6 +77,8 @@ #define GEM_TQ1 0x0440 #define GEM_RQ1 0x0480 +#define GEM_TBQP(hw_q) (0x0440 + ((hw_q) << 2)) + /* Bitfields in NCR */ #define MACB_LB_OFFSET 0 #define MACB_LB_SIZE 1 @@ -436,4 +440,7 @@ struct macb_dma_desc { #define MACB_TX_USED_OFFSET 31 #define MACB_TX_USED_SIZE 1 +#define gem_writel_queue_TBQP(port, value, queue_num) \ + writel((value), (port)->regs + GEM_TBQP(queue_num)) + #endif /* __DRIVERS_MACB_H__ */ diff --git a/drivers/net/phy/mv88e6xxx/chip.c b/drivers/net/phy/mv88e6xxx/chip.c index ac08b5ef54..9688dbd1be 100644 --- a/drivers/net/phy/mv88e6xxx/chip.c +++ b/drivers/net/phy/mv88e6xxx/chip.c @@ -572,7 +572,6 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6352", .num_ports = 7, .port_base_addr = 0x10, - .ops = &mv88e6352_ops, .global2_addr = 0x1c, .ops = &mv88e6352_ops, }, diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 0d5dcb31ee..ea7cea5f1b 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -540,7 +540,7 @@ static int smc911x_probe(struct device_d *dev) * poll the READY bit in PMT_CTRL. Any other access to the device is * forbidden while this bit isn't set. Try for 100ms */ - ret = wait_on_timeout(100 * MSECOND, !smc911x_reg_read(priv, PMT_CTRL) & PMT_CTRL_READY); + ret = wait_on_timeout(100 * MSECOND, smc911x_reg_read(priv, PMT_CTRL) & PMT_CTRL_READY); if (!ret) { dev_err(dev, "Device not READY in 100ms aborting\n"); return -ENODEV; diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index e0984708b4..d2c2b6f306 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -94,7 +94,7 @@ EXPORT_SYMBOL_GPL(nvme_set_queue_count); static int nvme_wait_ready(struct nvme_ctrl *ctrl, u64 cap, bool enabled) { uint64_t start = get_time_ns(); - unsigned long timeout = + uint64_t timeout = ((NVME_CAP_TIMEOUT(cap) + 1) * HZ / 2); u32 csts, bit = enabled ? NVME_CSTS_RDY : 0; int ret; @@ -496,7 +496,7 @@ EXPORT_SYMBOL_GPL(nvme_enable_ctrl); int nvme_shutdown_ctrl(struct nvme_ctrl *ctrl) { uint64_t start = get_time_ns(); - unsigned long timeout = SHUTDOWN_TIMEOUT; + uint64_t timeout = SHUTDOWN_TIMEOUT; u32 csts; int ret; diff --git a/drivers/serial/atmel.c b/drivers/serial/atmel.c index 2f8adc989f..8394273f9f 100644 --- a/drivers/serial/atmel.c +++ b/drivers/serial/atmel.c @@ -436,6 +436,7 @@ static int atmel_serial_probe(struct device_d *dev) cdev->getc = atmel_serial_getc; cdev->setbrg = atmel_serial_setbaudrate; cdev->set_mode = atmel_serial_set_mode; + cdev->linux_console_name = "ttyAT"; atmel_serial_init_port(cdev); diff --git a/drivers/serial/efi-stdio.c b/drivers/serial/efi-stdio.c index 0703f727e7..2ca89fa4f8 100644 --- a/drivers/serial/efi-stdio.c +++ b/drivers/serial/efi-stdio.c @@ -243,12 +243,13 @@ static int efi_process_key(struct efi_console_priv *priv, const char *inp) return 1; } -static int efi_console_puts(struct console_device *cdev, const char *s) +static int efi_console_puts(struct console_device *cdev, const char *s, + size_t nbytes) { struct efi_console_priv *priv = to_efi(cdev); int n = 0; - while (*s) { + while (nbytes--) { if (*s == 27) { priv->efi_console_buffer[n] = 0; priv->out->output_string(priv->out, diff --git a/drivers/serial/serial_efi.c b/drivers/serial/serial_efi.c index f0a2b22c2b..667d51f622 100644 --- a/drivers/serial/serial_efi.c +++ b/drivers/serial/serial_efi.c @@ -130,13 +130,14 @@ static void efi_serial_putc(struct console_device *cdev, char c) serial->write(serial, &buffersize, &c); } -static int efi_serial_puts(struct console_device *cdev, const char *s) +static int efi_serial_puts(struct console_device *cdev, const char *s, + size_t nbytes) { struct efi_serial_port *uart = to_efi_serial_port(cdev); struct efi_serial_io_protocol *serial = uart->serial; uint32_t control; efi_status_t efiret; - unsigned long buffersize = strlen(s) * sizeof(char); + unsigned long buffersize = nbytes; do { efiret = serial->getcontrol(serial, &control); diff --git a/drivers/serial/serial_stm32.c b/drivers/serial/serial_stm32.c index a84e64e974..4bbfb1eef7 100644 --- a/drivers/serial/serial_stm32.c +++ b/drivers/serial/serial_stm32.c @@ -182,6 +182,7 @@ static int stm32_serial_probe(struct device_d *dev) cdev->getc = stm32_serial_getc; cdev->flush = stm32_serial_flush; cdev->setbrg = stm32_serial_setbaudrate; + cdev->linux_console_name = "ttySTM"; if (dev->device_node) { devname = of_alias_get(dev->device_node); diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 86411a76ff..9d4b1cc4e3 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -25,6 +25,15 @@ config DRIVER_SPI_ATMEL bool "Atmel (AT91) SPI Master driver" depends on ARCH_AT91 +config SPI_ATMEL_QUADSPI + tristate "Atmel Quad SPI Controller" + depends on ARCH_AT91 + depends on SPI_MEM + help + This enables support for the Quad SPI controller in master mode. + This driver does not support generic SPI. The implementation only + supports spi-mem interface. + config DRIVER_SPI_FSL_QUADSPI bool "Freescale QSPI controller" depends on SPI_MEM diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index dd8a8cb8b0..c5d2de74e1 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -8,5 +8,6 @@ obj-$(CONFIG_DRIVER_SPI_MVEBU) += mvebu_spi.o obj-$(CONFIG_DRIVER_SPI_MXS) += mxs_spi.o obj-$(CONFIG_DRIVER_SPI_ALTERA) += altera_spi.o obj-$(CONFIG_DRIVER_SPI_ATMEL) += atmel_spi.o +obj-$(CONFIG_SPI_ATMEL_QUADSPI) += atmel-quadspi.o obj-$(CONFIG_DRIVER_SPI_OMAP3) += omap3_spi.o obj-$(CONFIG_DRIVER_SPI_DSPI) += dspi_spi.o diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c new file mode 100644 index 0000000000..6799f95ea3 --- /dev/null +++ b/drivers/spi/atmel-quadspi.c @@ -0,0 +1,541 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for Atmel QSPI Controller + * + * Copyright (C) 2015 Atmel Corporation + * Copyright (C) 2018 Cryptera A/S + * + * Author: Cyrille Pitchen <cyrille.pitchen@atmel.com> + * Author: Piotr Bugalski <bugalski.piotr@gmail.com> + * + * This driver is based on drivers/mtd/spi-nor/fsl-quadspi.c from Freescale. + */ + +#include <common.h> +#include <init.h> +#include <driver.h> +#include <errno.h> +#include <clock.h> +#include <xfuncs.h> +#include <gpio.h> +#include <of_gpio.h> +#include <io.h> +#include <spi/spi.h> +#include <mach/iomux.h> +#include <mach/board.h> +#include <mach/cpu.h> +#include <linux/clk.h> +#include <linux/err.h> + +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/spi/spi-mem.h> +#include <of_device.h> +#include <linux/iopoll.h> + +#define writel_relaxed writel +#define readl_relaxed readl + +/* QSPI register offsets */ +#define QSPI_CR 0x0000 /* Control Register */ +#define QSPI_MR 0x0004 /* Mode Register */ +#define QSPI_RD 0x0008 /* Receive Data Register */ +#define QSPI_TD 0x000c /* Transmit Data Register */ +#define QSPI_SR 0x0010 /* Status Register */ +#define QSPI_IER 0x0014 /* Interrupt Enable Register */ +#define QSPI_IDR 0x0018 /* Interrupt Disable Register */ +#define QSPI_IMR 0x001c /* Interrupt Mask Register */ +#define QSPI_SCR 0x0020 /* Serial Clock Register */ + +#define QSPI_IAR 0x0030 /* Instruction Address Register */ +#define QSPI_ICR 0x0034 /* Instruction Code Register */ +#define QSPI_WICR 0x0034 /* Write Instruction Code Register */ +#define QSPI_IFR 0x0038 /* Instruction Frame Register */ +#define QSPI_RICR 0x003C /* Read Instruction Code Register */ + +#define QSPI_SMR 0x0040 /* Scrambling Mode Register */ +#define QSPI_SKR 0x0044 /* Scrambling Key Register */ + +#define QSPI_WPMR 0x00E4 /* Write Protection Mode Register */ +#define QSPI_WPSR 0x00E8 /* Write Protection Status Register */ + +#define QSPI_VERSION 0x00FC /* Version Register */ + + +/* Bitfields in QSPI_CR (Control Register) */ +#define QSPI_CR_QSPIEN BIT(0) +#define QSPI_CR_QSPIDIS BIT(1) +#define QSPI_CR_SWRST BIT(7) +#define QSPI_CR_LASTXFER BIT(24) + +/* Bitfields in QSPI_MR (Mode Register) */ +#define QSPI_MR_SMM BIT(0) +#define QSPI_MR_LLB BIT(1) +#define QSPI_MR_WDRBT BIT(2) +#define QSPI_MR_SMRM BIT(3) +#define QSPI_MR_CSMODE_MASK GENMASK(5, 4) +#define QSPI_MR_CSMODE_NOT_RELOADED (0 << 4) +#define QSPI_MR_CSMODE_LASTXFER (1 << 4) +#define QSPI_MR_CSMODE_SYSTEMATICALLY (2 << 4) +#define QSPI_MR_NBBITS_MASK GENMASK(11, 8) +#define QSPI_MR_NBBITS(n) ((((n) - 8) << 8) & QSPI_MR_NBBITS_MASK) +#define QSPI_MR_DLYBCT_MASK GENMASK(23, 16) +#define QSPI_MR_DLYBCT(n) (((n) << 16) & QSPI_MR_DLYBCT_MASK) +#define QSPI_MR_DLYCS_MASK GENMASK(31, 24) +#define QSPI_MR_DLYCS(n) (((n) << 24) & QSPI_MR_DLYCS_MASK) + +/* Bitfields in QSPI_SR/QSPI_IER/QSPI_IDR/QSPI_IMR */ +#define QSPI_SR_RDRF BIT(0) +#define QSPI_SR_TDRE BIT(1) +#define QSPI_SR_TXEMPTY BIT(2) +#define QSPI_SR_OVRES BIT(3) +#define QSPI_SR_CSR BIT(8) +#define QSPI_SR_CSS BIT(9) +#define QSPI_SR_INSTRE BIT(10) +#define QSPI_SR_QSPIENS BIT(24) + +#define QSPI_SR_CMD_COMPLETED (QSPI_SR_INSTRE | QSPI_SR_CSR) + +/* Bitfields in QSPI_SCR (Serial Clock Register) */ +#define QSPI_SCR_CPOL BIT(0) +#define QSPI_SCR_CPHA BIT(1) +#define QSPI_SCR_SCBR_MASK GENMASK(15, 8) +#define QSPI_SCR_SCBR(n) (((n) << 8) & QSPI_SCR_SCBR_MASK) +#define QSPI_SCR_DLYBS_MASK GENMASK(23, 16) +#define QSPI_SCR_DLYBS(n) (((n) << 16) & QSPI_SCR_DLYBS_MASK) + +/* Bitfields in QSPI_ICR (Read/Write Instruction Code Register) */ +#define QSPI_ICR_INST_MASK GENMASK(7, 0) +#define QSPI_ICR_INST(inst) (((inst) << 0) & QSPI_ICR_INST_MASK) +#define QSPI_ICR_OPT_MASK GENMASK(23, 16) +#define QSPI_ICR_OPT(opt) (((opt) << 16) & QSPI_ICR_OPT_MASK) + +/* Bitfields in QSPI_IFR (Instruction Frame Register) */ +#define QSPI_IFR_WIDTH_MASK GENMASK(2, 0) +#define QSPI_IFR_WIDTH_SINGLE_BIT_SPI (0 << 0) +#define QSPI_IFR_WIDTH_DUAL_OUTPUT (1 << 0) +#define QSPI_IFR_WIDTH_QUAD_OUTPUT (2 << 0) +#define QSPI_IFR_WIDTH_DUAL_IO (3 << 0) +#define QSPI_IFR_WIDTH_QUAD_IO (4 << 0) +#define QSPI_IFR_WIDTH_DUAL_CMD (5 << 0) +#define QSPI_IFR_WIDTH_QUAD_CMD (6 << 0) +#define QSPI_IFR_INSTEN BIT(4) +#define QSPI_IFR_ADDREN BIT(5) +#define QSPI_IFR_OPTEN BIT(6) +#define QSPI_IFR_DATAEN BIT(7) +#define QSPI_IFR_OPTL_MASK GENMASK(9, 8) +#define QSPI_IFR_OPTL_1BIT (0 << 8) +#define QSPI_IFR_OPTL_2BIT (1 << 8) +#define QSPI_IFR_OPTL_4BIT (2 << 8) +#define QSPI_IFR_OPTL_8BIT (3 << 8) +#define QSPI_IFR_ADDRL BIT(10) +#define QSPI_IFR_TFRTYP_MEM BIT(12) +#define QSPI_IFR_SAMA5D2_WRITE_TRSFR BIT(13) +#define QSPI_IFR_CRM BIT(14) +#define QSPI_IFR_NBDUM_MASK GENMASK(20, 16) +#define QSPI_IFR_NBDUM(n) (((n) << 16) & QSPI_IFR_NBDUM_MASK) +#define QSPI_IFR_APBTFRTYP_READ BIT(24) /* Defined in SAM9X60 */ + +/* Bitfields in QSPI_SMR (Scrambling Mode Register) */ +#define QSPI_SMR_SCREN BIT(0) +#define QSPI_SMR_RVDIS BIT(1) + +/* Bitfields in QSPI_WPMR (Write Protection Mode Register) */ +#define QSPI_WPMR_WPEN BIT(0) +#define QSPI_WPMR_WPKEY_MASK GENMASK(31, 8) +#define QSPI_WPMR_WPKEY(wpkey) (((wpkey) << 8) & QSPI_WPMR_WPKEY_MASK) + +/* Bitfields in QSPI_WPSR (Write Protection Status Register) */ +#define QSPI_WPSR_WPVS BIT(0) +#define QSPI_WPSR_WPVSRC_MASK GENMASK(15, 8) +#define QSPI_WPSR_WPVSRC(src) (((src) << 8) & QSPI_WPSR_WPVSRC) + +struct atmel_qspi_caps { + bool has_qspick; + bool has_ricr; +}; + +struct atmel_qspi { + struct spi_controller ctlr; + void __iomem *regs; + void __iomem *mem; + struct clk *pclk; + struct clk *qspick; + struct platform_device *pdev; + const struct atmel_qspi_caps *caps; + u32 mr; +}; + +struct atmel_qspi_mode { + u8 cmd_buswidth; + u8 addr_buswidth; + u8 data_buswidth; + u32 config; +}; + +static const struct atmel_qspi_mode atmel_qspi_modes[] = { + { 1, 1, 1, QSPI_IFR_WIDTH_SINGLE_BIT_SPI }, + { 1, 1, 2, QSPI_IFR_WIDTH_DUAL_OUTPUT }, + { 1, 1, 4, QSPI_IFR_WIDTH_QUAD_OUTPUT }, + { 1, 2, 2, QSPI_IFR_WIDTH_DUAL_IO }, + { 1, 4, 4, QSPI_IFR_WIDTH_QUAD_IO }, + { 2, 2, 2, QSPI_IFR_WIDTH_DUAL_CMD }, + { 4, 4, 4, QSPI_IFR_WIDTH_QUAD_CMD }, +}; + +static inline bool atmel_qspi_is_compatible(const struct spi_mem_op *op, + const struct atmel_qspi_mode *mode) +{ + if (op->cmd.buswidth != mode->cmd_buswidth) + return false; + + if (op->addr.nbytes && op->addr.buswidth != mode->addr_buswidth) + return false; + + if (op->data.nbytes && op->data.buswidth != mode->data_buswidth) + return false; + + return true; +} + +static int atmel_qspi_find_mode(const struct spi_mem_op *op) +{ + u32 i; + + for (i = 0; i < ARRAY_SIZE(atmel_qspi_modes); i++) + if (atmel_qspi_is_compatible(op, &atmel_qspi_modes[i])) + return i; + + return -ENOTSUPP; +} + +static bool atmel_qspi_supports_op(struct spi_mem *mem, + const struct spi_mem_op *op) +{ + if (atmel_qspi_find_mode(op) < 0) + return false; + + /* special case not supported by hardware */ + if (op->addr.nbytes == 2 && op->cmd.buswidth != op->addr.buswidth && + op->dummy.nbytes == 0) + return false; + + return true; +} + +static int atmel_qspi_set_cfg(struct atmel_qspi *aq, + const struct spi_mem_op *op, u32 *offset) +{ + u32 iar, icr, ifr; + u32 dummy_cycles = 0; + int mode; + + iar = 0; + icr = QSPI_ICR_INST(op->cmd.opcode); + ifr = QSPI_IFR_INSTEN; + + mode = atmel_qspi_find_mode(op); + if (mode < 0) + return mode; + ifr |= atmel_qspi_modes[mode].config; + + if (op->dummy.buswidth && op->dummy.nbytes) + dummy_cycles = op->dummy.nbytes * 8 / op->dummy.buswidth; + + /* + * The controller allows 24 and 32-bit addressing while NAND-flash + * requires 16-bit long. Handling 8-bit long addresses is done using + * the option field. For the 16-bit addresses, the workaround depends + * of the number of requested dummy bits. If there are 8 or more dummy + * cycles, the address is shifted and sent with the first dummy byte. + * Otherwise opcode is disabled and the first byte of the address + * contains the command opcode (works only if the opcode and address + * use the same buswidth). The limitation is when the 16-bit address is + * used without enough dummy cycles and the opcode is using a different + * buswidth than the address. + */ + if (op->addr.buswidth) { + switch (op->addr.nbytes) { + case 0: + break; + case 1: + ifr |= QSPI_IFR_OPTEN | QSPI_IFR_OPTL_8BIT; + icr |= QSPI_ICR_OPT(op->addr.val & 0xff); + break; + case 2: + if (dummy_cycles < 8 / op->addr.buswidth) { + ifr &= ~QSPI_IFR_INSTEN; + ifr |= QSPI_IFR_ADDREN; + iar = (op->cmd.opcode << 16) | + (op->addr.val & 0xffff); + } else { + ifr |= QSPI_IFR_ADDREN; + iar = (op->addr.val << 8) & 0xffffff; + dummy_cycles -= 8 / op->addr.buswidth; + } + break; + case 3: + ifr |= QSPI_IFR_ADDREN; + iar = op->addr.val & 0xffffff; + break; + case 4: + ifr |= QSPI_IFR_ADDREN | QSPI_IFR_ADDRL; + iar = op->addr.val & 0x7ffffff; + break; + default: + return -ENOTSUPP; + } + } + + /* offset of the data access in the QSPI memory space */ + *offset = iar; + + /* Set number of dummy cycles */ + if (dummy_cycles) + ifr |= QSPI_IFR_NBDUM(dummy_cycles); + + /* Set data enable */ + if (op->data.nbytes) + ifr |= QSPI_IFR_DATAEN; + + /* + * If the QSPI controller is set in regular SPI mode, set it in + * Serial Memory Mode (SMM). + */ + if (aq->mr != QSPI_MR_SMM) { + writel_relaxed(QSPI_MR_SMM, aq->regs + QSPI_MR); + aq->mr = QSPI_MR_SMM; + } + + /* Clear pending interrupts */ + (void)readl_relaxed(aq->regs + QSPI_SR); + + if (aq->caps->has_ricr) { + if (!op->addr.nbytes && op->data.dir == SPI_MEM_DATA_IN) + ifr |= QSPI_IFR_APBTFRTYP_READ; + + /* Set QSPI Instruction Frame registers */ + writel_relaxed(iar, aq->regs + QSPI_IAR); + if (op->data.dir == SPI_MEM_DATA_IN) + writel_relaxed(icr, aq->regs + QSPI_RICR); + else + writel_relaxed(icr, aq->regs + QSPI_WICR); + writel_relaxed(ifr, aq->regs + QSPI_IFR); + } else { + if (op->data.dir == SPI_MEM_DATA_OUT) + ifr |= QSPI_IFR_SAMA5D2_WRITE_TRSFR; + + /* Set QSPI Instruction Frame registers */ + writel_relaxed(iar, aq->regs + QSPI_IAR); + writel_relaxed(icr, aq->regs + QSPI_ICR); + writel_relaxed(ifr, aq->regs + QSPI_IFR); + } + + return 0; +} + +static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) +{ + struct atmel_qspi *aq = spi_controller_get_devdata(mem->spi->controller); + u32 sr, imr, offset; + int err; + + err = atmel_qspi_set_cfg(aq, op, &offset); + if (err) + return err; + + /* Skip to the final steps if there is no data */ + if (op->data.nbytes) { + /* Dummy read of QSPI_IFR to synchronize APB and AHB accesses */ + (void)readl_relaxed(aq->regs + QSPI_IFR); + + /* Send/Receive data */ + if (op->data.dir == SPI_MEM_DATA_IN) + memcpy_fromio(op->data.buf.in, aq->mem + offset, + op->data.nbytes); + else + memcpy_toio(aq->mem + offset, op->data.buf.out, + op->data.nbytes); + + /* Release the chip-select */ + writel_relaxed(QSPI_CR_LASTXFER, aq->regs + QSPI_CR); + } + + /* Poll INSTruction End and Chip Select Rise flags. */ + imr = QSPI_SR_CMD_COMPLETED; + return readl_poll_timeout(aq->regs + QSPI_SR, sr, (sr & imr) == imr, + 1000000); +} + +static const char *atmel_qspi_get_name(struct spi_mem *mem) +{ + return dev_name(&mem->spi->dev); +} + +static const struct spi_controller_mem_ops atmel_qspi_mem_ops = { + .supports_op = atmel_qspi_supports_op, + .exec_op = atmel_qspi_exec_op, + .get_name = atmel_qspi_get_name +}; + +static int atmel_qspi_setup(struct spi_device *spi) +{ + struct atmel_qspi *aq = container_of(spi->controller, struct atmel_qspi, + ctlr); + unsigned long src_rate; + u32 scr, scbr; + + if (!spi->max_speed_hz) + return -EINVAL; + + src_rate = clk_get_rate(aq->pclk); + if (!src_rate) + return -EINVAL; + + /* Compute the QSPI baudrate */ + scbr = DIV_ROUND_UP(src_rate, spi->max_speed_hz); + if (scbr > 0) + scbr--; + + scr = QSPI_SCR_SCBR(scbr); + writel_relaxed(scr, aq->regs + QSPI_SCR); + + return 0; +} + +static int atmel_qspi_init(struct atmel_qspi *aq) +{ + /* Reset the QSPI controller */ + writel_relaxed(QSPI_CR_SWRST, aq->regs + QSPI_CR); + + /* Set the QSPI controller by default in Serial Memory Mode */ + writel_relaxed(QSPI_MR_SMM, aq->regs + QSPI_MR); + aq->mr = QSPI_MR_SMM; + + /* Enable the QSPI controller */ + writel_relaxed(QSPI_CR_QSPIEN, aq->regs + QSPI_CR); + + return 0; +} + +static int atmel_qspi_probe(struct device_d *dev) +{ + struct spi_controller *ctrl; + struct atmel_qspi *aq; + int err = 0; + + aq = xzalloc(sizeof(*aq)); + ctrl = &aq->ctlr; + + /* ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD | SPI_TX_DUAL | SPI_TX_QUAD; */ + + ctrl->dev = dev; + ctrl->setup = atmel_qspi_setup; + ctrl->bus_num = -1; + ctrl->mem_ops = &atmel_qspi_mem_ops; + ctrl->num_chipselect = 1; + + spi_controller_set_devdata(ctrl, aq); + + /* Map the registers */ + aq->regs = dev_request_mem_region_by_name(dev, "qspi_base"); + if (IS_ERR(aq->regs)) { + dev_err(dev, "missing registers\n"); + err = PTR_ERR(aq->regs); + goto exit; + } + + /* Map the AHB memory */ + aq->mem = dev_request_mem_region_by_name(dev, "qspi_mmap"); + if (IS_ERR(aq->mem)) { + dev_err(dev, "missing AHB memory\n"); + err = PTR_ERR(aq->mem); + goto exit; + } + + /* Get the peripheral clock */ + aq->pclk = clk_get(dev, "pclk"); + if (IS_ERR(aq->pclk)) + aq->pclk = clk_get(dev, NULL); + + if (IS_ERR(aq->pclk)) { + dev_err(dev, "missing peripheral clock\n"); + err = PTR_ERR(aq->pclk); + goto exit; + } + + /* Enable the peripheral clock */ + err = clk_enable(aq->pclk); + if (err) { + dev_err(dev, "failed to enable the peripheral clock\n"); + goto exit; + } + + aq->caps = of_device_get_match_data(dev); + if (!aq->caps) { + dev_err(dev, "Could not retrieve QSPI caps\n"); + err = -EINVAL; + goto exit; + } + + if (aq->caps->has_qspick) { + /* Get the QSPI system clock */ + aq->qspick = clk_get(dev, "qspick"); + if (IS_ERR(aq->qspick)) { + dev_err(dev, "missing system clock\n"); + err = PTR_ERR(aq->qspick); + goto disable_pclk; + } + + /* Enable the QSPI system clock */ + err = clk_enable(aq->qspick); + if (err) { + dev_err(dev, "failed to enable the QSPI system clock\n"); + goto disable_pclk; + } + } + + err = atmel_qspi_init(aq); + if (err) + goto disable_qspick; + + err = spi_register_controller(ctrl); + if (err) + goto disable_qspick; + + return 0; + +disable_qspick: + clk_disable(aq->qspick); +disable_pclk: + clk_disable(aq->pclk); +exit: + return err; +} + +static const struct atmel_qspi_caps atmel_sama5d2_qspi_caps = {}; + +static const struct atmel_qspi_caps atmel_sam9x60_qspi_caps = { + .has_qspick = true, + .has_ricr = true, +}; + +static const struct of_device_id atmel_qspi_dt_ids[] = { + { + .compatible = "atmel,sama5d2-qspi", + .data = &atmel_sama5d2_qspi_caps, + }, + { + .compatible = "microchip,sam9x60-qspi", + .data = &atmel_sam9x60_qspi_caps, + }, + { /* sentinel */ } +}; + +static struct driver_d atmel_qspi_driver = { + .name = "atmel_qspi", + .of_compatible = atmel_qspi_dt_ids, + .probe = atmel_qspi_probe, +}; +device_platform_driver(atmel_qspi_driver); diff --git a/drivers/usb/gadget/fsl_udc.c b/drivers/usb/gadget/fsl_udc.c index a47ba20f46..a44c7abc01 100644 --- a/drivers/usb/gadget/fsl_udc.c +++ b/drivers/usb/gadget/fsl_udc.c @@ -1422,8 +1422,7 @@ static void udc_reset_ep_queue(struct fsl_udc *udc, u8 pipe) { struct fsl_ep *ep = get_ep_by_pipe(udc, pipe); - if (ep->name) - nuke(ep, -ESHUTDOWN); + nuke(ep, -ESHUTDOWN); } /* Clear up all ep queues */ @@ -1914,12 +1913,6 @@ static void dtd_complete_irq(struct fsl_udc *udc) curr_ep = get_ep_by_pipe(udc, i); - /* If the ep is configured */ - if (curr_ep->name == NULL) { - WARNING("Invalid EP?"); - continue; - } - /* process the req queue until an uncomplete request */ list_for_each_entry_safe(curr_req, temp_req, &curr_ep->queue, queue) { diff --git a/drivers/video/stm.c b/drivers/video/stm.c index 0c190d36ae..d4a618fe50 100644 --- a/drivers/video/stm.c +++ b/drivers/video/stm.c @@ -551,9 +551,9 @@ static int stmfb_probe(struct device_d *hw_dev) } modes = of_get_display_timings(display); - if (IS_ERR(modes)) { + if (!modes) { dev_err(hw_dev, "unable to parse display timings\n"); - return PTR_ERR(modes); + return -EINVAL; } fbi.info.modes.modes = modes->modes; |