summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/bus/omap-gpmc.c3
-rw-r--r--drivers/clk/zynqmp/clk-mux-zynqmp.c4
-rw-r--r--drivers/eeprom/Kconfig1
-rw-r--r--drivers/i2c/muxes/i2c-mux-pca954x.c13
-rw-r--r--drivers/input/Kconfig6
-rw-r--r--drivers/input/Makefile1
-rw-r--r--drivers/input/specialkeys.c36
-rw-r--r--drivers/mfd/rave-sp.c18
-rw-r--r--drivers/mtd/nand/Kconfig10
-rw-r--r--drivers/mtd/nand/Makefile1
-rw-r--r--drivers/mtd/nand/atmel_nand.c40
-rw-r--r--drivers/mtd/nand/denali.h1
-rw-r--r--drivers/mtd/nand/nand_base.c72
-rw-r--r--drivers/mtd/nand/nand_bbt.c32
-rw-r--r--drivers/mtd/nand/nand_bch.c6
-rw-r--r--drivers/mtd/nand/nand_denali.c139
-rw-r--r--drivers/mtd/nand/nand_imx.c28
-rw-r--r--drivers/mtd/nand/nand_imx_bbm.c4
-rw-r--r--drivers/mtd/nand/nand_mrvl_nfc.c20
-rw-r--r--drivers/mtd/nand/nand_mxs.c34
-rw-r--r--drivers/mtd/nand/nand_omap_gpmc.c348
-rw-r--r--drivers/mtd/nand/nand_orion.c8
-rw-r--r--drivers/mtd/nand/nand_s3c24xx.c18
-rw-r--r--drivers/mtd/nand/nomadik_nand.c10
-rw-r--r--drivers/mtd/nand/omap_elm.c413
-rw-r--r--drivers/mtd/peb.c84
-rw-r--r--drivers/mtd/spi-nor/spi-nor.c57
-rw-r--r--drivers/net/cpsw.c178
-rw-r--r--drivers/net/macb.c33
-rw-r--r--drivers/net/macb.h7
-rw-r--r--drivers/net/phy/mv88e6xxx/chip.c1
-rw-r--r--drivers/net/smc911x.c2
-rw-r--r--drivers/nvme/host/core.c4
-rw-r--r--drivers/serial/atmel.c1
-rw-r--r--drivers/serial/efi-stdio.c5
-rw-r--r--drivers/serial/serial_efi.c5
-rw-r--r--drivers/serial/serial_stm32.c1
-rw-r--r--drivers/spi/Kconfig9
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/atmel-quadspi.c541
-rw-r--r--drivers/usb/gadget/fsl_udc.c9
-rw-r--r--drivers/video/stm.c4
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(&notifier);
+}
+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(&params->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;