From bruce.mullins at emerylehman.com  Sat Oct  1 01:10:17 2016
From: bruce.mullins at emerylehman.com (FedEx 2Day)
Date: Sat, 1 Oct 2016 08:10:17 +0000
Subject: Delivery Notification, ID 00394204
Message-ID: <791d71e4facda89127568e5c7f28e798@emerylehman.com>

Dear Customer,

We could not deliver your parcel.
Shipment Label is attached to this email.

Yours sincerely,
Bruce Mullins,
Sr. Station Manager.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: Delivery_Notification_00394204.zip
Type: application/zip
Size: 5273 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20161001/2de2e48a/attachment.zip>

From boris.brezillon at free-electrons.com  Sat Oct  1 01:24:03 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Sat,  1 Oct 2016 10:24:03 +0200
Subject: [PATCH 2/2] mtd: nand: Wait tCCS after a column change
In-Reply-To: <1475310243-32625-1-git-send-email-boris.brezillon@free-electrons.com>
References: <1475310243-32625-1-git-send-email-boris.brezillon@free-electrons.com>
Message-ID: <1475310243-32625-3-git-send-email-boris.brezillon@free-electrons.com>

Drivers implementing ->cmd_ctrl() and relying on the default ->cmdfunc()
implementation usually don't wait tCCS when a column change (RNDIN or
RNDOUT) is requested.
Add an option flag to ask the core to do so (note that we keep this as
an opt-in to avoid breaking existing implementations), and make use of
the ->data_interface information is available (otherwise, wait 500ns).

Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/nand_base.c | 26 +++++++++++++++++++++++++-
 include/linux/mtd/nand.h     | 10 ++++++++++
 2 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 7a00245ebada..3b0e6d861e2e 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -709,6 +709,25 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
 	nand_wait_ready(mtd);
 }
 
+static void nand_ccs_delay(struct nand_chip *chip)
+{
+	/*
+	 * The controller already takes care of waiting for tCCS when the RNDIN
+	 * or RNDOUT command is sent, return directly.
+	 */
+	if (!(chip->options & NAND_WAIT_TCCS))
+		return;
+
+	/*
+	 * Wait tCCS_min if it is correctly defined, otherwise wait 500ns
+	 * (which should be safe for all NANDs).
+	 */
+	if (chip->data_interface && chip->data_interface->timings.sdr.tCCS_min)
+		ndelay(chip->data_interface->timings.sdr.tCCS_min / 1000);
+	else
+		ndelay(500);
+}
+
 /**
  * nand_command_lp - [DEFAULT] Send command to NAND large page device
  * @mtd: MTD device structure
@@ -773,10 +792,13 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
 	case NAND_CMD_ERASE1:
 	case NAND_CMD_ERASE2:
 	case NAND_CMD_SEQIN:
-	case NAND_CMD_RNDIN:
 	case NAND_CMD_STATUS:
 		return;
 
+	case NAND_CMD_RNDIN:
+		nand_ccs_delay(chip);
+		return;
+
 	case NAND_CMD_RESET:
 		if (chip->dev_ready)
 			break;
@@ -795,6 +817,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
 			       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
 		chip->cmd_ctrl(mtd, NAND_CMD_NONE,
 			       NAND_NCE | NAND_CTRL_CHANGE);
+
+		nand_ccs_delay(chip);
 		return;
 
 	case NAND_CMD_READ0:
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 6fe83bce83a6..970ceb948835 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -210,6 +210,16 @@ enum nand_ecc_algo {
  */
 #define NAND_USE_BOUNCE_BUFFER	0x00100000
 
+/*
+ * In case your controller is implementing ->cmd_ctrl() and is relying on the
+ * default ->cmdfunc() implementation, you may want to let the core handle the
+ * tCCS delay which is required when a column change (RNDIN or RNDOUT) is
+ * requested.
+ * If your controller already takes care of this delay, you don't need to set
+ * this flag.
+ */
+#define NAND_WAIT_TCCS		0x00200000
+
 /* Options set by nand scan */
 /* Nand scan has allocated controller struct */
 #define NAND_CONTROLLER_ALLOC	0x80000000
-- 
2.7.4



From boris.brezillon at free-electrons.com  Sat Oct  1 01:24:01 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Sat,  1 Oct 2016 10:24:01 +0200
Subject: [PATCH 0/2] mtd: nand: Enforce tCCS wait time after a column change
Message-ID: <1475310243-32625-1-git-send-email-boris.brezillon@free-electrons.com>

Hi,

Marc recently struggled with the RNDIN/RNDOUT commands when trying to
add support for the Tango NAND controller.
After some investigation it appeared that nothing in the
nand_command_lp() code waits tCCS, which is required to make sure the
NAND chip is ready to receive/send data on the bus after a column
change.

This series adds some more timings to the nand_sdr_timings struct
(including tCCS) and try to extract them from the ONFI parameter table
(if available).

It then adds a new flags to ask the core to enforce the tCCS
constraint.
As noted in the commit message, this is an opt-in flag to avoid perf
regressions on existing implementations (adding an ndelay() might be
useless if the controller IP or driver already takes care of that),
but it might appear that some implementations are actually broken and
needs this flag as well.

Regards,

Boris

Boris Brezillon (2):
  mtd: nand: Add a few more timings to nand_sdr_timings
  mtd: nand: Wait tCCS after a column change

 drivers/mtd/nand/nand_base.c    | 26 +++++++++++++++++++++++++-
 drivers/mtd/nand/nand_timings.c | 26 +++++++++++++++++++++++++-
 include/linux/mtd/nand.h        | 18 ++++++++++++++++++
 3 files changed, 68 insertions(+), 2 deletions(-)

-- 
2.7.4



From boris.brezillon at free-electrons.com  Sat Oct  1 01:24:02 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Sat,  1 Oct 2016 10:24:02 +0200
Subject: [PATCH 1/2] mtd: nand: Add a few more timings to nand_sdr_timings
In-Reply-To: <1475310243-32625-1-git-send-email-boris.brezillon@free-electrons.com>
References: <1475310243-32625-1-git-send-email-boris.brezillon@free-electrons.com>
Message-ID: <1475310243-32625-2-git-send-email-boris.brezillon@free-electrons.com>

Add the tR_max, tBERS_max, tPROG_max and tCCS_min timings to the
nand_sdr_timings struct.
Assign default/safe values for the statically defined timings, and
extract them from the ONFI parameter table if the NAND is ONFI
compliant.

Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/nand_timings.c | 26 +++++++++++++++++++++++++-
 include/linux/mtd/nand.h        |  8 ++++++++
 2 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/nand_timings.c
index 13a587407be3..f06312df3669 100644
--- a/drivers/mtd/nand/nand_timings.c
+++ b/drivers/mtd/nand/nand_timings.c
@@ -18,6 +18,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
 	{
 		.type = NAND_SDR_IFACE,
 		.timings.sdr = {
+			.tCCS_min = 500000,
+			.tR_max = 200000000,
 			.tADL_min = 400000,
 			.tALH_min = 20000,
 			.tALS_min = 50000,
@@ -58,6 +60,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
 	{
 		.type = NAND_SDR_IFACE,
 		.timings.sdr = {
+			.tCCS_min = 500000,
+			.tR_max = 200000000,
 			.tADL_min = 400000,
 			.tALH_min = 10000,
 			.tALS_min = 25000,
@@ -98,6 +102,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
 	{
 		.type = NAND_SDR_IFACE,
 		.timings.sdr = {
+			.tCCS_min = 500000,
+			.tR_max = 200000000,
 			.tADL_min = 400000,
 			.tALH_min = 10000,
 			.tALS_min = 15000,
@@ -138,6 +144,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
 	{
 		.type = NAND_SDR_IFACE,
 		.timings.sdr = {
+			.tCCS_min = 500000,
+			.tR_max = 200000000,
 			.tADL_min = 400000,
 			.tALH_min = 5000,
 			.tALS_min = 10000,
@@ -178,6 +186,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
 	{
 		.type = NAND_SDR_IFACE,
 		.timings.sdr = {
+			.tCCS_min = 500000,
+			.tR_max = 200000000,
 			.tADL_min = 400000,
 			.tALH_min = 5000,
 			.tALS_min = 10000,
@@ -218,6 +228,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
 	{
 		.type = NAND_SDR_IFACE,
 		.timings.sdr = {
+			.tCCS_min = 500000,
+			.tR_max = 200000000,
 			.tADL_min = 400000,
 			.tALH_min = 5000,
 			.tALS_min = 10000,
@@ -290,10 +302,22 @@ int onfi_init_data_interface(struct nand_chip *chip,
 	*iface = onfi_sdr_timings[timing_mode];
 
 	/*
-	 * TODO: initialize timings that cannot be deduced from timing mode:
+	 * Initialize timings that cannot be deduced from timing mode:
 	 * tR, tPROG, tCCS, ...
 	 * These information are part of the ONFI parameter page.
 	 */
+	if (chip->onfi_version) {
+		struct nand_onfi_params *params = &chip->onfi_params;
+		struct nand_sdr_timings *timings = &iface->timings.sdr;
+
+		/* microseconds -> picoseconds */
+		timings->tPROG_max = 1000000UL * le16_to_cpu(params->t_prog);
+		timings->tBERS_max = 1000000UL * le16_to_cpu(params->t_bers);
+		timings->tR_max = 1000000UL * le16_to_cpu(params->t_r);
+
+		/* nanoseconds -> picoseconds */
+		timings->tCCS_min = 1000UL * le16_to_cpu(params->t_ccs);
+	}
 
 	return 0;
 }
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index c5d3d5024fc8..6fe83bce83a6 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -584,6 +584,10 @@ struct nand_buffers {
  *
  * All these timings are expressed in picoseconds.
  *
+ * @tBERS_max: Block erase time
+ * @tCCS_min: Change column setup time
+ * @tPROG_max: Page program time
+ * @tR_max: Page read time
  * @tALH_min: ALE hold time
  * @tADL_min: ALE to data loading time
  * @tALS_min: ALE setup time
@@ -621,6 +625,10 @@ struct nand_buffers {
  * @tWW_min: WP# transition to WE# low
  */
 struct nand_sdr_timings {
+	u32 tBERS_max;
+	u32 tCCS_min;
+	u32 tPROG_max;
+	u32 tR_max;
 	u32 tALH_min;
 	u32 tADL_min;
 	u32 tALS_min;
-- 
2.7.4



From boris.brezillon at free-electrons.com  Sat Oct  1 02:25:05 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Sat, 1 Oct 2016 11:25:05 +0200
Subject: [PATCH] mtd: mtk: avoid warning in mtk_ecc_encode
In-Reply-To: <201609301925.17577.arnd@arndb.de>
References: <20160930163429.380785-1-arnd@arndb.de>
 <20160930185139.15c8be66@bbrezillon>
 <201609301925.17577.arnd@arndb.de>
Message-ID: <20161001112505.5f391ee6@bbrezillon>

On Fri, 30 Sep 2016 19:25:17 +0200
Arnd Bergmann <arnd at arndb.de> wrote:

> On Friday 30 September 2016, Boris Brezillon wrote:
> > > +     /* copy into possibly unaligned OOB region with actual length */
> > > +     memcpy(data + bytes, eccdata, len);  
> > 
> > Is it better than
> > 
> >         for (i = 0; i < len; i += 4) {
> >                 u32 val = __raw_readl(ecc->regs + ECC_ENCPAR(i / 4));
> > 
> >                 memcpy(data + bytes + i, &val, min(len, 4));
> >         }
> > 
> > I'm probably missing something, but what's the point of creating a
> > temporary buffer of 112 bytes on the stack since you'll have to copy
> > this data to the oob buffer at some point?  
> 
> 
> I tried something like that first, but wasn't too happy with it for
> a number of small reasons:
> 
> - __raw_readl in a driver is not usually the right API, __memcpy32_from_io
>   uses it internally, but it's better for a driver not to rely on that,
>   in case we need some barriers (which we may in factt need for other drivers).

I agree, even though calling something prefixed with __ (in this case,
__ioread32_copy()) sounds like a bad thing too :).

> 
> - the min(len,4) expression is incorrect, fixing that makes it more complicated
>   again

Sorry, it's min(len - i, 4), which is not that complicated :P.

> 
> - I didn't like to call memcpy() multiple times, as that might get turned
>   into an external function call (the compiler is free to optimize small
>   memcpy calls or not).

Okay.

> 
> I agree that he 112 byte buffer isn't ideal either, it just seemed to
> be the lesser annoyance.

How about we keep your approach, but put the buffer in the mtk_ecc
struct?



From Julia.Lawall at lip6.fr  Sat Oct  1 12:46:18 2016
From: Julia.Lawall at lip6.fr (Julia Lawall)
Date: Sat,  1 Oct 2016 21:46:18 +0200
Subject: [PATCH 01/15] UBIFS: improve function-level documentation
In-Reply-To: <1475351192-27079-1-git-send-email-Julia.Lawall@lip6.fr>
References: <1475351192-27079-1-git-send-email-Julia.Lawall@lip6.fr>
Message-ID: <1475351192-27079-2-git-send-email-Julia.Lawall@lip6.fr>

Fix various inconsistencies in the documentation associated with various
functions.

In the case of fs/ubifs/lprops.c, the second parameter of
ubifs_get_lp_stats was renamed from st to lst in 84abf972.

In the case of fs/ubifs/lpt_commit.c, the excess variables have never
existed in the associated functions since the code was introduced into the
kernel.

The others appear to be straightforward typos.

Issues detected using Coccinelle (http://coccinelle.lip6.fr/)

Signed-off-by: Julia Lawall <Julia.Lawall at lip6.fr>

---
 fs/ubifs/file.c       |    2 +-
 fs/ubifs/gc.c         |    2 +-
 fs/ubifs/lprops.c     |    2 +-
 fs/ubifs/lpt_commit.c |    4 +---
 fs/ubifs/replay.c     |    2 +-
 5 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index b0a6a53..629c719 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -1397,7 +1397,7 @@ int ubifs_update_time(struct inode *inode, struct timespec *time,
 #endif
 
 /**
- * update_ctime - update mtime and ctime of an inode.
+ * update_mctime - update mtime and ctime of an inode.
  * @inode: inode to update
  *
  * This function updates mtime and ctime of the inode if it is not equivalent to
diff --git a/fs/ubifs/gc.c b/fs/ubifs/gc.c
index 821b348..e845c64 100644
--- a/fs/ubifs/gc.c
+++ b/fs/ubifs/gc.c
@@ -113,7 +113,7 @@ static int switch_gc_head(struct ubifs_info *c)
  * data_nodes_cmp - compare 2 data nodes.
  * @priv: UBIFS file-system description object
  * @a: first data node
- * @a: second data node
+ * @b: second data node
  *
  * This function compares data nodes @a and @b. Returns %1 if @a has greater
  * inode or block number, and %-1 otherwise.
diff --git a/fs/ubifs/lprops.c b/fs/ubifs/lprops.c
index a0011aa..6c3a1ab 100644
--- a/fs/ubifs/lprops.c
+++ b/fs/ubifs/lprops.c
@@ -636,7 +636,7 @@ const struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c,
 /**
  * ubifs_get_lp_stats - get lprops statistics.
  * @c: UBIFS file-system description object
- * @st: return statistics
+ * @lst: return statistics
  */
 void ubifs_get_lp_stats(struct ubifs_info *c, struct ubifs_lp_stats *lst)
 {
diff --git a/fs/ubifs/lpt_commit.c b/fs/ubifs/lpt_commit.c
index ce89bdc..235654c 100644
--- a/fs/ubifs/lpt_commit.c
+++ b/fs/ubifs/lpt_commit.c
@@ -34,7 +34,6 @@
 
 /**
  * first_dirty_cnode - find first dirty cnode.
- * @c: UBIFS file-system description object
  * @nnode: nnode at which to start
  *
  * This function returns the first dirty cnode or %NULL if there is not one.
@@ -1623,7 +1622,6 @@ static int dbg_is_node_dirty(struct ubifs_info *c, int node_type, int lnum,
  * dbg_check_ltab_lnum - check the ltab for a LPT LEB number.
  * @c: the UBIFS file-system description object
  * @lnum: LEB number where node was written
- * @offs: offset where node was written
  *
  * This function returns %0 on success and a negative error code on failure.
  */
@@ -1870,7 +1868,7 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)
 }
 
 /**
- * ubifs_dump_lpt_leb - dump an LPT LEB.
+ * dump_lpt_leb - dump an LPT LEB.
  * @c: UBIFS file-system description object
  * @lnum: LEB number to dump
  *
diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
index 3ca4540..fb0f44c 100644
--- a/fs/ubifs/replay.c
+++ b/fs/ubifs/replay.c
@@ -267,7 +267,7 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
  * replay_entries_cmp - compare 2 replay entries.
  * @priv: UBIFS file-system description object
  * @a: first replay entry
- * @a: second replay entry
+ * @b: second replay entry
  *
  * This is a comparios function for 'list_sort()' which compares 2 replay
  * entries @a and @b by comparing their sequence numer.  Returns %1 if @a has



From Julia.Lawall at lip6.fr  Sat Oct  1 12:46:17 2016
From: Julia.Lawall at lip6.fr (Julia Lawall)
Date: Sat,  1 Oct 2016 21:46:17 +0200
Subject: [PATCH 00/15] improve function-level documentation
Message-ID: <1475351192-27079-1-git-send-email-Julia.Lawall@lip6.fr>

These patches fix cases where the documentation above a function definition
is not consistent with the function header.  Issues are detected using the
semantic patch below (http://coccinelle.lip6.fr/).  Basically, the semantic
patch parses a file to find comments, then matches each function header,
and checks that the name and parameter list in the function header are
compatible with the comment that preceeds it most closely.

// <smpl>
@initialize:ocaml@
@@

let tbl = ref []
let fnstart = ref []
let success = Hashtbl.create 101
let thefile = ref ""
let parsed = ref []
let nea = ref []

let parse file =
  thefile := List.nth (Str.split (Str.regexp "linux-next/") file) 1;
  let i = open_in file in
  let startline = ref 0 in
  let fn = ref "" in
  let ids = ref [] in
  let rec inside n =
    let l = input_line i in
    let n = n + 1 in
    match Str.split_delim (Str.regexp_string "*/") l with
      before::after::_ ->
	(if not (!fn = "")
	then tbl := (!startline,n,!fn,List.rev !ids)::!tbl);
	startline := 0;
	fn := "";
	ids := [];
	outside n
    | _ ->
	(match Str.split (Str.regexp "[ \t]+") l with
	  "*"::name::rest ->
	    let len = String.length name in
	    (if !fn = "" && len > 2 && String.sub name (len-2) 2 = "()"
	    then fn := String.sub name 0 (len-2)
	    else if !fn = "" && (not (rest = [])) && List.hd rest = "-"
	    then
	      if String.get name (len-1) = ':'
	      then fn := String.sub name 0 (len-1)
	      else fn := name
	    else if not(!fn = "") && len > 2 &&
	      String.get name 0 = '@' && String.get name (len-1) = ':'
	    then ids := (String.sub name 1 (len-2)) :: !ids);
	| _ -> ());
	inside n
  and outside n =
    let l = input_line i in
    let n = n + 1 in
    if String.length l > 2 && String.sub l 0 3 = "/**"
    then
      begin
	startline := n;
	inside n
      end
    else outside n in
  try outside 0 with End_of_file -> ()

let hashadd tbl k v =
  let cell =
    try Hashtbl.find tbl k
    with Not_found ->
      let cell = ref [] in
      Hashtbl.add tbl k cell;
      cell in
  cell := v :: !cell

@script:ocaml@
@@

tbl := [];
fnstart := [];
Hashtbl.clear success;
parsed := [];
nea := [];
parse (List.hd (Coccilib.files()))

@r@
identifier f;
position p;
@@

f at p(...) { ... }

@script:ocaml@
p << r.p;
f << r.f;
@@

parsed := f :: !parsed;
fnstart := (List.hd p).line :: !fnstart

@param@
identifier f;
type T;
identifier i;
parameter list[n] ps;
parameter list[n1] ps1;
position p;
@@

f at p(ps,T i,ps1) { ... }

@script:ocaml@
@@

tbl := List.rev (List.sort compare !tbl)

@script:ocaml@
p << param.p;
f << param.f;
@@

let myline = (List.hd p).line in
let prevline =
  List.fold_left
    (fun prev x ->
      if x < myline
      then max x prev
      else prev)
    0 !fnstart in
let _ =
  List.exists
    (function (st,fn,nm,ids) ->
      if prevline < st && myline > st && prevline < fn && myline > fn
      then
	begin
	  (if not (String.lowercase f = String.lowercase nm)
	  then
	    Printf.printf "%s:%d %s doesn't match preceding comment: %s\n"
	      !thefile myline f nm);
	  true
	end
      else false)
    !tbl in
()

@script:ocaml@
p << param.p;
n << param.n;
n1 << param.n1;
i << param.i;
f << param.f;
@@

let myline = (List.hd p).line in
let prevline =
  List.fold_left
    (fun prev x ->
      if x < myline
      then max x prev
      else prev)
    0 !fnstart in
let _ =
  List.exists
    (function (st,fn,nm,ids) ->
      if prevline < st && myline > st && prevline < fn && myline > fn
      then
	begin
	  (if List.mem i ids then hashadd success (st,fn,nm) i);
	  (if ids = [] (* arg list seems not obligatory *)
	  then ()
	  else if not (List.mem i ids)
	  then
	    Printf.printf "%s:%d %s doesn't appear in ids: %s\n"
	      !thefile myline i (String.concat " " ids)
	  else if List.length ids <= n || List.length ids <= n1
	  then
	    (if not (List.mem f !nea)
	    then
	      begin
		nea := f :: !nea;
		Printf.printf "%s:%d %s not enough args\n" !thefile myline f;
	      end)
	  else
	    let foundid = List.nth ids n in
	    let efoundid = List.nth (List.rev ids) n1 in
	    if not(foundid = i || efoundid = i)
	    then
	      Printf.printf "%s:%d %s wrong arg in position %d: %s\n"
		!thefile myline i n foundid);
	  true
	end
      else false)
    !tbl in
()

@script:ocaml@
@@
List.iter
  (function (st,fn,nm,ids) ->
    if List.mem nm !parsed
    then
      let entry =
	try !(Hashtbl.find success (st,fn,nm))
	with Not_found -> [] in
      List.iter
	(fun id ->
	  if not (List.mem id entry) && not (id = "...")
	  then Printf.printf "%s:%d %s not used\n" !thefile st id)
	ids)
  !tbl
// </smpl>


---

 drivers/clk/keystone/pll.c               |    4 ++--
 drivers/clk/sunxi/clk-mod0.c             |    2 +-
 drivers/clk/tegra/cvb.c                  |   10 +++++-----
 drivers/dma-buf/sw_sync.c                |    6 +++---
 drivers/gpu/drm/gma500/intel_i2c.c       |    3 +--
 drivers/gpu/drm/omapdrm/omap_drv.c       |    4 ++--
 drivers/irqchip/irq-metag-ext.c          |    1 -
 drivers/irqchip/irq-vic.c                |    1 -
 drivers/mfd/tc3589x.c                    |    4 ++--
 drivers/power/supply/ab8500_fg.c         |    8 ++++----
 drivers/power/supply/abx500_chargalg.c   |    1 +
 drivers/power/supply/intel_mid_battery.c |    2 +-
 drivers/power/supply/power_supply_core.c |    4 ++--
 fs/crypto/crypto.c                       |    4 ++--
 fs/crypto/fname.c                        |    4 ++--
 fs/ubifs/file.c                          |    2 +-
 fs/ubifs/gc.c                            |    2 +-
 fs/ubifs/lprops.c                        |    2 +-
 fs/ubifs/lpt_commit.c                    |    4 +---
 fs/ubifs/replay.c                        |    2 +-
 lib/kobject_uevent.c                     |    6 +++---
 lib/lru_cache.c                          |    4 ++--
 lib/nlattr.c                             |    2 +-
 23 files changed, 39 insertions(+), 43 deletions(-)


From joe at perches.com  Sat Oct  1 13:19:54 2016
From: joe at perches.com (Joe Perches)
Date: Sat, 01 Oct 2016 13:19:54 -0700
Subject: [PATCH 00/15] improve function-level documentation
In-Reply-To: <1475351192-27079-1-git-send-email-Julia.Lawall@lip6.fr>
References: <1475351192-27079-1-git-send-email-Julia.Lawall@lip6.fr>
Message-ID: <1475353194.1996.3.camel@perches.com>

On Sat, 2016-10-01 at 21:46 +0200, Julia Lawall wrote:
> These patches fix cases where the documentation above a function definition
> is not consistent with the function header.  Issues are detected using the
> semantic patch below (http://coccinelle.lip6.fr/).  Basically, the semantic
> patch parses a file to find comments, then matches each function header,
> and checks that the name and parameter list in the function header are
> compatible with the comment that preceeds it most closely.

Hi Julia.

Would it be possible for a semantic patch to scan for
function definitions where the types do not have
identifiers and update the definitions to match the
declarations?

For instance, given:

<some.h>
int foo(int);

<some.c>
int foo(int bar)
{
	return baz;
}

Could coccinelle output:

diff a/some.h b/some.h
[]
-int foo(int);
+int foo(int bar);


From julia.lawall at lip6.fr  Sat Oct  1 13:39:15 2016
From: julia.lawall at lip6.fr (Julia Lawall)
Date: Sat, 1 Oct 2016 22:39:15 +0200 (CEST)
Subject: [PATCH 00/15] improve function-level documentation
In-Reply-To: <1475353194.1996.3.camel@perches.com>
References: <1475351192-27079-1-git-send-email-Julia.Lawall@lip6.fr>
 <1475353194.1996.3.camel@perches.com>
Message-ID: <alpine.DEB.2.10.1610012232350.3445@hadrien>



On Sat, 1 Oct 2016, Joe Perches wrote:

> On Sat, 2016-10-01 at 21:46 +0200, Julia Lawall wrote:
> > These patches fix cases where the documentation above a function definition
> > is not consistent with the function header.  Issues are detected using the
> > semantic patch below (http://coccinelle.lip6.fr/).  Basically, the semantic
> > patch parses a file to find comments, then matches each function header,
> > and checks that the name and parameter list in the function header are
> > compatible with the comment that preceeds it most closely.
>
> Hi Julia.
>
> Would it be possible for a semantic patch to scan for
> function definitions where the types do not have
> identifiers and update the definitions to match the
> declarations?
>
> For instance, given:
>
> <some.h>
> int foo(int);
>
> <some.c>
> int foo(int bar)
> {
> 	return baz;
> }
>
> Could coccinelle output:
>
> diff a/some.h b/some.h
> []
> -int foo(int);
> +int foo(int bar);

The following seems to work:

@r@
identifier f;
position p;
type T, t;
parameter list[n] ps;
@@

T f at p(ps,t,...);

@s@
identifier r.f,x;
type r.T, r.t;
parameter list[r.n] ps;
@@

T f(ps,t x,...) { ... }

@@
identifier r.f, s.x;
position r.p;
type r.T, r.t;
parameter list[r.n] ps;
@@

T f at p(ps,t
+ x
  ,...);

After letting it run for a few minutes without making any effort to
include .h files, I get over 2700 changed lines.

julia


From julia.lawall at lip6.fr  Sat Oct  1 13:53:11 2016
From: julia.lawall at lip6.fr (Julia Lawall)
Date: Sat, 1 Oct 2016 22:53:11 +0200 (CEST)
Subject: [PATCH 01/15 v2] UBIFS: improve function-level documentation
Message-ID: <alpine.DEB.2.10.1610012252190.3445@hadrien>

Fix various inconsistencies in the documentation associated with various
functions.

In the case of fs/ubifs/lprops.c, the second parameter of
ubifs_get_lp_stats was renamed from st to lst in commit 84abf972ccff
("UBIFS: add re-mount debugging checks")

In the case of fs/ubifs/lpt_commit.c, the excess variables have never
existed in the associated functions since the code was introduced into the
kernel.

The others appear to be straightforward typos.

Issues detected using Coccinelle (http://coccinelle.lip6.fr/)

Signed-off-by: Julia Lawall <Julia.Lawall at lip6.fr>

---
v2: improve reference to earlier commit

 fs/ubifs/file.c       |    2 +-
 fs/ubifs/gc.c         |    2 +-
 fs/ubifs/lprops.c     |    2 +-
 fs/ubifs/lpt_commit.c |    4 +---
 fs/ubifs/replay.c     |    2 +-
 5 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index b0a6a53..629c719 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -1397,7 +1397,7 @@ int ubifs_update_time(struct inode *inode, struct timespec *time,
 #endif

 /**
- * update_ctime - update mtime and ctime of an inode.
+ * update_mctime - update mtime and ctime of an inode.
  * @inode: inode to update
  *
  * This function updates mtime and ctime of the inode if it is not equivalent to
diff --git a/fs/ubifs/gc.c b/fs/ubifs/gc.c
index 821b348..e845c64 100644
--- a/fs/ubifs/gc.c
+++ b/fs/ubifs/gc.c
@@ -113,7 +113,7 @@ static int switch_gc_head(struct ubifs_info *c)
  * data_nodes_cmp - compare 2 data nodes.
  * @priv: UBIFS file-system description object
  * @a: first data node
- * @a: second data node
+ * @b: second data node
  *
  * This function compares data nodes @a and @b. Returns %1 if @a has greater
  * inode or block number, and %-1 otherwise.
diff --git a/fs/ubifs/lprops.c b/fs/ubifs/lprops.c
index a0011aa..6c3a1ab 100644
--- a/fs/ubifs/lprops.c
+++ b/fs/ubifs/lprops.c
@@ -636,7 +636,7 @@ const struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c,
 /**
  * ubifs_get_lp_stats - get lprops statistics.
  * @c: UBIFS file-system description object
- * @st: return statistics
+ * @lst: return statistics
  */
 void ubifs_get_lp_stats(struct ubifs_info *c, struct ubifs_lp_stats *lst)
 {
diff --git a/fs/ubifs/lpt_commit.c b/fs/ubifs/lpt_commit.c
index ce89bdc..235654c 100644
--- a/fs/ubifs/lpt_commit.c
+++ b/fs/ubifs/lpt_commit.c
@@ -34,7 +34,6 @@

 /**
  * first_dirty_cnode - find first dirty cnode.
- * @c: UBIFS file-system description object
  * @nnode: nnode at which to start
  *
  * This function returns the first dirty cnode or %NULL if there is not one.
@@ -1623,7 +1622,6 @@ static int dbg_is_node_dirty(struct ubifs_info *c, int node_type, int lnum,
  * dbg_check_ltab_lnum - check the ltab for a LPT LEB number.
  * @c: the UBIFS file-system description object
  * @lnum: LEB number where node was written
- * @offs: offset where node was written
  *
  * This function returns %0 on success and a negative error code on failure.
  */
@@ -1870,7 +1868,7 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)
 }

 /**
- * ubifs_dump_lpt_leb - dump an LPT LEB.
+ * dump_lpt_leb - dump an LPT LEB.
  * @c: UBIFS file-system description object
  * @lnum: LEB number to dump
  *
diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
index 3ca4540..fb0f44c 100644
--- a/fs/ubifs/replay.c
+++ b/fs/ubifs/replay.c
@@ -267,7 +267,7 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
  * replay_entries_cmp - compare 2 replay entries.
  * @priv: UBIFS file-system description object
  * @a: first replay entry
- * @a: second replay entry
+ * @b: second replay entry
  *
  * This is a comparios function for 'list_sort()' which compares 2 replay
  * entries @a and @b by comparing their sequence numer.  Returns %1 if @a has



From zach.brown at ni.com  Mon Oct  3 07:29:32 2016
From: zach.brown at ni.com (Zach Brown)
Date: Mon, 3 Oct 2016 09:29:32 -0500
Subject: [RFC v3] UBI: add debugfs file for tracking PEB state
Message-ID: <1475504972-8859-1-git-send-email-zach.brown@ni.com>

From: Ben Shelton <ben.shelton at ni.com>

Add a file under debugfs to allow easy access to the erase count for
each physical erase block on an UBI device.  This is useful when
debugging data integrity issues with UBIFS on NAND flash devices.

Signed-off-by: Ben Shelton <ben.shelton at ni.com>
Signed-off-by: Zach Brown <zach.brown at ni.com>
---
v2
 * Cast pointer in unsigned long instead of int to avoid build warning
 * Use ubi->lookuptbl[] to get erase counter instead of reading from flash
v3
 * Use wl_lock to protect section that uses ubi_wl_entry
 * Handle case where ubi->lookuptbl returns null


 drivers/mtd/ubi/debug.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 150 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c
index f101a49..6086822 100644
--- a/drivers/mtd/ubi/debug.c
+++ b/drivers/mtd/ubi/debug.c
@@ -22,6 +22,7 @@
 #include <linux/debugfs.h>
 #include <linux/uaccess.h>
 #include <linux/module.h>
+#include <linux/seq_file.h>
 
 
 /**
@@ -386,7 +387,9 @@ out:
 	return count;
 }
 
-/* File operations for all UBI debugfs files */
+/* File operations for all UBI debugfs files except
+ * detailed_erase_block_info
+ */
 static const struct file_operations dfs_fops = {
 	.read   = dfs_file_read,
 	.write  = dfs_file_write,
@@ -395,6 +398,146 @@ static const struct file_operations dfs_fops = {
 	.owner  = THIS_MODULE,
 };
 
+/* As long as the position is less then that total number of erase blocks,
+ * we still have more to print.
+ */
+static void *eraseblk_count_seq_start(struct seq_file *s, loff_t *pos)
+{
+	struct ubi_device *ubi = s->private;
+
+	if (*pos == 0)
+		return SEQ_START_TOKEN;
+
+	if (*pos < ubi->peb_count)
+		return pos;
+
+	return NULL;
+}
+
+/* Since we are using the position as the iterator, we just need to check if we
+ * are done and increment the position.
+ */
+static void *eraseblk_count_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+	struct ubi_device *ubi = s->private;
+
+	if (v == SEQ_START_TOKEN)
+		return pos;
+	(*pos)++;
+
+	if (*pos < ubi->peb_count)
+		return pos;
+
+	return NULL;
+}
+
+static void eraseblk_count_seq_stop(struct seq_file *s, void *v)
+{
+}
+
+enum block_status {
+	BLOCK_STATUS_OK,
+	BLOCK_STATUS_BAD_BLOCK,
+	BLOCK_STATUS_ERASE_COUNT_BEYOND_MAX
+};
+
+static char const *block_status_names[] = {"OK", "marked_bad",
+					   "erase_count_beyond_max"};
+
+enum read_status {
+	READ_STATUS_OK,
+	READ_STATUS_ERR_READING_BLOCK,
+};
+
+static char const *read_status_names[] = {"OK", "err_reading_block"};
+
+static int eraseblk_count_seq_show(struct seq_file *s, void *iter)
+{
+	struct ubi_device *ubi = s->private;
+	struct ubi_wl_entry *wl;
+	int *block_number = iter;
+	int erase_count = -1;
+	enum block_status b_sts = BLOCK_STATUS_OK;
+	enum read_status r_sts = READ_STATUS_OK;
+	int err;
+
+	/* If this is the start, print a header */
+	if (iter == SEQ_START_TOKEN) {
+		seq_puts(s,
+			 "physical_block_number\terase_count\tblock_status\tread_status\n");
+		return 0;
+	}
+
+	err = ubi_io_is_bad(ubi, *block_number);
+	if (err) {
+		if (err < 0)
+			r_sts = READ_STATUS_ERR_READING_BLOCK;
+		else
+			b_sts = BLOCK_STATUS_BAD_BLOCK;
+	} else {
+		spin_lock(&ubi->wl_lock);
+
+		wl = ubi->lookuptbl[*block_number];
+		if (wl)
+			erase_count = wl->ec;
+		else
+			r_sts = READ_STATUS_ERR_READING_BLOCK;
+
+		spin_unlock(&ubi->wl_lock);
+
+		if (erase_count > UBI_MAX_ERASECOUNTER)
+			b_sts = BLOCK_STATUS_ERASE_COUNT_BEYOND_MAX;
+	}
+
+	seq_printf(s, "%-22d\t%-11d\t%-12s\t%-12s\n", *block_number,
+		   erase_count, block_status_names[b_sts],
+		   read_status_names[r_sts]);
+	return 0;
+}
+
+static const struct seq_operations eraseblk_count_seq_ops = {
+	.start = eraseblk_count_seq_start,
+	.next = eraseblk_count_seq_next,
+	.stop = eraseblk_count_seq_stop,
+	.show = eraseblk_count_seq_show
+};
+
+static int eraseblk_count_open(struct inode *inode, struct file *f)
+{
+	struct seq_file *s;
+	int err;
+
+	err = seq_open(f, &eraseblk_count_seq_ops);
+	if (err)
+		return err;
+
+	s = f->private_data;
+	s->private = ubi_get_device((unsigned long)inode->i_private);
+
+	if (!s->private)
+		return -ENODEV;
+	else
+		return 0;
+}
+
+static int eraseblk_count_release(struct inode *inode, struct file *f)
+{
+	struct seq_file *s = f->private_data;
+	struct ubi_device *ubi = s->private;
+
+	ubi_put_device(ubi);
+
+	return seq_release(inode, f);
+}
+
+static const struct file_operations eraseblk_count_fops = {
+	.owner = THIS_MODULE,
+	.open = eraseblk_count_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = eraseblk_count_release,
+};
+
 /**
  * ubi_debugfs_init_dev - initialize debugfs for an UBI device.
  * @ubi: UBI device description object
@@ -491,6 +634,12 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi)
 		goto out_remove;
 	d->dfs_power_cut_max = dent;
 
+	fname = "detailed_erase_block_info";
+	dent = debugfs_create_file(fname, S_IRUSR, d->dfs_dir, (void *)ubi_num,
+				   &eraseblk_count_fops);
+	if (IS_ERR_OR_NULL(dent))
+		goto out_remove;
+
 	return 0;
 
 out_remove:
-- 
2.7.4



From computersforpeace at gmail.com  Mon Oct  3 09:55:33 2016
From: computersforpeace at gmail.com (Brian Norris)
Date: Mon, 3 Oct 2016 09:55:33 -0700
Subject: [PULL] mtd: nand: material for 4.9
In-Reply-To: <20160925205326.67b5a9bd@bbrezillon>
References: <20160925205326.67b5a9bd@bbrezillon>
Message-ID: <20161003165533.GA66959@google.com>

Hi Boris,

On Sun, Sep 25, 2016 at 08:53:26PM +0200, Boris Brezillon wrote:
> Hi Brian,
> 
> Here is my PR for 4.9. Let me know if you see any problem.
> Also, please let us know ahead of time if you can't take this PR (I know you
> are busy lately, and I guess I could send this PR directly to Linus or ask
> Richard to take it in its UBIFS/UBI tree).

I made some time for this one. We'll see about the pairing one
(hopefully trivial? but I'm not sure if there's value in merging without
users).

> Thanks,
> 
> Boris
> 
> The following changes since commit 29b4817d4018df78086157ea3a55c1d9424a7cfc:
> 
>   Linux 4.8-rc1 (2016-08-07 18:18:00 -0700)
> 
> are available in the git repository at:
> 
>   git at github.com:linux-nand/linux.git tags/for-4.9
> 
> for you to fetch changes up to d44154f969a44269a9288c274c1c2fd9e85df8a5:
> 
>   mtd: nand: Provide nand_cleanup() function to free NAND related resources (2016-09-23 09:35:16 +0200)

Thanks. I only added one trivial fixup that checkpatch.pl's spelling.txt
(what??) caught:

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 7a00245ebada..e5718e5ecf92 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -746,7 +746,7 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
 			chip->cmd_ctrl(mtd, column, ctrl);
 			ctrl &= ~NAND_CTRL_CHANGE;
 
-			/* Only ouput a single addr cycle for 8bits opcodes. */
+			/* Only output a single addr cycle for 8bits opcodes. */
 			if (!nand_opcode_8bits(command))
 				chip->cmd_ctrl(mtd, column >> 8, ctrl);
 		}


> ----------------------------------------------------------------
> Notable core changes:
> - add the infrastructure to automate NAND timings configuration
> - provide a generic DT property to maximize ECC strength
> 
> The rest is just a bunch of minor drivers and core fixes/cleanup
> patches.
> 
> ----------------------------------------------------------------

I added a small note in the merge commit about the BBT changes you made.
That's an especially fragile piece of code I think (and used by every
NAND driver), but it looked OK to me.

Brian


From boris.brezillon at free-electrons.com  Mon Oct  3 10:38:26 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Mon, 3 Oct 2016 19:38:26 +0200
Subject: [PULL] mtd: nand: material for 4.9
In-Reply-To: <20161003165533.GA66959@google.com>
References: <20160925205326.67b5a9bd@bbrezillon>
 <20161003165533.GA66959@google.com>
Message-ID: <20161003193826.414116cf@bbrezillon>

Hi Brian,

On Mon, 3 Oct 2016 09:55:33 -0700
Brian Norris <computersforpeace at gmail.com> wrote:

> Hi Boris,
> 
> On Sun, Sep 25, 2016 at 08:53:26PM +0200, Boris Brezillon wrote:
> > Hi Brian,
> > 
> > Here is my PR for 4.9. Let me know if you see any problem.
> > Also, please let us know ahead of time if you can't take this PR (I know you
> > are busy lately, and I guess I could send this PR directly to Linus or ask
> > Richard to take it in its UBIFS/UBI tree).  
> 
> I made some time for this one. We'll see about the pairing one
> (hopefully trivial? but I'm not sure if there's value in merging without
> users).

Well, I already posted UBI patches using this API, and that'd be easier
if the interface is already available (that would solve cross-tree
dependencies).
> 
> > Thanks,
> > 
> > Boris
> > 
> > The following changes since commit 29b4817d4018df78086157ea3a55c1d9424a7cfc:
> > 
> >   Linux 4.8-rc1 (2016-08-07 18:18:00 -0700)
> > 
> > are available in the git repository at:
> > 
> >   git at github.com:linux-nand/linux.git tags/for-4.9
> > 
> > for you to fetch changes up to d44154f969a44269a9288c274c1c2fd9e85df8a5:
> > 
> >   mtd: nand: Provide nand_cleanup() function to free NAND related resources (2016-09-23 09:35:16 +0200)  
> 
> Thanks. I only added one trivial fixup that checkpatch.pl's spelling.txt
> (what??) caught:
> 
> diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
> index 7a00245ebada..e5718e5ecf92 100644
> --- a/drivers/mtd/nand/nand_base.c
> +++ b/drivers/mtd/nand/nand_base.c
> @@ -746,7 +746,7 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
>  			chip->cmd_ctrl(mtd, column, ctrl);
>  			ctrl &= ~NAND_CTRL_CHANGE;
>  
> -			/* Only ouput a single addr cycle for 8bits opcodes. */
> +			/* Only output a single addr cycle for 8bits opcodes. */
>  			if (!nand_opcode_8bits(command))
>  				chip->cmd_ctrl(mtd, column >> 8, ctrl);
>  		}
> 
> 
> > ----------------------------------------------------------------
> > Notable core changes:
> > - add the infrastructure to automate NAND timings configuration
> > - provide a generic DT property to maximize ECC strength
> > 
> > The rest is just a bunch of minor drivers and core fixes/cleanup
> > patches.
> > 
> > ----------------------------------------------------------------  
> 
> I added a small note in the merge commit about the BBT changes you made.
> That's an especially fragile piece of code I think (and used by every
> NAND driver), but it looked OK to me.

Oh, I completely forgot about this important change.

Thanks for fixing the typo and adding more information in the merge
message.

Boris


From robh at kernel.org  Mon Oct  3 11:51:43 2016
From: robh at kernel.org (Rob Herring)
Date: Mon, 3 Oct 2016 13:51:43 -0500
Subject: [PATCH 2/2] fsl-quadspi: introduce per-bus spi-bus-width property
In-Reply-To: <20160927055957.427-2-albert.aribaud@3adev.fr>
References: <20160927055957.427-1-albert.aribaud@3adev.fr>
 <20160927055957.427-2-albert.aribaud@3adev.fr>
Message-ID: <20161003185143.GA27634@rob-hp-laptop>

On Tue, Sep 27, 2016 at 07:59:57AM +0200, Albert ARIBAUD (3ADEV) wrote:
> Introduce spi-bus-width property for bus subnodes, to
> specify per-bus capability to use NORMAL, FAST, DUAL,
> and/or QUAD reads.
> 
> Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud at 3adev.fr>
> ---
>  Documentation/devicetree/bindings/mtd/fsl-quadspi.txt | 18 ++++++++++++++++++
>  1 file changed, 18 insertions(+)

Make this a common property.

Rob


From geert at linux-m68k.org  Mon Oct  3 12:57:58 2016
From: geert at linux-m68k.org (Geert Uytterhoeven)
Date: Mon, 3 Oct 2016 21:57:58 +0200
Subject: [PATCH 2/2] fsl-quadspi: introduce per-bus spi-bus-width property
In-Reply-To: <20161003185143.GA27634@rob-hp-laptop>
References: <20160927055957.427-1-albert.aribaud@3adev.fr>
 <20160927055957.427-2-albert.aribaud@3adev.fr>
 <20161003185143.GA27634@rob-hp-laptop>
Message-ID: <CAMuHMdW6WJBj3TiXU0mmwKJmcwp28HEVUSD17-7RH7-UXFtX1g@mail.gmail.com>

On Mon, Oct 3, 2016 at 8:51 PM, Rob Herring <robh at kernel.org> wrote:
> On Tue, Sep 27, 2016 at 07:59:57AM +0200, Albert ARIBAUD (3ADEV) wrote:
>> Introduce spi-bus-width property for bus subnodes, to
>> specify per-bus capability to use NORMAL, FAST, DUAL,
>> and/or QUAD reads.
>>
>> Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud at 3adev.fr>
>> ---
>>  Documentation/devicetree/bindings/mtd/fsl-quadspi.txt | 18 ++++++++++++++++++
>>  1 file changed, 18 insertions(+)
>
> Make this a common property.

They already exist:

Documentation/devicetree/bindings/spi/spi-bus.txt:
- spi-tx-bus-width - (optional) The bus width (number of data wires) that is
                      used for MOSI. Defaults to 1 if not present.
- spi-rx-bus-width - (optional) The bus width (number of data wires) that is
                      used for MISO. Defaults to 1 if not present.

The above are for normal/dual/quad.

"Fast" is not a property of the bus, but of the SPI slave, right? Cfr.

Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt:
- m25p,fast-read : Use the "fast read" opcode to read data from the chip instead
                   of the usual "read" opcode. This opcode is not supported by
                   all chips and support for it can not be detected at runtime.
                   Refer to your chips' datasheet to check if this is supported
                   by your chip.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds


From cyrille.pitchen at atmel.com  Tue Oct  4 05:30:04 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Tue, 4 Oct 2016 14:30:04 +0200
Subject: [PATCH 1/2] fsl-quadspi: fix QUAD read, add NORMAL, DUAL and FAST
 reads
In-Reply-To: <20160927055957.427-1-albert.aribaud@3adev.fr>
References: <20160927055957.427-1-albert.aribaud@3adev.fr>
Message-ID: <f7f42f60-2853-d43d-b635-24397590a666@atmel.com>

Hi Albert,

your patch is likely to conflict with:
https://patchwork.kernel.org/patch/9287005/

Yunhui's patch relies on the settings selected by spi-nor.c to configure the
freescale QSPI controller correctly. The freescale QSPI controller driver, like
other QSPI controller drivers, should never override settings selected in
spi_nor_scan() otherwise it will duplicate the code, will be hard to maintain
and won't work with every memory. For instance, not all memory manufacturers
use the very same op codes for Quad SPI Fast Read.
So let's spi-nor.c handle this stuff!

That's why I suggest you rebase your work on Yunhui patches.

Best regards,

Cyrille

Le 27/09/2016 ? 07:59, Albert ARIBAUD (3ADEV) a ?crit :
> Fix QUAD read LUT sequence missing JMP_ON_CS which caused
> read corruptions with non-1K-size reads on BK4R1 machine.
> 
> Add NORMAL, DUAL and FAST read sequences.
> 
> Introduce spi-bus-width property for bus subnodes, to
> specify per-bus capability to use NORMAL, FAST, DUAL,
> and/or QUAD reads.
> 
> Also:
> 
> Simplify ioremap/memcpy usage.
> 
> Make controller clock frequency equal to the lowest of
> subnode max frequencies instead of the last one.
> 
> Limit Vybrid to use only half its RX fifo, using more will
> cause corrupt reads.
> 
> Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud at 3adev.fr>
> ---
>  drivers/mtd/spi-nor/fsl-quadspi.c | 204 ++++++++++++++++++++++++++++----------
>  1 file changed, 152 insertions(+), 52 deletions(-)
> 
> diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c
> index 5c82e4e..9811cf2 100644
> --- a/drivers/mtd/spi-nor/fsl-quadspi.c
> +++ b/drivers/mtd/spi-nor/fsl-quadspi.c
> @@ -41,6 +41,8 @@
>  #define QUADSPI_QUIRK_TKT253890		(1 << 2)
>  /* Controller cannot wake up from wait mode, TKT245618 */
>  #define QUADSPI_QUIRK_TKT245618         (1 << 3)
> +/* Controller can only read half a rx fifo through AHB */
> +#define QUADSPI_QUIRK_AHB_READ_HALF_FIFO  (1 << 4)
>  
>  /* The registers */
>  #define QUADSPI_MCR			0x00
> @@ -117,6 +119,10 @@
>  #define QUADSPI_FR			0x160
>  #define QUADSPI_FR_TFF_MASK		0x1
>  
> +#define QUADSPI_SPTRCLR			0x15c
> +#define QUADSPI_SPTRCLR_BFPTRC_SHIFT		0
> +#define QUADSPI_SPTRCLR_BFPTRC_MASK		(0x1 << QUADSPI_SPTRCLR_BFPTRC_SHIFT)
> +
>  #define QUADSPI_SFA1AD			0x180
>  #define QUADSPI_SFA2AD			0x184
>  #define QUADSPI_SFB1AD			0x188
> @@ -193,7 +199,7 @@
>  #define QUADSPI_LUT_NUM		64
>  
>  /* SEQID -- we can have 16 seqids at most. */
> -#define SEQID_QUAD_READ		0
> +#define SEQID_READ		0
>  #define SEQID_WREN		1
>  #define SEQID_WRDI		2
>  #define SEQID_RDSR		3
> @@ -205,6 +211,9 @@
>  #define SEQID_RDCR		9
>  #define SEQID_EN4B		10
>  #define SEQID_BRWR		11
> +#define SEQID_FAST_READ		12
> +#define SEQID_DUAL_READ		13
> +#define SEQID_QUAD_READ		14
>  
>  #define QUADSPI_MIN_IOMAP SZ_4M
>  
> @@ -229,7 +238,8 @@ static struct fsl_qspi_devtype_data vybrid_data = {
>  	.rxfifo = 128,
>  	.txfifo = 64,
>  	.ahb_buf_size = 1024,
> -	.driver_data = QUADSPI_QUIRK_SWAP_ENDIAN,
> +	.driver_data = QUADSPI_QUIRK_SWAP_ENDIAN
> +		       | QUADSPI_QUIRK_AHB_READ_HALF_FIFO,
>  };
>  
>  static struct fsl_qspi_devtype_data imx6sx_data = {
> @@ -309,6 +319,11 @@ static inline int needs_wakeup_wait_mode(struct fsl_qspi *q)
>  	return q->devtype_data->driver_data & QUADSPI_QUIRK_TKT245618;
>  }
>  
> +static inline int needs_half_fifo(struct fsl_qspi *q)
> +{
> +	return q->devtype_data->driver_data & QUADSPI_QUIRK_AHB_READ_HALF_FIFO;
> +}
> +
>  /*
>   * R/W functions for big- or little-endian registers:
>   * The qSPI controller's endian is independent of the CPU core's endian.
> @@ -373,8 +388,20 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
>  	void __iomem *base = q->iobase;
>  	int rxfifo = q->devtype_data->rxfifo;
>  	u32 lut_base;
> -	u8 cmd, addrlen, dummy;
> +	u8 cmd, addrlen;
>  	int i;
> +	/* use 8 dummy cycles for all fast operations */
> +	const int dummy = 8;
> +
> +	/* use only half fifo if controller needs that */
> +	if (needs_half_fifo(q))
> +		rxfifo /= 2;
> +
> +    /* use 24-bit addresses for up to 16MB, 32-bit above 16MB */
> +	if (q->nor_size <= SZ_16M)
> +		addrlen = ADDR24BIT;
> +	else
> +		addrlen = ADDR32BIT;
>  
>  	fsl_qspi_unlock_lut(q);
>  
> @@ -382,24 +409,12 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
>  	for (i = 0; i < QUADSPI_LUT_NUM; i++)
>  		qspi_writel(q, 0, base + QUADSPI_LUT_BASE + i * 4);
>  
> -	/* Quad Read */
> -	lut_base = SEQID_QUAD_READ * 4;
> -
> -	if (q->nor_size <= SZ_16M) {
> -		cmd = SPINOR_OP_READ_1_1_4;
> -		addrlen = ADDR24BIT;
> -		dummy = 8;
> -	} else {
> -		/* use the 4-byte address */
> -		cmd = SPINOR_OP_READ_1_1_4;
> -		addrlen = ADDR32BIT;
> -		dummy = 8;
> -	}
> -
> -	qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
> -			base + QUADSPI_LUT(lut_base));
> -	qspi_writel(q, LUT0(DUMMY, PAD1, dummy) | LUT1(FSL_READ, PAD4, rxfifo),
> -			base + QUADSPI_LUT(lut_base + 1));
> +	/* Read */
> +	lut_base = SEQID_READ * 4;
> +	qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_READ) | LUT1(ADDR, PAD1, addrlen),
> +		base + QUADSPI_LUT(lut_base));
> +	qspi_writel(q, LUT0(FSL_READ, PAD1, rxfifo) | LUT1(JMP_ON_CS, PAD1, SEQID_READ * 8),
> +		base + QUADSPI_LUT(lut_base + 1));
>  
>  	/* Write enable */
>  	lut_base = SEQID_WREN * 4;
> @@ -409,16 +424,7 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
>  	/* Page Program */
>  	lut_base = SEQID_PP * 4;
>  
> -	if (q->nor_size <= SZ_16M) {
> -		cmd = SPINOR_OP_PP;
> -		addrlen = ADDR24BIT;
> -	} else {
> -		/* use the 4-byte address */
> -		cmd = SPINOR_OP_PP;
> -		addrlen = ADDR32BIT;
> -	}
> -
> -	qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
> +	qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_PP) | LUT1(ADDR, PAD1, addrlen),
>  			base + QUADSPI_LUT(lut_base));
>  	qspi_writel(q, LUT0(FSL_WRITE, PAD1, 0),
>  			base + QUADSPI_LUT(lut_base + 1));
> @@ -431,7 +437,6 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
>  
>  	/* Erase a sector */
>  	lut_base = SEQID_SE * 4;
> -
>  	cmd = q->nor[0].erase_opcode;
>  	addrlen = q->nor_size <= SZ_16M ? ADDR24BIT : ADDR32BIT;
>  
> @@ -476,6 +481,33 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
>  	qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_BRWR),
>  			base + QUADSPI_LUT(lut_base));
>  
> +	/* Fast Read */
> +	lut_base = SEQID_FAST_READ * 4;
> +	qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_READ_FAST) | LUT1(ADDR, PAD1, addrlen),
> +		base + QUADSPI_LUT(lut_base));
> +	qspi_writel(q, LUT0(DUMMY, PAD1, dummy) | LUT1(FSL_READ, PAD1, rxfifo),
> +		base + QUADSPI_LUT(lut_base + 1));
> +	qspi_writel(q, LUT0(JMP_ON_CS, PAD1, SEQID_FAST_READ * 8),
> +		base + QUADSPI_LUT(lut_base + 2));
> +
> +	/* Dual Read */
> +	lut_base = SEQID_DUAL_READ * 4;
> +	qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_READ_1_1_2) | LUT1(ADDR, PAD1, addrlen),
> +		base + QUADSPI_LUT(lut_base));
> +	qspi_writel(q, LUT0(DUMMY, PAD1, dummy) | LUT1(FSL_READ, PAD2, rxfifo),
> +		base + QUADSPI_LUT(lut_base + 1));
> +	qspi_writel(q, LUT0(JMP_ON_CS, PAD1, SEQID_DUAL_READ * 8),
> +		base + QUADSPI_LUT(lut_base + 2));
> +
> +	/* Quad Read */
> +	lut_base = SEQID_QUAD_READ * 4;
> +	qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_READ_1_1_4) | LUT1(ADDR, PAD1, addrlen),
> +		base + QUADSPI_LUT(lut_base));
> +	qspi_writel(q, LUT0(DUMMY, PAD1, dummy) | LUT1(FSL_READ, PAD4, rxfifo),
> +		base + QUADSPI_LUT(lut_base + 1));
> +	qspi_writel(q, LUT0(JMP_ON_CS, PAD1, SEQID_QUAD_READ * 8),
> +		base + QUADSPI_LUT(lut_base + 2));
> +
>  	fsl_qspi_lock_lut(q);
>  }
>  
> @@ -483,8 +515,8 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
>  static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd)
>  {
>  	switch (cmd) {
> -	case SPINOR_OP_READ_1_1_4:
> -		return SEQID_QUAD_READ;
> +	case SPINOR_OP_READ:
> +		return SEQID_READ;
>  	case SPINOR_OP_WREN:
>  		return SEQID_WREN;
>  	case SPINOR_OP_WRDI:
> @@ -507,6 +539,12 @@ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd)
>  		return SEQID_EN4B;
>  	case SPINOR_OP_BRWR:
>  		return SEQID_BRWR;
> +	case SPINOR_OP_READ_FAST:
> +		return SEQID_FAST_READ;
> +	case SPINOR_OP_READ_1_1_2:
> +		return SEQID_DUAL_READ;
> +	case SPINOR_OP_READ_1_1_4:
> +		return SEQID_QUAD_READ;
>  	default:
>  		if (cmd == q->nor[0].erase_opcode)
>  			return SEQID_SE;
> @@ -676,11 +714,16 @@ static void fsl_qspi_set_map_addr(struct fsl_qspi *q)
>   * the memcpy to read the data directly. A "missed" access to the buffer
>   * causes the controller to clear the buffer, and use the sequence pointed
>   * by the QUADSPI_BFGENCR[SEQID] to initiate a read from the flash.
> + *
> + * When using two ports, the SEQID to use for one port might differ from
> + * the one to use for the other (e.g., if one port can do 4-pad reads but
> + * the other cannot). So we set up a basic mode here (SEQID_READ) and we
> + * will set up the proper SEQID for the port right before doing the AHB
> + * access(es).
>   */
>  static void fsl_qspi_init_abh_read(struct fsl_qspi *q)
>  {
>  	void __iomem *base = q->iobase;
> -	int seqid;
>  
>  	/* AHB configuration for access buffer 0/1/2 .*/
>  	qspi_writel(q, QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF0CR);
> @@ -688,11 +731,13 @@ static void fsl_qspi_init_abh_read(struct fsl_qspi *q)
>  	qspi_writel(q, QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF2CR);
>  	/*
>  	 * Set ADATSZ with the maximum AHB buffer size to improve the
> -	 * read performance.
> +	 * read performance, except when the controller should not use
> +	 * more than half its RX fifo in AHB reads, in which case read
> +	 * size is given in the LUT FSL_READ instructions.
>  	 */
>  	qspi_writel(q, QUADSPI_BUF3CR_ALLMST_MASK |
> -			((q->devtype_data->ahb_buf_size / 8)
> -			<< QUADSPI_BUF3CR_ADATSZ_SHIFT),
> +			(needs_half_fifo(q)? 0 : q->devtype_data->ahb_buf_size / 8)
> +	        << QUADSPI_BUF3CR_ADATSZ_SHIFT,
>  			base + QUADSPI_BUF3CR);
>  
>  	/* We only use the buffer3 */
> @@ -700,9 +745,8 @@ static void fsl_qspi_init_abh_read(struct fsl_qspi *q)
>  	qspi_writel(q, 0, base + QUADSPI_BUF1IND);
>  	qspi_writel(q, 0, base + QUADSPI_BUF2IND);
>  
> -	/* Set the default lut sequence for AHB Read. */
> -	seqid = fsl_qspi_get_seqid(q, q->nor[0].read_opcode);
> -	qspi_writel(q, seqid << QUADSPI_BFGENCR_SEQID_SHIFT,
> +	/* Set the default lut sequence for AHB Read to READ. */
> +	qspi_writel(q, SEQID_READ << QUADSPI_BFGENCR_SEQID_SHIFT,
>  		q->iobase + QUADSPI_BFGENCR);
>  }
>  
> @@ -841,6 +885,7 @@ static int fsl_qspi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
>  		return ret;
>  
>  	fsl_qspi_read_data(q, len, buf);
> +
>  	return 0;
>  }
>  
> @@ -887,11 +932,27 @@ static ssize_t fsl_qspi_read(struct spi_nor *nor, loff_t from,
>  {
>  	struct fsl_qspi *q = nor->priv;
>  	u8 cmd = nor->read_opcode;
> +	uint32_t seqid;
> +	size_t qlen = q->nor_size * 4;
> +	int nor_idx = nor - q->nor;
> +	size_t nor_ofs = q->nor_size * nor_idx;
> +
> +	/* Set the actual lut sequence for AHB Read from the considered nor. */
> +	seqid = fsl_qspi_get_seqid(q, nor->read_opcode);
> +	qspi_writel(q, seqid << QUADSPI_BFGENCR_SEQID_SHIFT,
> +		q->iobase + QUADSPI_BFGENCR);
> +	/* Reset the AHB sequence pointer */
> +	qspi_writel(q, QUADSPI_SPTRCLR_BFPTRC_MASK, q->iobase + QUADSPI_SPTRCLR);
> +    /* make sure the Rx buffer is read through AHB, not IP */
> +	qspi_writel(q, QUADSPI_RBCT_WMRK_MASK, q->iobase + QUADSPI_RBCT);
> +
> +	/* set the chip address for READID */
> +	fsl_qspi_set_base_addr(q, q->nor);
>  
>  	/* if necessary,ioremap buffer before AHB read, */
>  	if (!q->ahb_addr) {
> -		q->memmap_offs = q->chip_base_addr + from;
> -		q->memmap_len = len > QUADSPI_MIN_IOMAP ? len : QUADSPI_MIN_IOMAP;
> +		q->memmap_offs = q->chip_base_addr;
> +		q->memmap_len = qlen > QUADSPI_MIN_IOMAP ? qlen : QUADSPI_MIN_IOMAP;
>  
>  		q->ahb_addr = ioremap_nocache(
>  				q->memmap_phy + q->memmap_offs,
> @@ -906,8 +967,8 @@ static ssize_t fsl_qspi_read(struct spi_nor *nor, loff_t from,
>  			q->memmap_offs + q->memmap_len) {
>  		iounmap(q->ahb_addr);
>  
> -		q->memmap_offs = q->chip_base_addr + from;
> -		q->memmap_len = len > QUADSPI_MIN_IOMAP ? len : QUADSPI_MIN_IOMAP;
> +		q->memmap_offs = q->chip_base_addr;
> +		q->memmap_len = qlen > QUADSPI_MIN_IOMAP ? qlen : QUADSPI_MIN_IOMAP;
>  		q->ahb_addr = ioremap_nocache(
>  				q->memmap_phy + q->memmap_offs,
>  				q->memmap_len);
> @@ -917,13 +978,11 @@ static ssize_t fsl_qspi_read(struct spi_nor *nor, loff_t from,
>  		}
>  	}
>  
> -	dev_dbg(q->dev, "cmd [%x],read from %p, len:%zd\n",
> -		cmd, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs,
> -		len);
> +	dev_dbg(q->dev, "cmd [%x], read from %p, len:%zd\n",
> +		cmd, q->ahb_addr + nor_ofs + from, len);
>  
>  	/* Read out the data directly from the AHB buffer.*/
> -	memcpy(buf, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs,
> -		len);
> +	memcpy(buf, q->ahb_addr + nor_ofs + from, len);
>  
>  	return len;
>  }
> @@ -980,6 +1039,11 @@ static int fsl_qspi_probe(struct platform_device *pdev)
>  	struct spi_nor *nor;
>  	struct mtd_info *mtd;
>  	int ret, i = 0;
> +	const struct of_device_id *of_id =
> +			of_match_device(fsl_qspi_dt_ids, &pdev->dev);
> +	enum read_mode readmode;
> +	unsigned int buswidth;
> +	u32 qspimaxfreq, spimaxfreq;
>  
>  	q = devm_kzalloc(dev, sizeof(*q), GFP_KERNEL);
>  	if (!q)
> @@ -1050,6 +1114,9 @@ static int fsl_qspi_probe(struct platform_device *pdev)
>  
>  	mutex_init(&q->lock);
>  
> +	/* Running MIN of all "spi-max-frequency' values present in subnodes */
> +	qspimaxfreq = INT_MAX;
> +
>  	/* iterate the subnodes. */
>  	for_each_available_child_of_node(dev->of_node, np) {
>  		/* skip the holes */
> @@ -1073,15 +1140,44 @@ static int fsl_qspi_probe(struct platform_device *pdev)
>  		nor->prepare = fsl_qspi_prep;
>  		nor->unprepare = fsl_qspi_unprep;
>  
> +		/* Update running MIN of subnode max frequencies */
>  		ret = of_property_read_u32(np, "spi-max-frequency",
> -				&q->clk_rate);
> +				&spimaxfreq);
>  		if (ret < 0)
>  			goto mutex_failed;
> +		qspimaxfreq = (qspimaxfreq > spimaxfreq) ? spimaxfreq: qspimaxfreq;
>  
>  		/* set the chip address for READID */
>  		fsl_qspi_set_base_addr(q, nor);
>  
> -		ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
> +		/* scan using the proper read mode for this subnode */
> +		if (of_property_read_u32(np, "spi-bus-width", &buswidth)<0) {
> +			nor->read_opcode = SPINOR_OP_READ;
> +			readmode = SPI_NOR_NORMAL;
> +		} else {
> +			switch (buswidth) {
> +			case 4:
> +				nor->read_opcode = SPINOR_OP_READ_1_1_4;
> +				readmode = SPI_NOR_QUAD;
> +				break;
> +			case 2:
> +				nor->read_opcode = SPINOR_OP_READ_1_1_2;
> +				readmode = SPI_NOR_DUAL;
> +				break;
> +			case 1:
> +				nor->read_opcode = SPINOR_OP_READ_FAST;
> +				readmode = SPI_NOR_FAST;
> +				break;
> +			default:
> +				dev_warn(q->dev,
> +					"ignoring spi-bus-width=%d (should be 1, 2 or 4)",
> +					buswidth);
> +				nor->read_opcode = SPINOR_OP_READ;
> +				readmode = SPI_NOR_NORMAL;
> +			}
> +		}
> +
> +		ret = spi_nor_scan(nor, NULL, readmode);
>  		if (ret)
>  			goto mutex_failed;
>  
> @@ -1112,6 +1208,10 @@ static int fsl_qspi_probe(struct platform_device *pdev)
>  		i++;
>  	}
>  
> +	/* If we know the lowest subnode frequency, override driver default. */
> +	if (qspimaxfreq<INT_MAX)
> +		q->clk_rate = qspimaxfreq;
> +
>  	/* finish the rest init. */
>  	ret = fsl_qspi_nor_setup_last(q);
>  	if (ret)
> 



From cyrille.pitchen at atmel.com  Tue Oct  4 09:37:02 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Tue, 4 Oct 2016 18:37:02 +0200
Subject: [PATCH 0/9] mtd: spi-nor: parse SFDP tables to setup (Q)SPI memories
Message-ID: <cover.1475597385.git.cyrille.pitchen@atmel.com>

Hi all,

This series extends support of SPI protocols to new protocols such as
SPI x-2-2 and SPI x-4-4. Also spi_nor_scan() tries now to select the right
op codes, timing parameters (number of mode and dummy cycles) and erase
sector size by parsing the Serial Flash Discoverable Parameter (SFDP)
tables, when available, as defined in the JEDEC JESD216 specifications.

When SFDP tables are not available, legacy settings are still used for
backward compatibility (SPI and earlier QSPI memories).

Support of SPI memories >128Mbits is also improved by using the 4byte
address instruction set, when available. Using those dedicated op codes
is stateless as opposed to enter the 4byte address mode, hence a better
compatibility with some boot loaders which expect to use 3byte address
op codes.


This series was tested on a Atmel sama5d2 xplained board with the
atmel-qspi.c driver. Except for SST memories, the SPI bus clock was set
to 83MHz. The config MTD_SPI_NOR_USE_4K_SECTORS was selected.

For my tests, I used some shell scripts using mtd_debug and sha1sum to
check the data integrity.

e.g:
#!/bin/sh

mtd_debug erase /dev/mtd5 0 0x780000
mtd_debug write /dev/mtd5 0 7674703 sama5d4_doc11238.pdf
mtd_debug read /dev/mtd5 0 7674703 sam5d4_tmp.pdf

sha1sum sama5d4_doc11238.pdf sam5d4_tmp.pdf


The series was tested with the following QSPI memories:

Spansion/Cypress:
- s25fl127s	OK
- s25fl512s	OK
- s25fl164k	OK

Micron:
- n25q128a	OK

Macronix:
- mx25l6433f	OK
- mx25l6473f	OK
- mx25l12835f	OK
- mx25l12845g	OK
- mx25l12873g	OK
- mx25l25645g	OK
- mx25l25673g	OK
- mx25l51245g	OK
- mx66l1g45g	OK (1)

SST:
- sst26vf016b	OK (2)
- sst26vf032b	OK (2)
- sst26vf064b	OK (2)

(1): requires patch 8
(2): requires patch 9, the SPI bus clock frequency was decreased down to 55.3MHz


Best regards,

Cyrille

Depending on the actual memory size, I may have used other partitions
(/dev/mtd4) and input file size (2880044 and 320044 bytes).

Cyrille Pitchen (9):
  mtd: spi-nor: improve macronix_quad_enable()
  mtd: spi-nor: add an alternative method to support memory >16MiB
  mtd: spi-nor: add support of SPI protocols like SPI 1-2-2 and SPI
    1-4-4
  mtd: spi-nor: remove unused set_quad_mode() function
  mtd: m25p80: add support of dual and quad spi protocols to all
    commands
  mtd: spi-nor: parse Serial Flash Discoverable Parameters (SFDP) tables
  mtd: spi-nor: parse SFDP 4-byte Address Instruction Table
  mtd: spi-nor: add support to Macronix mx66l1g45g
  mtd: spi-nor: add support to SST sst26* QSPI memories

 drivers/mtd/devices/m25p80.c            |  204 +++++--
 drivers/mtd/devices/serial_flash_cmds.h |    7 -
 drivers/mtd/devices/st_spi_fsm.c        |   28 +-
 drivers/mtd/spi-nor/atmel-quadspi.c     |   83 ++-
 drivers/mtd/spi-nor/cadence-quadspi.c   |    8 +-
 drivers/mtd/spi-nor/fsl-quadspi.c       |    8 +-
 drivers/mtd/spi-nor/hisi-sfc.c          |    8 +-
 drivers/mtd/spi-nor/mtk-quadspi.c       |   16 +-
 drivers/mtd/spi-nor/nxp-spifi.c         |   21 +-
 drivers/mtd/spi-nor/spi-nor.c           | 1013 ++++++++++++++++++++++++++++---
 include/linux/mtd/spi-nor.h             |  165 ++++-
 11 files changed, 1337 insertions(+), 224 deletions(-)

-- 
2.7.4



From cyrille.pitchen at atmel.com  Tue Oct  4 09:37:03 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Tue, 4 Oct 2016 18:37:03 +0200
Subject: [PATCH 1/9] mtd: spi-nor: improve macronix_quad_enable()
In-Reply-To: <cover.1475597385.git.cyrille.pitchen@atmel.com>
References: <cover.1475597385.git.cyrille.pitchen@atmel.com>
Message-ID: <84482e0c2b73181036e8e02492434f237f148c7f.1475597385.git.cyrille.pitchen@atmel.com>

The patch checks whether the Quad Enable bit is already set in the Status
Register. If so, the function exits immediately with a successful return
code. Otherwise, a message is now printed telling we're setting the
non-volatile bit.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index d0fc165d7d66..5c87b2d99507 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1211,6 +1211,11 @@ static int macronix_quad_enable(struct spi_nor *nor)
 	val = read_sr(nor);
 	if (val < 0)
 		return val;
+	if (val & SR_QUAD_EN_MX)
+		return 0;
+
+	/* Update the Quad Enable bit. */
+	dev_info(nor->dev, "setting Macronix Quad Enable (non-volatile) bit\n");
 	write_enable(nor);
 
 	write_sr(nor, val | SR_QUAD_EN_MX);
-- 
2.7.4



From cyrille.pitchen at atmel.com  Tue Oct  4 09:37:04 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Tue, 4 Oct 2016 18:37:04 +0200
Subject: [PATCH 2/9] mtd: spi-nor: add an alternative method to support memory
 >16MiB
In-Reply-To: <cover.1475597385.git.cyrille.pitchen@atmel.com>
References: <cover.1475597385.git.cyrille.pitchen@atmel.com>
Message-ID: <75db6c008249df8d0646ea5006648e57fea40706.1475597385.git.cyrille.pitchen@atmel.com>

This patch provides an alternative mean to support memory above 16MiB
(128Mib) by replacing 3byte address op codes by their associated 4byte
address versions.

Using the dedicated 4byte address op codes doesn't change the internal
state of the SPI NOR memory as opposed to using other means such as
updating a Base Address Register (BAR) and sending command to enter/leave
the 4byte mode.

Hence when a CPU reset occurs, early bootloaders don't need to be aware
of BAR value or 4byte mode being enabled: they can still access the first
16MiB of the SPI NOR memory using the regular 3byte address op codes.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
 drivers/mtd/devices/serial_flash_cmds.h |   7 ---
 drivers/mtd/devices/st_spi_fsm.c        |  28 ++++-----
 drivers/mtd/spi-nor/spi-nor.c           | 104 +++++++++++++++++++++++++-------
 include/linux/mtd/spi-nor.h             |  22 +++++--
 4 files changed, 113 insertions(+), 48 deletions(-)

diff --git a/drivers/mtd/devices/serial_flash_cmds.h b/drivers/mtd/devices/serial_flash_cmds.h
index f59a125295d0..8b81e15105dd 100644
--- a/drivers/mtd/devices/serial_flash_cmds.h
+++ b/drivers/mtd/devices/serial_flash_cmds.h
@@ -18,19 +18,12 @@
 #define SPINOR_OP_RDVCR		0x85
 
 /* JEDEC Standard - Serial Flash Discoverable Parmeters (SFDP) Commands */
-#define SPINOR_OP_READ_1_2_2	0xbb	/* DUAL I/O READ */
-#define SPINOR_OP_READ_1_4_4	0xeb	/* QUAD I/O READ */
-
 #define SPINOR_OP_WRITE		0x02	/* PAGE PROGRAM */
 #define SPINOR_OP_WRITE_1_1_2	0xa2	/* DUAL INPUT PROGRAM */
 #define SPINOR_OP_WRITE_1_2_2	0xd2	/* DUAL INPUT EXT PROGRAM */
 #define SPINOR_OP_WRITE_1_1_4	0x32	/* QUAD INPUT PROGRAM */
 #define SPINOR_OP_WRITE_1_4_4	0x12	/* QUAD INPUT EXT PROGRAM */
 
-/* READ commands with 32-bit addressing */
-#define SPINOR_OP_READ4_1_2_2	0xbc
-#define SPINOR_OP_READ4_1_4_4	0xec
-
 /* Configuration flags */
 #define FLASH_FLAG_SINGLE	0x000000ff
 #define FLASH_FLAG_READ_WRITE	0x00000001
diff --git a/drivers/mtd/devices/st_spi_fsm.c b/drivers/mtd/devices/st_spi_fsm.c
index 5454b4113589..804313a33f2b 100644
--- a/drivers/mtd/devices/st_spi_fsm.c
+++ b/drivers/mtd/devices/st_spi_fsm.c
@@ -507,13 +507,13 @@ static struct seq_rw_config n25q_read3_configs[] = {
  *	- 'FAST' variants configured for 8 dummy cycles (see note above.)
  */
 static struct seq_rw_config n25q_read4_configs[] = {
-	{FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ4_1_4_4,	0, 4, 4, 0x00, 0, 8},
-	{FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ4_1_1_4,	0, 1, 4, 0x00, 0, 8},
-	{FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ4_1_2_2,	0, 2, 2, 0x00, 0, 8},
-	{FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ4_1_1_2,	0, 1, 2, 0x00, 0, 8},
-	{FLASH_FLAG_READ_FAST,	SPINOR_OP_READ4_FAST,	0, 1, 1, 0x00, 0, 8},
-	{FLASH_FLAG_READ_WRITE, SPINOR_OP_READ4,	0, 1, 1, 0x00, 0, 0},
-	{0x00,			0,			0, 0, 0, 0x00, 0, 0},
+	{FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ_1_4_4_4B, 0, 4, 4, 0x00, 0, 8},
+	{FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ_1_1_4_4B, 0, 1, 4, 0x00, 0, 8},
+	{FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ_1_2_2_4B, 0, 2, 2, 0x00, 0, 8},
+	{FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ_1_1_2_4B, 0, 1, 2, 0x00, 0, 8},
+	{FLASH_FLAG_READ_FAST,	SPINOR_OP_READ_FAST_4B,  0, 1, 1, 0x00, 0, 8},
+	{FLASH_FLAG_READ_WRITE, SPINOR_OP_READ_4B,       0, 1, 1, 0x00, 0, 0},
+	{0x00,			0,                       0, 0, 0, 0x00, 0, 0},
 };
 
 /*
@@ -553,13 +553,13 @@ static int stfsm_mx25_en_32bit_addr_seq(struct stfsm_seq *seq)
  * entering a state that is incompatible with the SPIBoot Controller.
  */
 static struct seq_rw_config stfsm_s25fl_read4_configs[] = {
-	{FLASH_FLAG_READ_1_4_4,  SPINOR_OP_READ4_1_4_4,  0, 4, 4, 0x00, 2, 4},
-	{FLASH_FLAG_READ_1_1_4,  SPINOR_OP_READ4_1_1_4,  0, 1, 4, 0x00, 0, 8},
-	{FLASH_FLAG_READ_1_2_2,  SPINOR_OP_READ4_1_2_2,  0, 2, 2, 0x00, 4, 0},
-	{FLASH_FLAG_READ_1_1_2,  SPINOR_OP_READ4_1_1_2,  0, 1, 2, 0x00, 0, 8},
-	{FLASH_FLAG_READ_FAST,   SPINOR_OP_READ4_FAST,   0, 1, 1, 0x00, 0, 8},
-	{FLASH_FLAG_READ_WRITE,  SPINOR_OP_READ4,        0, 1, 1, 0x00, 0, 0},
-	{0x00,                   0,                      0, 0, 0, 0x00, 0, 0},
+	{FLASH_FLAG_READ_1_4_4,  SPINOR_OP_READ_1_4_4_4B,  0, 4, 4, 0x00, 2, 4},
+	{FLASH_FLAG_READ_1_1_4,  SPINOR_OP_READ_1_1_4_4B,  0, 1, 4, 0x00, 0, 8},
+	{FLASH_FLAG_READ_1_2_2,  SPINOR_OP_READ_1_2_2_4B,  0, 2, 2, 0x00, 4, 0},
+	{FLASH_FLAG_READ_1_1_2,  SPINOR_OP_READ_1_1_2_4B,  0, 1, 2, 0x00, 0, 8},
+	{FLASH_FLAG_READ_FAST,   SPINOR_OP_READ_FAST_4B,   0, 1, 1, 0x00, 0, 8},
+	{FLASH_FLAG_READ_WRITE,  SPINOR_OP_READ_4B,        0, 1, 1, 0x00, 0, 0},
+	{0x00,                   0,                        0, 0, 0, 0x00, 0, 0},
 };
 
 static struct seq_rw_config stfsm_s25fl_write4_configs[] = {
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 5c87b2d99507..423448c1c7a8 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -75,6 +75,10 @@ struct flash_info {
 					 * bit. Must be used with
 					 * SPI_NOR_HAS_LOCK.
 					 */
+#define SPI_NOR_4B_OPCODES	BIT(10)	/*
+					 * Use dedicated 4byte address op codes
+					 * to support memory size above 128Mib.
+					 */
 };
 
 #define JEDEC_MFR(info)	((info)->id[0])
@@ -188,6 +192,81 @@ static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd)
 	return mtd->priv;
 }
 
+
+struct spi_nor_address_entry {
+	u8	src_opcode;
+	u8	dst_opcode;
+};
+
+static u8 spi_nor_convert_opcode(u8 opcode,
+				 const struct spi_nor_address_entry *entries,
+				 size_t num_entries)
+{
+	int min, max;
+
+	min = 0;
+	max = num_entries - 1;
+	while (min <= max) {
+		int mid = (min + max) >> 1;
+		const struct spi_nor_address_entry *entry = &entries[mid];
+
+		if (opcode == entry->src_opcode)
+			return entry->dst_opcode;
+
+		if (opcode < entry->src_opcode)
+			max = mid - 1;
+		else
+			min = mid + 1;
+	}
+
+	/* No conversion found */
+	return opcode;
+}
+
+static u8 spi_nor_3to4_opcode(u8 opcode)
+{
+	/* MUST be sorted by 3byte opcode */
+#define ENTRY_3TO4(_opcode)	{ _opcode, _opcode##_4B }
+	static const struct spi_nor_address_entry spi_nor_3to4_table[] = {
+		ENTRY_3TO4(SPINOR_OP_PP),		/* 0x02 */
+		ENTRY_3TO4(SPINOR_OP_READ),		/* 0x03 */
+		ENTRY_3TO4(SPINOR_OP_READ_FAST),	/* 0x0b */
+		ENTRY_3TO4(SPINOR_OP_BE_4K),		/* 0x20 */
+		ENTRY_3TO4(SPINOR_OP_PP_1_1_4),		/* 0x32 */
+		ENTRY_3TO4(SPINOR_OP_PP_1_4_4),		/* 0x38 */
+		ENTRY_3TO4(SPINOR_OP_READ_1_1_2),	/* 0x3b */
+		ENTRY_3TO4(SPINOR_OP_BE_32K),		/* 0x52 */
+		ENTRY_3TO4(SPINOR_OP_READ_1_1_4),	/* 0x6b */
+		ENTRY_3TO4(SPINOR_OP_READ_1_2_2),	/* 0xbb */
+		ENTRY_3TO4(SPINOR_OP_SE),		/* 0xd8 */
+		ENTRY_3TO4(SPINOR_OP_READ_1_4_4),	/* 0xeb */
+	};
+#undef ENTRY_3TO4
+
+	return spi_nor_convert_opcode(opcode, spi_nor_3to4_table,
+				      ARRAY_SIZE(spi_nor_3to4_table));
+}
+
+static void spi_nor_set_4byte_opcodes(struct spi_nor *nor,
+				      const struct flash_info *info)
+{
+	/* Do some manufacturer fixups first */
+	switch (JEDEC_MFR(info)) {
+	case SNOR_MFR_SPANSION:
+		/* No small sector erase for 4-byte command set */
+		nor->erase_opcode = SPINOR_OP_SE;
+		nor->mtd.erasesize = info->sector_size;
+		break;
+
+	default:
+		break;
+	}
+
+	nor->read_opcode	= spi_nor_3to4_opcode(nor->read_opcode);
+	nor->program_opcode	= spi_nor_3to4_opcode(nor->program_opcode);
+	nor->erase_opcode	= spi_nor_3to4_opcode(nor->erase_opcode);
+}
+
 /* Enable/disable 4-byte addressing mode. */
 static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info,
 			    int enable)
@@ -1476,27 +1555,10 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 	else if (mtd->size > 0x1000000) {
 		/* enable 4-byte addressing if the device exceeds 16MiB */
 		nor->addr_width = 4;
-		if (JEDEC_MFR(info) == SNOR_MFR_SPANSION) {
-			/* Dedicated 4-byte command set */
-			switch (nor->flash_read) {
-			case SPI_NOR_QUAD:
-				nor->read_opcode = SPINOR_OP_READ4_1_1_4;
-				break;
-			case SPI_NOR_DUAL:
-				nor->read_opcode = SPINOR_OP_READ4_1_1_2;
-				break;
-			case SPI_NOR_FAST:
-				nor->read_opcode = SPINOR_OP_READ4_FAST;
-				break;
-			case SPI_NOR_NORMAL:
-				nor->read_opcode = SPINOR_OP_READ4;
-				break;
-			}
-			nor->program_opcode = SPINOR_OP_PP_4B;
-			/* No small sector erase for 4-byte command set */
-			nor->erase_opcode = SPINOR_OP_SE_4B;
-			mtd->erasesize = info->sector_size;
-		} else
+		if (JEDEC_MFR(info) == SNOR_MFR_SPANSION ||
+		    info->flags & SPI_NOR_4B_OPCODES)
+			spi_nor_set_4byte_opcodes(nor, info);
+		else
 			set_4byte(nor, info, 1);
 	} else {
 		nor->addr_width = 3;
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index c425c7b4c2a0..8b02fd7864d0 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -43,9 +43,13 @@
 #define SPINOR_OP_WRSR		0x01	/* Write status register 1 byte */
 #define SPINOR_OP_READ		0x03	/* Read data bytes (low frequency) */
 #define SPINOR_OP_READ_FAST	0x0b	/* Read data bytes (high frequency) */
-#define SPINOR_OP_READ_1_1_2	0x3b	/* Read data bytes (Dual SPI) */
-#define SPINOR_OP_READ_1_1_4	0x6b	/* Read data bytes (Quad SPI) */
+#define SPINOR_OP_READ_1_1_2	0x3b	/* Read data bytes (Dual Output SPI) */
+#define SPINOR_OP_READ_1_2_2	0xbb	/* Read data bytes (Dual I/O SPI) */
+#define SPINOR_OP_READ_1_1_4	0x6b	/* Read data bytes (Quad Output SPI) */
+#define SPINOR_OP_READ_1_4_4	0xeb	/* Read data bytes (Quad I/O SPI) */
 #define SPINOR_OP_PP		0x02	/* Page program (up to 256 bytes) */
+#define SPINOR_OP_PP_1_1_4	0x32	/* Quad page program */
+#define SPINOR_OP_PP_1_4_4	0x38	/* Quad page program */
 #define SPINOR_OP_BE_4K		0x20	/* Erase 4KiB block */
 #define SPINOR_OP_BE_4K_PMC	0xd7	/* Erase 4KiB block on PMC chips */
 #define SPINOR_OP_BE_32K	0x52	/* Erase 32KiB block */
@@ -56,11 +60,17 @@
 #define SPINOR_OP_RDFSR		0x70	/* Read flag status register */
 
 /* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
-#define SPINOR_OP_READ4		0x13	/* Read data bytes (low frequency) */
-#define SPINOR_OP_READ4_FAST	0x0c	/* Read data bytes (high frequency) */
-#define SPINOR_OP_READ4_1_1_2	0x3c	/* Read data bytes (Dual SPI) */
-#define SPINOR_OP_READ4_1_1_4	0x6c	/* Read data bytes (Quad SPI) */
+#define SPINOR_OP_READ_4B	0x13	/* Read data bytes (low frequency) */
+#define SPINOR_OP_READ_FAST_4B	0x0c	/* Read data bytes (high frequency) */
+#define SPINOR_OP_READ_1_1_2_4B	0x3c	/* Read data bytes (Dual Output SPI) */
+#define SPINOR_OP_READ_1_2_2_4B	0xbc	/* Read data bytes (Dual I/O SPI) */
+#define SPINOR_OP_READ_1_1_4_4B	0x6c	/* Read data bytes (Quad Output SPI) */
+#define SPINOR_OP_READ_1_4_4_4B	0xec	/* Read data bytes (Quad I/O SPI) */
 #define SPINOR_OP_PP_4B		0x12	/* Page program (up to 256 bytes) */
+#define SPINOR_OP_PP_1_1_4_4B	0x34	/* Quad page program */
+#define SPINOR_OP_PP_1_4_4_4B	0x3e	/* Quad page program */
+#define SPINOR_OP_BE_4K_4B	0x21	/* Erase 4KiB block */
+#define SPINOR_OP_BE_32K_4B	0x5c	/* Erase 32KiB block */
 #define SPINOR_OP_SE_4B		0xdc	/* Sector erase (usually 64KiB) */
 
 /* Used for SST flashes only. */
-- 
2.7.4



From cyrille.pitchen at atmel.com  Tue Oct  4 09:37:05 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Tue, 4 Oct 2016 18:37:05 +0200
Subject: [PATCH 3/9] mtd: spi-nor: add support of SPI protocols like SPI 1-2-2
 and SPI 1-4-4
In-Reply-To: <cover.1475597385.git.cyrille.pitchen@atmel.com>
References: <cover.1475597385.git.cyrille.pitchen@atmel.com>
Message-ID: <c131f4512f75a37ef36e33fdb1a8c4cb7fee6c37.1475597385.git.cyrille.pitchen@atmel.com>

This patch changes the prototype of spi_nor_scan(): its 3rd parameter
is replaced by a const struct spi_nor_modes pointer, which tells the
spi-nor framework about which SPI protocols are supported by the SPI
controller.

Besides, this patch also introduces a new spi_nor_basic_flash_parameter
structure telling the spi-nor framework about the SPI protocols supported
by the SPI memory and the needed op codes to use these SPI protocols.

Currently the struct spi_nor_basic_flash_parameter is filled with legacy
values but a later patch will allow to fill it dynamically by reading the
JESD216 Serial Flash Discoverable Parameter (SFDP) tables from the SPI
memory.

With both structures, the spi-nor framework can now compute the best
match between SPI protocols supported by both the (Q)SPI memory and
controller hence selecting the relevant op codes for (Fast) Read, Page
Program and Sector Erase operations.

The spi_nor_basic_flash_parameter structure also provides the spi-nor
framework with the number of dummy cycles to be used with each Fast Read
commands and the erase block size associated to the erase block op codes.

Finally the spi_nor_basic_flash_parameter structure, through the optional
.enable_quad_io() hook, tells the spi-nor framework how to set the Quad
Enable (QE) bit of the QSPI memory to enable its Quad SPI features.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
 drivers/mtd/devices/m25p80.c          |  17 ++-
 drivers/mtd/spi-nor/atmel-quadspi.c   |  83 ++++++----
 drivers/mtd/spi-nor/cadence-quadspi.c |   8 +-
 drivers/mtd/spi-nor/fsl-quadspi.c     |   8 +-
 drivers/mtd/spi-nor/hisi-sfc.c        |   8 +-
 drivers/mtd/spi-nor/mtk-quadspi.c     |  16 +-
 drivers/mtd/spi-nor/nxp-spifi.c       |  21 +--
 drivers/mtd/spi-nor/spi-nor.c         | 280 +++++++++++++++++++++++++++-------
 include/linux/mtd/spi-nor.h           | 136 +++++++++++++++--
 9 files changed, 460 insertions(+), 117 deletions(-)

diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 9cf7fcd28034..f0a55c01406b 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -111,10 +111,10 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
 
 static inline unsigned int m25p80_rx_nbits(struct spi_nor *nor)
 {
-	switch (nor->flash_read) {
-	case SPI_NOR_DUAL:
+	switch (SNOR_PROTO_DATA_FROM_PROTO(nor->read_proto)) {
+	case 2:
 		return 2;
-	case SPI_NOR_QUAD:
+	case 4:
 		return 4;
 	default:
 		return 0;
@@ -195,7 +195,10 @@ static int m25p_probe(struct spi_device *spi)
 	struct flash_platform_data	*data;
 	struct m25p *flash;
 	struct spi_nor *nor;
-	enum read_mode mode = SPI_NOR_NORMAL;
+	struct spi_nor_modes modes = {
+		.rd_modes = SNOR_MODE_SLOW,
+		.wr_modes = SNOR_MODE_1_1_1,
+	};
 	char *flash_name;
 	int ret;
 
@@ -221,9 +224,9 @@ static int m25p_probe(struct spi_device *spi)
 	flash->spi = spi;
 
 	if (spi->mode & SPI_RX_QUAD)
-		mode = SPI_NOR_QUAD;
+		modes.rd_modes |= SNOR_MODE_1_1_4;
 	else if (spi->mode & SPI_RX_DUAL)
-		mode = SPI_NOR_DUAL;
+		modes.rd_modes |= SNOR_MODE_1_1_2;
 
 	if (data && data->name)
 		nor->mtd.name = data->name;
@@ -240,7 +243,7 @@ static int m25p_probe(struct spi_device *spi)
 	else
 		flash_name = spi->modalias;
 
-	ret = spi_nor_scan(nor, flash_name, mode);
+	ret = spi_nor_scan(nor, flash_name, &modes);
 	if (ret)
 		return ret;
 
diff --git a/drivers/mtd/spi-nor/atmel-quadspi.c b/drivers/mtd/spi-nor/atmel-quadspi.c
index 47937d9beec6..9f7e3124e8b8 100644
--- a/drivers/mtd/spi-nor/atmel-quadspi.c
+++ b/drivers/mtd/spi-nor/atmel-quadspi.c
@@ -275,14 +275,48 @@ static void atmel_qspi_debug_command(struct atmel_qspi *aq,
 
 static int atmel_qspi_run_command(struct atmel_qspi *aq,
 				  const struct atmel_qspi_command *cmd,
-				  u32 ifr_tfrtyp, u32 ifr_width)
+				  u32 ifr_tfrtyp, enum spi_nor_protocol proto)
 {
 	u32 iar, icr, ifr, sr;
 	int err = 0;
 
 	iar = 0;
 	icr = 0;
-	ifr = ifr_tfrtyp | ifr_width;
+	ifr = ifr_tfrtyp;
+
+	/* Set the SPI protocol */
+	switch (proto) {
+	case SNOR_PROTO_1_1_1:
+		ifr |= QSPI_IFR_WIDTH_SINGLE_BIT_SPI;
+		break;
+
+	case SNOR_PROTO_1_1_2:
+		ifr |= QSPI_IFR_WIDTH_DUAL_OUTPUT;
+		break;
+
+	case SNOR_PROTO_1_1_4:
+		ifr |= QSPI_IFR_WIDTH_QUAD_OUTPUT;
+		break;
+
+	case SNOR_PROTO_1_2_2:
+		ifr |= QSPI_IFR_WIDTH_DUAL_IO;
+		break;
+
+	case SNOR_PROTO_1_4_4:
+		ifr |= QSPI_IFR_WIDTH_QUAD_IO;
+		break;
+
+	case SNOR_PROTO_2_2_2:
+		ifr |= QSPI_IFR_WIDTH_DUAL_CMD;
+		break;
+
+	case SNOR_PROTO_4_4_4:
+		ifr |= QSPI_IFR_WIDTH_QUAD_CMD;
+		break;
+
+	default:
+		return -EINVAL;
+	}
 
 	/* Compute instruction parameters */
 	if (cmd->enable.bits.instruction) {
@@ -434,7 +468,7 @@ static int atmel_qspi_read_reg(struct spi_nor *nor, u8 opcode,
 	cmd.rx_buf = buf;
 	cmd.buf_len = len;
 	return atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_READ,
-				      QSPI_IFR_WIDTH_SINGLE_BIT_SPI);
+				      nor->reg_proto);
 }
 
 static int atmel_qspi_write_reg(struct spi_nor *nor, u8 opcode,
@@ -450,7 +484,7 @@ static int atmel_qspi_write_reg(struct spi_nor *nor, u8 opcode,
 	cmd.tx_buf = buf;
 	cmd.buf_len = len;
 	return atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_WRITE,
-				      QSPI_IFR_WIDTH_SINGLE_BIT_SPI);
+				      nor->reg_proto);
 }
 
 static ssize_t atmel_qspi_write(struct spi_nor *nor, loff_t to, size_t len,
@@ -469,7 +503,7 @@ static ssize_t atmel_qspi_write(struct spi_nor *nor, loff_t to, size_t len,
 	cmd.tx_buf = write_buf;
 	cmd.buf_len = len;
 	ret = atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_WRITE_MEM,
-				     QSPI_IFR_WIDTH_SINGLE_BIT_SPI);
+				     nor->write_proto);
 	return (ret < 0) ? ret : len;
 }
 
@@ -484,7 +518,7 @@ static int atmel_qspi_erase(struct spi_nor *nor, loff_t offs)
 	cmd.instruction = nor->erase_opcode;
 	cmd.address = (u32)offs;
 	return atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_WRITE,
-				      QSPI_IFR_WIDTH_SINGLE_BIT_SPI);
+				      nor->reg_proto);
 }
 
 static ssize_t atmel_qspi_read(struct spi_nor *nor, loff_t from, size_t len,
@@ -493,27 +527,8 @@ static ssize_t atmel_qspi_read(struct spi_nor *nor, loff_t from, size_t len,
 	struct atmel_qspi *aq = nor->priv;
 	struct atmel_qspi_command cmd;
 	u8 num_mode_cycles, num_dummy_cycles;
-	u32 ifr_width;
 	ssize_t ret;
 
-	switch (nor->flash_read) {
-	case SPI_NOR_NORMAL:
-	case SPI_NOR_FAST:
-		ifr_width = QSPI_IFR_WIDTH_SINGLE_BIT_SPI;
-		break;
-
-	case SPI_NOR_DUAL:
-		ifr_width = QSPI_IFR_WIDTH_DUAL_OUTPUT;
-		break;
-
-	case SPI_NOR_QUAD:
-		ifr_width = QSPI_IFR_WIDTH_QUAD_OUTPUT;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
 	if (nor->read_dummy >= 2) {
 		num_mode_cycles = 2;
 		num_dummy_cycles = nor->read_dummy - 2;
@@ -536,7 +551,7 @@ static ssize_t atmel_qspi_read(struct spi_nor *nor, loff_t from, size_t len,
 	cmd.rx_buf = read_buf;
 	cmd.buf_len = len;
 	ret = atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_READ_MEM,
-				     ifr_width);
+				     nor->read_proto);
 	return (ret < 0) ? ret : len;
 }
 
@@ -596,6 +611,20 @@ static int atmel_qspi_probe(struct platform_device *pdev)
 	struct spi_nor *nor;
 	struct mtd_info *mtd;
 	int irq, err = 0;
+	struct spi_nor_modes modes = {
+		.rd_modes = (SNOR_MODE_SLOW |
+			     SNOR_MODE_1_1_1 |
+			     SNOR_MODE_1_1_2 |
+			     SNOR_MODE_1_1_4 |
+			     SNOR_MODE_1_2_2 |
+			     SNOR_MODE_1_4_4),
+		.wr_modes = (SNOR_MODE_SLOW |
+			     SNOR_MODE_1_1_1 |
+			     SNOR_MODE_1_1_2 |
+			     SNOR_MODE_1_1_4 |
+			     SNOR_MODE_1_2_2 |
+			     SNOR_MODE_1_4_4),
+	};
 
 	if (of_get_child_count(np) != 1)
 		return -ENODEV;
@@ -679,7 +708,7 @@ static int atmel_qspi_probe(struct platform_device *pdev)
 	if (err)
 		goto disable_clk;
 
-	err = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
+	err = spi_nor_scan(nor, NULL, &modes);
 	if (err)
 		goto disable_clk;
 
diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c
index d403ba7b8f43..0e2eefaad94e 100644
--- a/drivers/mtd/spi-nor/cadence-quadspi.c
+++ b/drivers/mtd/spi-nor/cadence-quadspi.c
@@ -1074,6 +1074,12 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
 	struct mtd_info *mtd;
 	unsigned int cs;
 	int i, ret;
+	static const struct spi_nor_modes modes = {
+		.rd_modes = (SNOR_MODE_SLOW |
+			     SNOR_MODE_1_1_1 |
+			     SNOR_MODE_1_1_4),
+		.wr_modes = SNOR_MODE_1_1_1,
+	};
 
 	/* Get flash device data */
 	for_each_available_child_of_node(dev->of_node, np) {
@@ -1119,7 +1125,7 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
 			goto err;
 		}
 
-		ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
+		ret = spi_nor_scan(nor, NULL, &modes);
 		if (ret)
 			goto err;
 
diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c
index 5c82e4ef1904..01e7356d6623 100644
--- a/drivers/mtd/spi-nor/fsl-quadspi.c
+++ b/drivers/mtd/spi-nor/fsl-quadspi.c
@@ -980,6 +980,12 @@ static int fsl_qspi_probe(struct platform_device *pdev)
 	struct spi_nor *nor;
 	struct mtd_info *mtd;
 	int ret, i = 0;
+	static const struct spi_nor_modes modes = {
+		.rd_modes = (SNOR_MODE_SLOW |
+			     SNOR_MODE_1_1_1 |
+			     SNOR_MODE_1_1_4),
+		.wr_modes = SNOR_MODE_1_1_1,
+	};
 
 	q = devm_kzalloc(dev, sizeof(*q), GFP_KERNEL);
 	if (!q)
@@ -1081,7 +1087,7 @@ static int fsl_qspi_probe(struct platform_device *pdev)
 		/* set the chip address for READID */
 		fsl_qspi_set_base_addr(q, nor);
 
-		ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
+		ret = spi_nor_scan(nor, NULL, &modes);
 		if (ret)
 			goto mutex_failed;
 
diff --git a/drivers/mtd/spi-nor/hisi-sfc.c b/drivers/mtd/spi-nor/hisi-sfc.c
index 20378b0d55e9..36b3e7d913b8 100644
--- a/drivers/mtd/spi-nor/hisi-sfc.c
+++ b/drivers/mtd/spi-nor/hisi-sfc.c
@@ -326,6 +326,12 @@ static int hisi_spi_nor_register(struct device_node *np,
 	struct hifmc_priv *priv;
 	struct mtd_info *mtd;
 	int ret;
+	static const struct spi_nor_modes modes = {
+		.rd_modes = (SNOR_MODE_SLOW |
+			     SNOR_MODE_1_1_1 |
+			     SNOR_MODE_1_1_4),
+		.wr_modes = SNOR_MODE_1_1_1,
+	};
 
 	nor = devm_kzalloc(dev, sizeof(*nor), GFP_KERNEL);
 	if (!nor)
@@ -362,7 +368,7 @@ static int hisi_spi_nor_register(struct device_node *np,
 	nor->read = hisi_spi_nor_read;
 	nor->write = hisi_spi_nor_write;
 	nor->erase = NULL;
-	ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
+	ret = spi_nor_scan(nor, NULL, &modes);
 	if (ret)
 		return ret;
 
diff --git a/drivers/mtd/spi-nor/mtk-quadspi.c b/drivers/mtd/spi-nor/mtk-quadspi.c
index e661877c23de..4dc2bb8eb488 100644
--- a/drivers/mtd/spi-nor/mtk-quadspi.c
+++ b/drivers/mtd/spi-nor/mtk-quadspi.c
@@ -121,20 +121,20 @@ static void mt8173_nor_set_read_mode(struct mt8173_nor *mt8173_nor)
 {
 	struct spi_nor *nor = &mt8173_nor->nor;
 
-	switch (nor->flash_read) {
-	case SPI_NOR_FAST:
+	switch (SNOR_PROTO_DATA_FROM_PROTO(nor->read_proto)) {
+	case 1:
 		writeb(nor->read_opcode, mt8173_nor->base +
 		       MTK_NOR_PRGDATA3_REG);
 		writeb(MTK_NOR_FAST_READ, mt8173_nor->base +
 		       MTK_NOR_CFG1_REG);
 		break;
-	case SPI_NOR_DUAL:
+	case 2:
 		writeb(nor->read_opcode, mt8173_nor->base +
 		       MTK_NOR_PRGDATA3_REG);
 		writeb(MTK_NOR_DUAL_READ_EN, mt8173_nor->base +
 		       MTK_NOR_DUAL_REG);
 		break;
-	case SPI_NOR_QUAD:
+	case 4:
 		writeb(nor->read_opcode, mt8173_nor->base +
 		       MTK_NOR_PRGDATA4_REG);
 		writeb(MTK_NOR_QUAD_READ_EN, mt8173_nor->base +
@@ -383,6 +383,12 @@ static int mtk_nor_init(struct mt8173_nor *mt8173_nor,
 {
 	int ret;
 	struct spi_nor *nor;
+	static const struct spi_nor_modes modes = {
+		.rd_modes = (SNOR_MODE_SLOW |
+			     SNOR_MODE_1_1_1 |
+			     SNOR_MODE_1_1_2),
+		.wr_modes = SNOR_MODE_1_1_1,
+	};
 
 	/* initialize controller to accept commands */
 	writel(MTK_NOR_ENABLE_SF_CMD, mt8173_nor->base + MTK_NOR_WRPROT_REG);
@@ -399,7 +405,7 @@ static int mtk_nor_init(struct mt8173_nor *mt8173_nor,
 	nor->write_reg = mt8173_nor_write_reg;
 	nor->mtd.name = "mtk_nor";
 	/* initialized with NULL */
-	ret = spi_nor_scan(nor, NULL, SPI_NOR_DUAL);
+	ret = spi_nor_scan(nor, NULL, &modes);
 	if (ret)
 		return ret;
 
diff --git a/drivers/mtd/spi-nor/nxp-spifi.c b/drivers/mtd/spi-nor/nxp-spifi.c
index 73a14f40928b..327c5b5fe9da 100644
--- a/drivers/mtd/spi-nor/nxp-spifi.c
+++ b/drivers/mtd/spi-nor/nxp-spifi.c
@@ -240,13 +240,12 @@ static int nxp_spifi_erase(struct spi_nor *nor, loff_t offs)
 
 static int nxp_spifi_setup_memory_cmd(struct nxp_spifi *spifi)
 {
-	switch (spifi->nor.flash_read) {
-	case SPI_NOR_NORMAL:
-	case SPI_NOR_FAST:
+	switch (SNOR_PROTO_DATA_FROM_PROTO(spifi->nor.read_proto)) {
+	case 1:
 		spifi->mcmd = SPIFI_CMD_FIELDFORM_ALL_SERIAL;
 		break;
-	case SPI_NOR_DUAL:
-	case SPI_NOR_QUAD:
+	case 2:
+	case 4:
 		spifi->mcmd = SPIFI_CMD_FIELDFORM_QUAD_DUAL_DATA;
 		break;
 	default:
@@ -274,7 +273,10 @@ static void nxp_spifi_dummy_id_read(struct spi_nor *nor)
 static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
 				 struct device_node *np)
 {
-	enum read_mode flash_read;
+	struct spi_nor_modes modes = {
+		.rd_modes = (SNOR_MODE_SLOW | SNOR_MODE_1_1_1),
+		.wr_modes = SNOR_MODE_1_1_1,
+	};
 	u32 ctrl, property;
 	u16 mode = 0;
 	int ret;
@@ -308,13 +310,12 @@ static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
 
 	if (mode & SPI_RX_DUAL) {
 		ctrl |= SPIFI_CTRL_DUAL;
-		flash_read = SPI_NOR_DUAL;
+		modes.rd_modes |= SNOR_MODE_1_1_2;
 	} else if (mode & SPI_RX_QUAD) {
 		ctrl &= ~SPIFI_CTRL_DUAL;
-		flash_read = SPI_NOR_QUAD;
+		modes.rd_modes |= SNOR_MODE_1_1_4;
 	} else {
 		ctrl |= SPIFI_CTRL_DUAL;
-		flash_read = SPI_NOR_NORMAL;
 	}
 
 	switch (mode & (SPI_CPHA | SPI_CPOL)) {
@@ -351,7 +352,7 @@ static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
 	 */
 	nxp_spifi_dummy_id_read(&spifi->nor);
 
-	ret = spi_nor_scan(&spifi->nor, NULL, flash_read);
+	ret = spi_nor_scan(&spifi->nor, NULL, &modes);
 	if (ret) {
 		dev_err(spifi->dev, "device scan failed\n");
 		return ret;
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 423448c1c7a8..51eac2278ec0 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -143,24 +143,6 @@ static int read_cr(struct spi_nor *nor)
 }
 
 /*
- * Dummy Cycle calculation for different type of read.
- * It can be used to support more commands with
- * different dummy cycle requirements.
- */
-static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor)
-{
-	switch (nor->flash_read) {
-	case SPI_NOR_FAST:
-	case SPI_NOR_DUAL:
-	case SPI_NOR_QUAD:
-		return 8;
-	case SPI_NOR_NORMAL:
-		return 0;
-	}
-	return 0;
-}
-
-/*
  * Write status register 1 byte
  * Returns negative if error occurred.
  */
@@ -1384,8 +1366,206 @@ static int spi_nor_check(struct spi_nor *nor)
 	return 0;
 }
 
-int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+static inline void spi_nor_set_read_settings(struct spi_nor_read *read,
+					     u8 num_mode_clocks,
+					     u8 num_wait_states,
+					     u8 opcode)
+{
+	read->num_mode_clocks = num_mode_clocks;
+	read->num_wait_states = num_wait_states;
+	read->opcode = opcode;
+}
+
+static inline void spi_nor_set_erase_settings(struct spi_nor_erase_type *erase,
+					      u8 size, u8 opcode)
+{
+	erase->size = size;
+	erase->opcode = opcode;
+}
+
+static int spi_nor_init_params(struct spi_nor *nor,
+			       const struct flash_info *info,
+			       struct spi_nor_basic_flash_parameter *params)
+{
+	// TODO: parse SFDP table
+
+	/* If SFDP tables are not available, use legacy settings. */
+	memset(params, 0, sizeof(*params));
+
+	/* (Fast) Read settings. */
+	params->rd_modes = SNOR_MODE_SLOW;
+	spi_nor_set_read_settings(&params->reads[SNOR_PINDEX_SLOW],
+				  0, 0, SPINOR_OP_READ);
+	if (!(info->flags & SPI_NOR_NO_FR)) {
+		params->rd_modes |= SNOR_MODE_1_1_1;
+		spi_nor_set_read_settings(&params->reads[SNOR_PINDEX_1_1_1],
+					  0, 8, SPINOR_OP_READ_FAST);
+	}
+	if (info->flags & SPI_NOR_DUAL_READ) {
+		params->rd_modes |= SNOR_MODE_1_1_2;
+		spi_nor_set_read_settings(&params->reads[SNOR_PINDEX_1_1_2],
+					  0, 8, SPINOR_OP_READ_1_1_2);
+	}
+	if (info->flags & SPI_NOR_QUAD_READ) {
+		params->rd_modes|= SNOR_MODE_1_1_4;
+		spi_nor_set_read_settings(&params->reads[SNOR_PINDEX_1_1_4],
+					  0, 8, SPINOR_OP_READ_1_1_4);
+	}
+
+	/* Page Program settings. */
+	params->wr_modes = SNOR_MODE_1_1_1;
+	params->page_programs[SNOR_PINDEX_1_1_1] = SPINOR_OP_PP;
+
+	/* Sector Erase settings. */
+	spi_nor_set_erase_settings(&params->erase_types[0],
+				   SNOR_ERASE_64K, SPINOR_OP_SE);
+	if (info->flags & SECT_4K)
+		spi_nor_set_erase_settings(&params->erase_types[1],
+					   SNOR_ERASE_4K, SPINOR_OP_BE_4K);
+	else if (info->flags & SECT_4K_PMC)
+		spi_nor_set_erase_settings(&params->erase_types[1],
+					   SNOR_ERASE_4K, SPINOR_OP_BE_4K_PMC);
+
+	/* Select the procedure to set the Quad Enable bit. */
+	if (params->rd_modes & (SNOR_MODE_1_1_4 |
+				SNOR_MODE_1_4_4 |
+				SNOR_MODE_4_4_4)) {
+		switch (JEDEC_MFR(info)) {
+		case SNOR_MFR_MACRONIX:
+			params->enable_quad_io = macronix_quad_enable;
+			break;
+
+		case SNOR_MFR_MICRON:
+			break;
+
+		default:
+			params->enable_quad_io = spansion_quad_enable;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int spi_nor_pindex2proto(int pindex, enum spi_nor_protocol *proto)
+{
+	enum spi_nor_protocol_width pwidth;
+	enum spi_nor_protocol_class pclass;
+	uint8_t width;
+
+	if (pindex < 0)
+		return -EINVAL;
+
+	pwidth = (enum spi_nor_protocol_width)(pindex / SNOR_PCLASS_MAX);
+	pclass = (enum spi_nor_protocol_class)(pindex % SNOR_PCLASS_MAX);
+
+	width = (1 << pwidth) & 0xf;
+	if (!width)
+		return -EINVAL;
+
+	switch (pclass) {
+	case SNOR_PCLASS_1_1_N:
+		*proto = SNOR_PROTO(1, 1, width);
+		break;
+
+	case SNOR_PCLASS_1_N_N:
+		*proto = SNOR_PROTO(1, width, width);
+		break;
+
+	case SNOR_PCLASS_N_N_N:
+		*proto = SNOR_PROTO(width, width, width);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
+			 const struct spi_nor_basic_flash_parameter *params,
+			 const struct spi_nor_modes *modes)
 {
+	bool enable_quad_io;
+	u32 rd_modes, wr_modes, mask;
+	const struct spi_nor_erase_type *erase_type = NULL;
+	const struct spi_nor_read *read;
+	int rd_pindex, wr_pindex, i, err = 0;
+	u8 erase_size = SNOR_ERASE_64K;
+
+	/* 2-2-2 or 4-4-4 modes are not supported yet. */
+	mask = (SNOR_MODE_2_2_2 | SNOR_MODE_4_4_4);
+	rd_modes = modes->rd_modes & ~mask;
+	wr_modes = modes->wr_modes & ~mask;
+
+	/* Setup read operation. */
+	rd_pindex = fls(params->rd_modes & rd_modes) - 1;
+	if (spi_nor_pindex2proto(rd_pindex, &nor->read_proto)) {
+		dev_err(nor->dev, "invalid (fast) read\n");
+		return -EINVAL;
+	}
+	read = &params->reads[rd_pindex];
+	nor->read_opcode = read->opcode;
+	nor->read_dummy = read->num_mode_clocks + read->num_wait_states;
+
+	/* Set page program op code and protocol. */
+	wr_pindex = fls(params->wr_modes & wr_modes) - 1;
+	if (spi_nor_pindex2proto(wr_pindex, &nor->write_proto)) {
+		dev_err(nor->dev, "invalid page program\n");
+		return -EINVAL;
+	}
+	nor->program_opcode = params->page_programs[wr_pindex];
+
+	/* Set sector erase op code and size. */
+	erase_type = &params->erase_types[0];
+#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
+	erase_size = SNOR_ERASE_4K;
+#endif
+	for (i = 0; i < SNOR_MAX_ERASE_TYPES; ++i) {
+		if (params->erase_types[i].size == erase_size) {
+			erase_type = &params->erase_types[i];
+			break;
+		} else if (!erase_type->size && params->erase_types[i].size) {
+			erase_type = &params->erase_types[i];
+		}
+	}
+	nor->erase_opcode = erase_type->opcode;
+	nor->mtd.erasesize = (1 << erase_type->size);
+
+
+	enable_quad_io = (SNOR_PROTO_DATA_FROM_PROTO(nor->read_proto) == 4 ||
+			  SNOR_PROTO_DATA_FROM_PROTO(nor->write_proto) == 4);
+
+	/* Enable Quad I/O if needed. */
+	if (enable_quad_io && params->enable_quad_io) {
+		err = params->enable_quad_io(nor);
+		if (err) {
+			dev_err(nor->dev,
+				"failed to enable the Quad I/O mode\n");
+			return err;
+		}
+	}
+
+	dev_dbg(nor->dev,
+		"(Fast) Read:  opcode=%02Xh, protocol=%03x, mode=%u, wait=%u\n",
+		nor->read_opcode, nor->read_proto,
+		read->num_mode_clocks, read->num_wait_states);
+	dev_dbg(nor->dev,
+		"Page Program: opcode=%02Xh, protocol=%03x\n",
+		nor->program_opcode, nor->write_proto);
+	dev_dbg(nor->dev,
+		"Sector Erase: opcode=%02Xh, protocol=%03x, sector size=%u\n",
+		nor->erase_opcode, nor->reg_proto, (u32)nor->mtd.erasesize);
+
+	return 0;
+}
+
+int spi_nor_scan(struct spi_nor *nor, const char *name,
+		 const struct spi_nor_modes *modes)
+{
+	struct spi_nor_basic_flash_parameter params;
+	struct spi_nor_modes fixed_modes = *modes;
 	const struct flash_info *info = NULL;
 	struct device *dev = nor->dev;
 	struct mtd_info *mtd = &nor->mtd;
@@ -1397,6 +1577,11 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 	if (ret)
 		return ret;
 
+	/* Reset SPI protocol for all commands */
+	nor->reg_proto = SNOR_PROTO_1_1_1;
+	nor->read_proto = SNOR_PROTO_1_1_1;
+	nor->write_proto = SNOR_PROTO_1_1_1;
+
 	if (name)
 		info = spi_nor_match_id(name);
 	/* Try to auto-detect if chip name wasn't specified or not found */
@@ -1429,6 +1614,11 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 		}
 	}
 
+	/* Parse the Serial Flash Discoverable Parameters table */
+	ret = spi_nor_init_params(nor, info, &params);
+	if (ret)
+		return ret;
+
 	mutex_init(&nor->lock);
 
 	/*
@@ -1505,51 +1695,31 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 	if (np) {
 		/* If we were instantiated by DT, use it */
 		if (of_property_read_bool(np, "m25p,fast-read"))
-			nor->flash_read = SPI_NOR_FAST;
+			fixed_modes.rd_modes |= SNOR_MODE_1_1_1;
 		else
-			nor->flash_read = SPI_NOR_NORMAL;
+			fixed_modes.rd_modes &= ~SNOR_MODE_1_1_1;
 	} else {
 		/* If we weren't instantiated by DT, default to fast-read */
-		nor->flash_read = SPI_NOR_FAST;
+		fixed_modes.rd_modes |= SNOR_MODE_1_1_1;
 	}
 
 	/* Some devices cannot do fast-read, no matter what DT tells us */
 	if (info->flags & SPI_NOR_NO_FR)
-		nor->flash_read = SPI_NOR_NORMAL;
-
-	/* Quad/Dual-read mode takes precedence over fast/normal */
-	if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) {
-		ret = set_quad_mode(nor, info);
-		if (ret) {
-			dev_err(dev, "quad mode not supported\n");
-			return ret;
-		}
-		nor->flash_read = SPI_NOR_QUAD;
-	} else if (mode == SPI_NOR_DUAL && info->flags & SPI_NOR_DUAL_READ) {
-		nor->flash_read = SPI_NOR_DUAL;
-	}
-
-	/* Default commands */
-	switch (nor->flash_read) {
-	case SPI_NOR_QUAD:
-		nor->read_opcode = SPINOR_OP_READ_1_1_4;
-		break;
-	case SPI_NOR_DUAL:
-		nor->read_opcode = SPINOR_OP_READ_1_1_2;
-		break;
-	case SPI_NOR_FAST:
-		nor->read_opcode = SPINOR_OP_READ_FAST;
-		break;
-	case SPI_NOR_NORMAL:
-		nor->read_opcode = SPINOR_OP_READ;
-		break;
-	default:
-		dev_err(dev, "No Read opcode defined\n");
-		return -EINVAL;
-	}
+		fixed_modes.rd_modes &= ~SNOR_MODE_1_1_1;
 
 	nor->program_opcode = SPINOR_OP_PP;
 
+	/*
+	 * Configure the SPI memory:
+	 * - select op codes for (Fast) Read, Page Program and Sector Erase.
+	 * - set the number of dummy cycles (mode cycles + wait states).
+	 * - set the SPI protocols for register and memory accesses.
+	 * - set the Quad Enable bit if needed (required by SPI x-y-4 protos).
+	 */
+	ret = spi_nor_setup(nor, info, &params, &fixed_modes);
+	if (ret)
+		return ret;
+
 	if (info->addr_width)
 		nor->addr_width = info->addr_width;
 	else if (mtd->size > 0x1000000) {
@@ -1570,8 +1740,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 		return -EINVAL;
 	}
 
-	nor->read_dummy = spi_nor_read_dummy_cycles(nor);
-
 	dev_info(dev, "%s (%lld Kbytes)\n", info->name,
 			(long long)mtd->size >> 10);
 
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 8b02fd7864d0..730f33dce1ea 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -110,11 +110,124 @@
 /* Configuration Register bits. */
 #define CR_QUAD_EN_SPAN		BIT(1)	/* Spansion Quad I/O */
 
-enum read_mode {
-	SPI_NOR_NORMAL = 0,
-	SPI_NOR_FAST,
-	SPI_NOR_DUAL,
-	SPI_NOR_QUAD,
+
+/* Supported SPI protocols */
+enum spi_nor_protocol_class {
+	SNOR_PCLASS_1_1_N,
+	SNOR_PCLASS_1_N_N,
+	SNOR_PCLASS_N_N_N,
+
+	SNOR_PCLASS_MAX
+};
+
+enum spi_nor_protocol_width {
+	SNOR_PWIDTH_1,
+	SNOR_PWIDTH_2,
+	SNOR_PWIDTH_4,
+	SNOR_PWIDTH_8,
+};
+
+/* The encoding is chosen so the higher index the higher priority */
+#define SNOR_PINDEX(pwidth, pclass) \
+	((pwidth) * SNOR_PCLASS_MAX + (pclass))
+enum spi_nor_protocol_index {
+	SNOR_PINDEX_SLOW  = SNOR_PINDEX(SNOR_PWIDTH_1, SNOR_PCLASS_1_1_N),
+	/* Little trick to make the difference between Read and Fast Read commands. */
+	SNOR_PINDEX_1_1_1 = SNOR_PINDEX(SNOR_PWIDTH_1, SNOR_PCLASS_1_N_N),
+	SNOR_PINDEX_1_1_2 = SNOR_PINDEX(SNOR_PWIDTH_2, SNOR_PCLASS_1_1_N),
+	SNOR_PINDEX_1_2_2 = SNOR_PINDEX(SNOR_PWIDTH_2, SNOR_PCLASS_1_N_N),
+	SNOR_PINDEX_2_2_2 = SNOR_PINDEX(SNOR_PWIDTH_2, SNOR_PCLASS_N_N_N),
+	SNOR_PINDEX_1_1_4 = SNOR_PINDEX(SNOR_PWIDTH_4, SNOR_PCLASS_1_1_N),
+	SNOR_PINDEX_1_4_4 = SNOR_PINDEX(SNOR_PWIDTH_4, SNOR_PCLASS_1_N_N),
+	SNOR_PINDEX_4_4_4 = SNOR_PINDEX(SNOR_PWIDTH_4, SNOR_PCLASS_N_N_N),
+
+	SNOR_PINDEX_MAX
+};
+
+#define SNOR_MODE_SLOW		BIT(SNOR_PINDEX_SLOW)
+#define SNOR_MODE_1_1_1		BIT(SNOR_PINDEX_1_1_1)
+#define SNOR_MODE_1_1_2		BIT(SNOR_PINDEX_1_1_2)
+#define SNOR_MODE_1_2_2		BIT(SNOR_PINDEX_1_2_2)
+#define SNOR_MODE_2_2_2		BIT(SNOR_PINDEX_2_2_2)
+#define SNOR_MODE_1_1_4		BIT(SNOR_PINDEX_1_1_4)
+#define SNOR_MODE_1_4_4		BIT(SNOR_PINDEX_1_4_4)
+#define SNOR_MODE_4_4_4		BIT(SNOR_PINDEX_4_4_4)
+
+struct spi_nor_modes {
+	u32	rd_modes;	/* supported SPI modes for (Fast) Read */
+	u32	wr_modes;	/* supported SPI modes for Page Program */
+};
+
+
+struct spi_nor_read {
+	u8	num_wait_states:5;
+	u8	num_mode_clocks:3;
+	u8	opcode;
+};
+
+struct spi_nor_erase_type {
+	u8	size;	/* specifies 'N' so erase size = 2^N */
+	u8	opcode;
+};
+
+#define SNOR_ERASE_64K		0x10
+#define SNOR_ERASE_32K		0x0f
+#define SNOR_ERASE_4K		0x0c
+
+struct spi_nor;
+
+#define SNOR_MAX_ERASE_TYPES	4
+
+struct spi_nor_basic_flash_parameter {
+	/* Fast Read settings */
+	u32				rd_modes;
+	struct spi_nor_read		reads[SNOR_PINDEX_MAX];
+
+	/* Page Program settings */
+	u32				wr_modes;
+	u8				page_programs[SNOR_PINDEX_MAX];
+
+	/* Sector Erase settings */
+	struct spi_nor_erase_type	erase_types[SNOR_MAX_ERASE_TYPES];
+
+	int (*enable_quad_io)(struct spi_nor *nor);
+};
+
+
+#define SNOR_PROTO_CODE_OFF	8
+#define SNOR_PROTO_CODE_MASK	GENMASK(11, 8)
+#define SNOR_PROTO_CODE_TO_PROTO(code) \
+	(((code) << SNOR_PROTO_CODE_OFF) & SNOR_PROTO_CODE_MASK)
+#define SNOR_PROTO_CODE_FROM_PROTO(proto) \
+	((((u32)(proto)) & SNOR_PROTO_CODE_MASK) >> SNOR_PROTO_CODE_OFF)
+
+#define SNOR_PROTO_ADDR_OFF	4
+#define SNOR_PROTO_ADDR_MASK	GENMASK(7, 4)
+#define SNOR_PROTO_ADDR_TO_PROTO(addr) \
+	(((addr) << SNOR_PROTO_ADDR_OFF) & SNOR_PROTO_ADDR_MASK)
+#define SNOR_PROTO_ADDR_FROM_PROTO(proto) \
+	((((u32)(proto)) & SNOR_PROTO_ADDR_MASK) >> SNOR_PROTO_ADDR_OFF)
+
+#define SNOR_PROTO_DATA_OFF	0
+#define SNOR_PROTO_DATA_MASK	GENMASK(3, 0)
+#define SNOR_PROTO_DATA_TO_PROTO(data) \
+	(((data) << SNOR_PROTO_DATA_OFF) & SNOR_PROTO_DATA_MASK)
+#define SNOR_PROTO_DATA_FROM_PROTO(proto) \
+	((((u32)(proto)) & SNOR_PROTO_DATA_MASK) >> SNOR_PROTO_DATA_OFF)
+
+#define SNOR_PROTO(code, addr, data)	  \
+	(SNOR_PROTO_CODE_TO_PROTO(code) |   \
+	 SNOR_PROTO_ADDR_TO_PROTO(addr) | \
+	 SNOR_PROTO_DATA_TO_PROTO(data))
+
+enum spi_nor_protocol {
+	SNOR_PROTO_1_1_1 = SNOR_PROTO(1, 1, 1),	/* SPI */
+	SNOR_PROTO_1_1_2 = SNOR_PROTO(1, 1, 2),	/* Dual Output */
+	SNOR_PROTO_1_1_4 = SNOR_PROTO(1, 1, 4),	/* Quad Output */
+	SNOR_PROTO_1_2_2 = SNOR_PROTO(1, 2, 2),	/* Dual IO */
+	SNOR_PROTO_1_4_4 = SNOR_PROTO(1, 4, 4),	/* Quad IO */
+	SNOR_PROTO_2_2_2 = SNOR_PROTO(2, 2, 2),	/* Dual Command */
+	SNOR_PROTO_4_4_4 = SNOR_PROTO(4, 4, 4),	/* Quad Command */
 };
 
 #define SPI_NOR_MAX_CMD_SIZE	8
@@ -142,9 +255,11 @@ enum spi_nor_option_flags {
  * @read_opcode:	the read opcode
  * @read_dummy:		the dummy needed by the read operation
  * @program_opcode:	the program opcode
- * @flash_read:		the mode of the read
  * @sst_write_second:	used by the SST write operation
  * @flags:		flag options for the current SPI-NOR (SNOR_F_*)
+ * @read_proto:		the SPI protocol used by read operations
+ * @write_proto:	the SPI protocol used by write operations
+ * @reg_proto		the SPI protocol used by read_reg/write_reg operations
  * @cmd_buf:		used by the write_reg
  * @prepare:		[OPTIONAL] do some preparations for the
  *			read/write/erase/lock/unlock operations
@@ -173,7 +288,9 @@ struct spi_nor {
 	u8			read_opcode;
 	u8			read_dummy;
 	u8			program_opcode;
-	enum read_mode		flash_read;
+	enum spi_nor_protocol	read_proto;
+	enum spi_nor_protocol	write_proto;
+	enum spi_nor_protocol	reg_proto;
 	bool			sst_write_second;
 	u32			flags;
 	u8			cmd_buf[SPI_NOR_MAX_CMD_SIZE];
@@ -211,7 +328,7 @@ static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor)
  * spi_nor_scan() - scan the SPI NOR
  * @nor:	the spi_nor structure
  * @name:	the chip type name
- * @mode:	the read mode supported by the driver
+ * @modes:	the SPI modes supported by the controller driver
  *
  * The drivers can use this fuction to scan the SPI NOR.
  * In the scanning, it will try to get all the necessary information to
@@ -221,6 +338,7 @@ static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor)
  *
  * Return: 0 for success, others for failure.
  */
-int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode);
+int spi_nor_scan(struct spi_nor *nor, const char *name,
+		 const struct spi_nor_modes *modes);
 
 #endif
-- 
2.7.4



From cyrille.pitchen at atmel.com  Tue Oct  4 09:37:06 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Tue, 4 Oct 2016 18:37:06 +0200
Subject: [PATCH 4/9] mtd: spi-nor: remove unused set_quad_mode() function
In-Reply-To: <cover.1475597385.git.cyrille.pitchen@atmel.com>
References: <cover.1475597385.git.cyrille.pitchen@atmel.com>
Message-ID: <e98e94250cf0372b520d2691ad506900f29a439f.1475597385.git.cyrille.pitchen@atmel.com>

The set_quad_mode() function is no longer used, so we remove it.

This patch is not squashed into the previous patch on purpose for
readiness issue and to ease the review process of the whole series.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 24 ------------------------
 1 file changed, 24 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 51eac2278ec0..ce06c4b49dba 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1331,30 +1331,6 @@ static int spansion_quad_enable(struct spi_nor *nor)
 	return 0;
 }
 
-static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
-{
-	int status;
-
-	switch (JEDEC_MFR(info)) {
-	case SNOR_MFR_MACRONIX:
-		status = macronix_quad_enable(nor);
-		if (status) {
-			dev_err(nor->dev, "Macronix quad-read not enabled\n");
-			return -EINVAL;
-		}
-		return status;
-	case SNOR_MFR_MICRON:
-		return 0;
-	default:
-		status = spansion_quad_enable(nor);
-		if (status) {
-			dev_err(nor->dev, "Spansion quad-read not enabled\n");
-			return -EINVAL;
-		}
-		return status;
-	}
-}
-
 static int spi_nor_check(struct spi_nor *nor)
 {
 	if (!nor->dev || !nor->read || !nor->write ||
-- 
2.7.4



From cyrille.pitchen at atmel.com  Tue Oct  4 09:37:07 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Tue, 4 Oct 2016 18:37:07 +0200
Subject: [PATCH 5/9] mtd: m25p80: add support of dual and quad spi protocols
 to all commands
In-Reply-To: <cover.1475597385.git.cyrille.pitchen@atmel.com>
References: <cover.1475597385.git.cyrille.pitchen@atmel.com>
Message-ID: <9364e0f47398a6152f62b2eeee2b2513c18bdfe1.1475597385.git.cyrille.pitchen@atmel.com>

Before this patch, m25p80_read() supported few SPI protocols:
- regular SPI 1-1-1
- SPI Dual Output 1-1-2
- SPI Quad Output 1-1-4
On the other hand, all other m25p80_*() hooks only supported SPI 1-1-1.

This patch adds support to all currently existing SPI protocols to
cover as many protocols as possible.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
 drivers/mtd/devices/m25p80.c | 193 +++++++++++++++++++++++++++++++++----------
 1 file changed, 149 insertions(+), 44 deletions(-)

diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index f0a55c01406b..38778eac6c21 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -27,22 +27,64 @@
 #include <linux/spi/flash.h>
 #include <linux/mtd/spi-nor.h>
 
-#define	MAX_CMD_SIZE		6
+#define	MAX_CMD_SIZE		16
 struct m25p {
 	struct spi_device	*spi;
 	struct spi_nor		spi_nor;
 	u8			command[MAX_CMD_SIZE];
 };
 
+static inline int m25p80_proto2nbits(enum spi_nor_protocol proto,
+				     unsigned *code_nbits,
+				     unsigned *addr_nbits,
+				     unsigned *data_nbits)
+{
+	if (code_nbits)
+		*code_nbits = SNOR_PROTO_CODE_FROM_PROTO(proto);
+	if (addr_nbits)
+		*addr_nbits = SNOR_PROTO_ADDR_FROM_PROTO(proto);
+	if (data_nbits)
+		*data_nbits = SNOR_PROTO_DATA_FROM_PROTO(proto);
+
+	return 0;
+}
+
 static int m25p80_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len)
 {
 	struct m25p *flash = nor->priv;
 	struct spi_device *spi = flash->spi;
+	unsigned code_nbits, data_nbits;
+	struct spi_transfer xfers[2];
 	int ret;
 
-	ret = spi_write_then_read(spi, &code, 1, val, len);
+	/* Check the total length of command op code and data. */
+	if (len + 1 > MAX_CMD_SIZE)
+		return -EINVAL;
+
+	/* Get transfer protocols (addr_nbits is not relevant here). */
+	ret = m25p80_proto2nbits(nor->reg_proto,
+				 &code_nbits, NULL, &data_nbits);
+	if (ret < 0)
+		return ret;
+
+	/* Set up transfers. */
+	memset(xfers, 0, sizeof(xfers));
+
+	flash->command[0] = code;
+	xfers[0].len = 1;
+	xfers[0].tx_buf = flash->command;
+	xfers[0].tx_nbits = code_nbits;
+
+	xfers[1].len = len;
+	xfers[1].rx_buf = &flash->command[1];
+	xfers[1].rx_nbits = data_nbits;
+
+	/* Process command. */
+	ret = spi_sync_transfer(spi, xfers, 2);
 	if (ret < 0)
 		dev_err(&spi->dev, "error %d reading %x\n", ret, code);
+	else
+		memcpy(val, &flash->command[1], len);
 
 	return ret;
 }
@@ -65,12 +107,42 @@ static int m25p80_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
 {
 	struct m25p *flash = nor->priv;
 	struct spi_device *spi = flash->spi;
+	unsigned code_nbits, data_nbits, num_xfers = 1;
+	struct spi_transfer xfers[2];
+	int ret;
+
+	/* Check the total length of command op code and data. */
+	if (buf && (len + 1 > MAX_CMD_SIZE))
+		return -EINVAL;
+
+	/* Get transfer protocols (addr_nbits is not relevant here). */
+	ret = m25p80_proto2nbits(nor->reg_proto,
+				 &code_nbits, NULL, &data_nbits);
+	if (ret < 0)
+		return ret;
+
+	/* Set up transfer(s). */
+	memset(xfers, 0, sizeof(xfers));
 
 	flash->command[0] = opcode;
-	if (buf)
+	xfers[0].len = 1;
+	xfers[0].tx_buf = flash->command;
+	xfers[0].tx_nbits = code_nbits;
+
+	if (buf) {
 		memcpy(&flash->command[1], buf, len);
+		if (data_nbits == code_nbits) {
+			xfers[0].len += len;
+		} else {
+			xfers[1].len = len;
+			xfers[1].tx_buf = &flash->command[1];
+			xfers[1].tx_nbits = data_nbits;
+			num_xfers++;
+		}
+	}
 
-	return spi_write(spi, flash->command, len + 1);
+	/* Process command. */
+	return spi_sync_transfer(spi, xfers, num_xfers);
 }
 
 static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
@@ -78,27 +150,48 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
 {
 	struct m25p *flash = nor->priv;
 	struct spi_device *spi = flash->spi;
-	struct spi_transfer t[2] = {};
+	unsigned code_nbits, addr_nbits, data_nbits, num_xfers = 1;
+	struct spi_transfer xfers[3];
 	struct spi_message m;
 	int cmd_sz = m25p_cmdsz(nor);
 	ssize_t ret;
 
-	spi_message_init(&m);
-
 	if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
 		cmd_sz = 1;
 
-	flash->command[0] = nor->program_opcode;
-	m25p_addr2cmd(nor, to, flash->command);
+	/* Get transfer protocols. */
+	ret = m25p80_proto2nbits(nor->write_proto,
+				 &code_nbits, &addr_nbits, &data_nbits);
+	if (ret < 0)
+		return ret;
 
-	t[0].tx_buf = flash->command;
-	t[0].len = cmd_sz;
-	spi_message_add_tail(&t[0], &m);
+	/* Set up transfers. */
+	memset(xfers, 0, sizeof(xfers));
+
+	flash->command[0] = nor->program_opcode;
+	xfers[0].len = 1;
+	xfers[0].tx_buf = flash->command;
+	xfers[0].tx_nbits = code_nbits;
+
+	if (cmd_sz > 1) {
+		m25p_addr2cmd(nor, to, flash->command);
+		if (addr_nbits == code_nbits) {
+			xfers[0].len += nor->addr_width;
+		} else {
+			xfers[1].len = nor->addr_width;
+			xfers[1].tx_buf = &flash->command[1];
+			xfers[1].tx_nbits = addr_nbits;
+			num_xfers++;
+		}
+	}
 
-	t[1].tx_buf = buf;
-	t[1].len = len;
-	spi_message_add_tail(&t[1], &m);
+	xfers[num_xfers].len = len;
+	xfers[num_xfers].tx_buf = buf;
+	xfers[num_xfers].tx_nbits = data_nbits;
+	num_xfers++;
 
+	/* Process command. */
+	spi_message_init_with_transfers(&m, xfers, num_xfers);
 	ret = spi_sync(spi, &m);
 	if (ret)
 		return ret;
@@ -109,18 +202,6 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
 	return ret;
 }
 
-static inline unsigned int m25p80_rx_nbits(struct spi_nor *nor)
-{
-	switch (SNOR_PROTO_DATA_FROM_PROTO(nor->read_proto)) {
-	case 2:
-		return 2;
-	case 4:
-		return 4;
-	default:
-		return 0;
-	}
-}
-
 /*
  * Read an address range from the nor chip.  The address range
  * may be any size provided it is within the physical boundaries.
@@ -130,14 +211,22 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
 {
 	struct m25p *flash = nor->priv;
 	struct spi_device *spi = flash->spi;
-	struct spi_transfer t[2];
-	struct spi_message m;
+	unsigned code_nbits, addr_nbits, data_nbits, num_xfers = 1;
 	unsigned int dummy = nor->read_dummy;
 	ssize_t ret;
+	struct spi_transfer xfers[3];
+	struct spi_message m;
+
+	/* Get transfer protocols. */
+	ret = m25p80_proto2nbits(nor->read_proto,
+				 &code_nbits, &addr_nbits, &data_nbits);
+	if (ret < 0)
+		return ret;
 
 	/* convert the dummy cycles to the number of bytes */
-	dummy /= 8;
+	dummy = (dummy * addr_nbits) / 8;
 
+	/* Use the SPI flash API if supported. */
 	if (spi_flash_read_supported(spi)) {
 		struct spi_flash_read_message msg;
 
@@ -149,10 +238,9 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
 		msg.read_opcode = nor->read_opcode;
 		msg.addr_width = nor->addr_width;
 		msg.dummy_bytes = dummy;
-		/* TODO: Support other combinations */
-		msg.opcode_nbits = SPI_NBITS_SINGLE;
-		msg.addr_nbits = SPI_NBITS_SINGLE;
-		msg.data_nbits = m25p80_rx_nbits(nor);
+		msg.opcode_nbits = code_nbits;
+		msg.addr_nbits = addr_nbits;
+		msg.data_nbits = data_nbits;
 
 		ret = spi_flash_read(spi, &msg);
 		if (ret < 0)
@@ -160,21 +248,38 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
 		return msg.retlen;
 	}
 
-	spi_message_init(&m);
-	memset(t, 0, (sizeof t));
+	/* Set up transfers. */
+	memset(xfers, 0, sizeof(xfers));
 
 	flash->command[0] = nor->read_opcode;
-	m25p_addr2cmd(nor, from, flash->command);
+	xfers[0].len = 1;
+	xfers[0].tx_buf = flash->command;
+	xfers[0].tx_nbits = code_nbits;
 
-	t[0].tx_buf = flash->command;
-	t[0].len = m25p_cmdsz(nor) + dummy;
-	spi_message_add_tail(&t[0], &m);
+	m25p_addr2cmd(nor, from, flash->command);
+	/*
+	 * Clear all dummy/mode cycle bits to avoid sending some manufacturer
+	 * specific pattern, which might make the memory enter its Continuous
+	 * Read mode by mistake.
+	 */
+	memset(flash->command + 1 + nor->addr_width, 0, dummy);
+
+	if (addr_nbits == code_nbits) {
+		xfers[0].len += nor->addr_width + dummy;
+	} else {
+		xfers[1].len = nor->addr_width + dummy;
+		xfers[1].tx_buf = &flash->command[1];
+		xfers[1].tx_nbits = addr_nbits;
+		num_xfers++;
+	}
 
-	t[1].rx_buf = buf;
-	t[1].rx_nbits = m25p80_rx_nbits(nor);
-	t[1].len = min(len, spi_max_transfer_size(spi));
-	spi_message_add_tail(&t[1], &m);
+	xfers[num_xfers].len = len;
+	xfers[num_xfers].rx_buf = buf;
+	xfers[num_xfers].rx_nbits = data_nbits;
+	num_xfers++;
 
+	/* Process command. */
+	spi_message_init_with_transfers(&m, xfers, num_xfers);
 	ret = spi_sync(spi, &m);
 	if (ret)
 		return ret;
-- 
2.7.4



From cyrille.pitchen at atmel.com  Tue Oct  4 09:37:08 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Tue, 4 Oct 2016 18:37:08 +0200
Subject: [PATCH 6/9] mtd: spi-nor: parse Serial Flash Discoverable Parameters
 (SFDP) tables
In-Reply-To: <cover.1475597385.git.cyrille.pitchen@atmel.com>
References: <cover.1475597385.git.cyrille.pitchen@atmel.com>
Message-ID: <ac6749c20ce62e32bf9f41ed23f64759f7e931ff.1475597385.git.cyrille.pitchen@atmel.com>

This patch adds support the the JESD216B standard and parse the SFDP
tables to dynamically initialize the spi_nor_basic_flash_parameter
structure.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 455 +++++++++++++++++++++++++++++++++++++++++-
 include/linux/mtd/spi-nor.h   |   6 +
 2 files changed, 460 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index ce06c4b49dba..e91b3c39b68e 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -17,6 +17,7 @@
 #include <linux/mutex.h>
 #include <linux/math64.h>
 #include <linux/sizes.h>
+#include <linux/slab.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/of_platform.h>
@@ -79,6 +80,7 @@ struct flash_info {
 					 * Use dedicated 4byte address op codes
 					 * to support memory size above 128Mib.
 					 */
+#define SPI_NOR_SKIP_SFDP	BIT(11) /* Skip read of SFDP tables */
 };
 
 #define JEDEC_MFR(info)	((info)->id[0])
@@ -1331,6 +1333,87 @@ static int spansion_quad_enable(struct spi_nor *nor)
 	return 0;
 }
 
+static int spansion_new_quad_enable(struct spi_nor *nor)
+{
+	u8 sr_cr[2];
+	int ret;
+
+	/* Check current Quad Enable bit value. */
+	ret = read_cr(nor);
+	if (ret < 0) {
+		dev_err(nor->dev,
+			"error while reading configuration register\n");
+		return -EINVAL;
+	}
+	sr_cr[1] = ret;
+	if (sr_cr[1] & CR_QUAD_EN_SPAN)
+		return 0;
+
+	dev_info(nor->dev, "setting Spansion Quad Enable (non-volatile) bit\n");
+
+	/* Keep the current value of the Status Register. */
+	ret = read_sr(nor);
+	if (ret < 0) {
+		dev_err(nor->dev,
+			"error while reading status register\n");
+		return -EINVAL;
+	}
+	sr_cr[0] = ret;
+	sr_cr[1] |= CR_QUAD_EN_SPAN;
+
+	write_enable(nor);
+
+	ret = nor->write_reg(nor, SPINOR_OP_WRSR, sr_cr, 2);
+	if (ret < 0) {
+		dev_err(nor->dev,
+			"error while writing configuration register\n");
+		return -EINVAL;
+	}
+
+	/* read back and check it */
+	ret = read_cr(nor);
+	if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
+		dev_err(nor->dev, "Spansion Quad bit not set\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int sr2_bit7_quad_enable(struct spi_nor *nor)
+{
+	u8 sr2;
+	int ret;
+
+	/* Check current Quad Enable bit value. */
+	ret = nor->read_reg(nor, SPINOR_OP_RDSR2, &sr2, 1);
+	if (ret)
+		return ret;
+	if (sr2 & SR2_QUAD_EN_BIT7)
+		return 0;
+
+	/* Update the Quad Enable bit. */
+	sr2 |= SR2_QUAD_EN_BIT7;
+
+	write_enable(nor);
+
+	ret = nor->write_reg(nor, SPINOR_OP_WRSR2, &sr2, 1);
+	if (ret < 0) {
+		dev_err(nor->dev,
+			"error while writing status register 2\n");
+		return -EINVAL;
+	}
+
+	/* Read back and check it. */
+	ret = nor->read_reg(nor, SPINOR_OP_RDSR2, &sr2, 1);
+	if (ret || !(sr2 & SR2_QUAD_EN_BIT7)) {
+		dev_err(nor->dev, "SR2 Quad bit not set\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int spi_nor_check(struct spi_nor *nor)
 {
 	if (!nor->dev || !nor->read || !nor->write ||
@@ -1359,11 +1442,380 @@ static inline void spi_nor_set_erase_settings(struct spi_nor_erase_type *erase,
 	erase->opcode = opcode;
 }
 
+static int spi_nor_read_sfdp(struct spi_nor *nor, u32 addr, size_t len, void *buf)
+{
+	u8 addr_width, read_opcode, read_dummy;
+	int ret;
+
+	read_opcode = nor->read_opcode;
+	addr_width = nor->addr_width;
+	read_dummy = nor->read_dummy;
+
+	nor->read_opcode = SPINOR_OP_RDSFDP;
+	nor->addr_width = 3;
+	nor->read_dummy = 8;
+
+	ret = nor->read(nor, addr, len, (u8 *)buf);
+
+	nor->read_opcode = read_opcode;
+	nor->addr_width = addr_width;
+	nor->read_dummy = read_dummy;
+
+	return (ret < 0) ? ret : 0;
+}
+
+struct sfdp_parameter_header {
+	u8		id_lsb;
+	u8		minor;
+	u8		major;
+	u8		length; /* in double words */
+	u8		parameter_table_pointer[3]; /* byte address */
+	u8		id_msb;
+};
+
+#define SFDP_PARAM_HEADER_ID(p)	((u16)(((p)->id_msb << 8) | (p)->id_lsb))
+#define SFDP_PARAM_HEADER_PTP(p) \
+	((u32)(((p)->parameter_table_pointer[2] << 16) | \
+	       ((p)->parameter_table_pointer[1] <<  8) | \
+	       ((p)->parameter_table_pointer[0] <<  0)))
+
+
+#define SFDP_BFPT_ID		0xff00u	/* Basic Flash Parameter Table */
+
+#define SFDP_SIGNATURE		0x50444653u
+#define SFDP_JESD216_MAJOR	1
+#define SFDP_JESD216_MINOR	0
+#define SFDP_JESD216A_MINOR	5
+#define SFDP_JESD216B_MINOR	6
+
+struct sfdp_header {
+	u32		signature; /* Ox50444653 <=> "SFDP" */
+	u8		minor;
+	u8		major;
+	u8		nph; /* 0-base number of parameter headers */
+	u8		unused;
+
+	/* Basic Flash Parameter Table. */
+	struct sfdp_parameter_header	bfpt_header;
+};
+
+/* Basic Flash Parameter Table */
+
+/* 1st DWORD. */
+#define BFPT_WORD0_FAST_READ_1_1_2	BIT(16)
+#define BFPT_WORD0_ADDRESS_BYTES_MASK	GENMASK(18, 17)
+#define BFPT_WORD0_ADDRESS_BYTES_3_ONLY	(0u << 17)
+#define BFPT_WORD0_ADDRESS_BYTES_3_OR_4	(1u << 17)
+#define BFPT_WORD0_ADDRESS_BYTES_4_ONLY	(2u << 17)
+#define BFPT_WORD0_DTR			BIT(19)
+#define BFPT_WORD0_FAST_READ_1_2_2	BIT(20)
+#define BFPT_WORD0_FAST_READ_1_4_4	BIT(21)
+#define BFPT_WORD0_FAST_READ_1_1_4	BIT(22)
+
+/* 15th DWORD. */
+
+/*
+ * (from JESD216B)
+ * Quad Enable Requirements (QER):
+ * - 000b: Device does not have a QE bit. Device detects 1-1-4 and 1-4-4
+ *         reads based on instruction. DQ3/HOLD# functions are hold during
+ *         instruction pahse.
+ * - 001b: QE is bit 1 of status register 2. It is set via Write Status with
+ *         two data bytes where bit 1 of the second byte is one.
+ *         [...]
+ *         Writing only one byte to the status register has the side-effect of
+ *         clearing status register 2, including the QE bit. The 100b code is
+ *         used if writing one byte to the status register does not modify
+ *         status register 2.
+ * - 010b: QE is bit 6 of status register 1. It is set via Write Status with
+ *         one data byte where bit 6 is one.
+ *         [...]
+ * - 011b: QE is bit 7 of status register 2. It is set via Write status
+ *         register 2 instruction 3Eh with one data byte where bit 7 is one.
+ *         [...]
+ *         The status register 2 is read using instruction 3Fh.
+ * - 100b: QE is bit 1 of status register 2. It is set via Write Status with
+ *         two data bytes where bit 1 of the second byte is one.
+ *         [...]
+ *         In contrast to the 001b code, writing one byte to the status
+ *         register does not modify status register 2.
+ * - 101b: QE is bit 1 of status register 2. Status register 1 is read using
+ *         Read Status instruction 05h. Status register2 is read using
+ *         instruction 35h. QE is set via Writ Status instruction 01h with
+ *         two data bytes where bit 1 of the second byte is one.
+ *         [...]
+ */
+#define BFPT_WORD14_QER_MASK		GENMASK(22, 20)
+#define BFPT_WORD14_QER_NONE		(0 << 20) /* Micron */
+#define BFPT_WORD14_QER_SR2_BIT1_BUGGY	(1 << 20)
+#define BFPT_WORD14_QER_SR1_BIT6	(2 << 20) /* Macronix */
+#define BFPT_WORD14_QER_SR2_BIT7	(3 << 20)
+#define BFPT_WORD14_QER_SR2_BIT1_NO_RD	(4 << 20)
+#define BFPT_WORD14_QER_SR2_BIT1	(5 << 20) /* Spansion */
+
+/* JESD216B defines a Basic Flash Parameter Table of 16 words. */
+#define SFDP_BFPT_MAX_WORDS	16
+
+struct sfdp_bfpt {
+	u32	word[SFDP_BFPT_MAX_WORDS];
+};
+
+/* Fast Read settings. */
+#define BFPT_FAST_READ_WAIT_STATES(half)	((((u16)(half)) >> 0) & 0x1f)
+#define BFPT_FAST_READ_MODE_CLOCKS(half)	((((u16)(half)) >> 5) & 0x07)
+#define BFPT_FAST_READ_OP_CODE(half)		((((u16)(half)) >> 8) & 0xff)
+
+struct sfdp_read {
+	/* The protocol index of SPI x-y-z. */
+	enum spi_nor_protocol_index	pindex;
+
+	/*
+	 * The bit <wbit> in DWORD<windex> tells us whether the
+	 * Fast Read x-y-z command is supported.
+	 */
+	int				windex;
+	int				wbit;
+
+	/*
+	 * The half-word at offset <hshift> in DWORD<hindex> encodes the
+	 * op code, the number of mode clocks and the number of wait states
+	 * to be used by Fast Read x-y-z commands.
+	 */
+	int				hindex;
+	int				hshift;
+};
+
+static const struct sfdp_read sfdp_reads[] = {
+	/* Supported: DWORD0 bit 16,  Settings: DWORD3 bit[15:0] */
+	{SNOR_PINDEX_1_1_2, 0, 16, 3,  0},
+
+	/* Supported: DWORD0 bit 20,  Settings: DWORD3 bit[31:16] */
+	{SNOR_PINDEX_1_2_2, 0, 20, 3, 16},
+
+	/* Supported: DWORD4 bit  0,  Settings: DWORD5 bit[31:16] */
+	{SNOR_PINDEX_2_2_2, 4,  0, 5, 16},
+
+	/* Supported: DWORD0 bit 22,  Settings: DWORD2 bit[31:16] */
+	{SNOR_PINDEX_1_1_4, 0, 22, 2, 16},
+
+	/* Supported: DWORD0 bit 21,  Settings: DWORD2 bit[15:0] */
+	{SNOR_PINDEX_1_4_4, 0, 21, 2, 0},
+
+	/* Supported: DWORD4 bit  4,  Settings: DWORD6 bit[31:16] */
+	{SNOR_PINDEX_4_4_4, 4, 4, 6, 16},
+};
+
+
+/* Sector Erase settings. */
+#define BFPT_ERASE_SIZE(half)		((((u16)(half)) >> 0) & 0xff)
+#define BFPT_ERASE_OP_CODE(half)	((((u16)(half)) >> 8) & 0xff)
+
+struct sfdp_erase {
+	/*
+	 * The half-word at offset <hshift> in DWORD<hindex> encodes the
+	 * op code and erase sector size to be used by Sector Erase commands.
+	 */
+	int		hindex;
+	int		hshift;
+};
+
+static const struct sfdp_erase sfdp_erases[SNOR_MAX_ERASE_TYPES] = {
+	/* Erase Type 1 in DWORD7 bits[15:0] */
+	{7, 0},
+
+	/* Erase Type 2 in DWORD7 bits[31:16] */
+	{7, 16},
+
+	/* Erase Type 3 in DWORD8 bits[15:0] */
+	{8, 0},
+
+	/* Erase Type 4: in DWORD8 bits[31:16] */
+	{8, 16},
+};
+
+
+static int spi_nor_parse_bfpt(struct spi_nor *nor,
+			      const struct sfdp_parameter_header *bfpt_header,
+			      struct spi_nor_basic_flash_parameter *params)
+{
+	struct sfdp_bfpt bfpt;
+	size_t len;
+	int i, err;
+	u32 addr;
+	u16 half;
+
+	/* JESD216 Basic Flash Parameter Table length is at least 9 words. */
+	if (bfpt_header->length < 9)
+		return -EINVAL;
+
+	/* Read the Basic Flash Parameter Table. */
+	len = min_t(size_t, sizeof(bfpt),
+		    bfpt_header->length * sizeof(uint32_t));
+	addr = SFDP_PARAM_HEADER_PTP(bfpt_header);
+	memset(&bfpt, 0, sizeof(bfpt));
+	err = spi_nor_read_sfdp(nor,  addr, len, &bfpt);
+	if (err)
+		return err;
+
+	for (i = 0; i < SFDP_BFPT_MAX_WORDS; ++i)
+		bfpt.word[i] = le32_to_cpu(bfpt.word[i]);
+
+	memset(params, 0, sizeof(*params));
+
+	/* Fast Read settings. */
+	params->rd_modes = (SNOR_MODE_SLOW | SNOR_MODE_1_1_1);
+	spi_nor_set_read_settings(&params->reads[SNOR_PINDEX_SLOW],
+				  0, 0, SPINOR_OP_READ);
+	spi_nor_set_read_settings(&params->reads[SNOR_PINDEX_1_1_1],
+				  0, 8, SPINOR_OP_READ_FAST);
+
+	for (i = 0; i < ARRAY_SIZE(sfdp_reads); ++i) {
+		const struct sfdp_read *rd_info = &sfdp_reads[i];
+		struct spi_nor_read *read = &params->reads[rd_info->pindex];
+
+		if (!(bfpt.word[rd_info->windex] & BIT(rd_info->wbit)))
+			continue;
+
+		params->rd_modes |= BIT(rd_info->pindex);
+		half = bfpt.word[rd_info->hindex] >> rd_info->hshift;
+		read->num_mode_clocks = BFPT_FAST_READ_MODE_CLOCKS(half);
+		read->num_wait_states = BFPT_FAST_READ_WAIT_STATES(half);
+		read->opcode = BFPT_FAST_READ_OP_CODE(half);
+	}
+
+	/* Page Program settings. */
+	params->wr_modes = SNOR_MODE_1_1_1;
+	params->page_programs[SNOR_PINDEX_1_1_1] = SPINOR_OP_PP;
+
+	/* Sector Erase settings. */
+	for (i = 0; i < SNOR_MAX_ERASE_TYPES; ++i) {
+		const struct sfdp_erase *er_info = &sfdp_erases[i];
+		struct spi_nor_erase_type *erase = &params->erase_types[i];
+
+		half = bfpt.word[er_info->hindex] >> er_info->hshift;
+		erase->size = BFPT_ERASE_SIZE(half);
+		erase->opcode = BFPT_ERASE_OP_CODE(half);
+	}
+
+	/* Stop here if not JESD216 rev B or later. */
+	if (bfpt_header->length < 15)
+		return 0;
+
+	/* Enable Quad I/O. */
+	switch (bfpt.word[14] & BFPT_WORD14_QER_MASK) {
+	default:
+	case BFPT_WORD14_QER_NONE:
+		break;
+
+	case BFPT_WORD14_QER_SR2_BIT1_BUGGY:
+	case BFPT_WORD14_QER_SR2_BIT1_NO_RD:
+		params->enable_quad_io = spansion_quad_enable;
+		break;
+
+	case BFPT_WORD14_QER_SR1_BIT6:
+		params->enable_quad_io = macronix_quad_enable;
+		break;
+
+	case BFPT_WORD14_QER_SR2_BIT7:
+		params->enable_quad_io = sr2_bit7_quad_enable;
+		break;
+
+	case BFPT_WORD14_QER_SR2_BIT1:
+		params->enable_quad_io = spansion_new_quad_enable;
+		break;
+	}
+
+	return 0;
+}
+
+static int spi_nor_parse_sfdp(struct spi_nor *nor,
+			      struct spi_nor_basic_flash_parameter *params)
+{
+	const struct sfdp_parameter_header *param_header, *bfpt_header;
+	struct sfdp_parameter_header *param_headers = NULL;
+	struct sfdp_header header;
+	size_t psize;
+	int i, err;
+
+	/* Get the SFDP header. */
+	err = spi_nor_read_sfdp(nor, 0, sizeof(header), &header);
+	if (err)
+		return err;
+
+	/* Check the SFDP header version. */
+	if (le32_to_cpu(header.signature) != SFDP_SIGNATURE ||
+	    header.major != SFDP_JESD216_MAJOR ||
+	    header.minor < SFDP_JESD216_MINOR)
+		return -EINVAL;
+
+	/*
+	 * Verify that the first and only mandatory parameter header is a
+	 * Basic Flash Parameter Table header as specified in JESD216.
+	 */
+	bfpt_header = &header.bfpt_header;
+	if (SFDP_PARAM_HEADER_ID(bfpt_header) != SFDP_BFPT_ID ||
+	    bfpt_header->major != SFDP_JESD216_MAJOR)
+		return -EINVAL;
+
+	/* Allocate memory for parameter headers. */
+	if (header.nph) {
+		psize = header.nph * sizeof(*param_headers);
+
+		param_headers = kmalloc(psize, GFP_KERNEL);
+		if (!param_headers) {
+			dev_err(nor->dev,
+				"failed to allocate memory for SFDP parameter headers\n");
+			return -ENOMEM;
+		}
+
+		err = spi_nor_read_sfdp(nor, sizeof(header),
+					psize, param_headers);
+		if (err) {
+			dev_err(nor->dev,
+				"failed to read SFDP parameter headers\n");
+			goto exit;
+		}
+	}
+
+	/*
+	 * Check other parameter headers to get the latest revision of
+	 * the basic flash parameter table.
+	 */
+	for (i = 0; i < header.nph; ++i) {
+		param_header = &param_headers[i];
+
+		if (SFDP_PARAM_HEADER_ID(param_header) == SFDP_BFPT_ID &&
+		    param_header->major == SFDP_JESD216_MAJOR &&
+		    (param_header->minor > bfpt_header->minor ||
+		     (param_header->minor == bfpt_header->minor &&
+		      param_header->length > bfpt_header->length)))
+			bfpt_header = param_header;
+	}
+	err = spi_nor_parse_bfpt(nor, bfpt_header, params);
+	if (err)
+		goto exit;
+
+exit:
+	kfree(param_headers);
+	return (err) ? err : bfpt_header->minor;
+}
+
 static int spi_nor_init_params(struct spi_nor *nor,
 			       const struct flash_info *info,
 			       struct spi_nor_basic_flash_parameter *params)
 {
-	// TODO: parse SFDP table
+	int jesd216_minor = -EINVAL;
+
+	/* First trying to parse SFDP tables. */
+	if (!(info->flags & SPI_NOR_SKIP_SFDP)) {
+		jesd216_minor = spi_nor_parse_sfdp(nor, params);
+
+		if (jesd216_minor >= SFDP_JESD216B_MINOR)
+			return 0;
+
+		if (jesd216_minor >= SFDP_JESD216_MINOR)
+			goto set_enable_quad_io;
+	}
 
 	/* If SFDP tables are not available, use legacy settings. */
 	memset(params, 0, sizeof(*params));
@@ -1402,6 +1854,7 @@ static int spi_nor_init_params(struct spi_nor *nor,
 		spi_nor_set_erase_settings(&params->erase_types[1],
 					   SNOR_ERASE_4K, SPINOR_OP_BE_4K_PMC);
 
+set_enable_quad_io:
 	/* Select the procedure to set the Quad Enable bit. */
 	if (params->rd_modes & (SNOR_MODE_1_1_4 |
 				SNOR_MODE_1_4_4 |
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 730f33dce1ea..ede7ad83c9c5 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -41,6 +41,8 @@
 #define SPINOR_OP_WREN		0x06	/* Write enable */
 #define SPINOR_OP_RDSR		0x05	/* Read status register */
 #define SPINOR_OP_WRSR		0x01	/* Write status register 1 byte */
+#define SPINOR_OP_RDSR2		0x3f	/* Read status register 2 */
+#define SPINOR_OP_WRSR2		0x3e	/* Write status register 2 */
 #define SPINOR_OP_READ		0x03	/* Read data bytes (low frequency) */
 #define SPINOR_OP_READ_FAST	0x0b	/* Read data bytes (high frequency) */
 #define SPINOR_OP_READ_1_1_2	0x3b	/* Read data bytes (Dual Output SPI) */
@@ -56,6 +58,7 @@
 #define SPINOR_OP_CHIP_ERASE	0xc7	/* Erase whole flash chip */
 #define SPINOR_OP_SE		0xd8	/* Sector erase (usually 64KiB) */
 #define SPINOR_OP_RDID		0x9f	/* Read JEDEC ID */
+#define SPINOR_OP_RDSFDP	0x5a	/* Read SFDP */
 #define SPINOR_OP_RDCR		0x35	/* Read configuration register */
 #define SPINOR_OP_RDFSR		0x70	/* Read flag status register */
 
@@ -110,6 +113,9 @@
 /* Configuration Register bits. */
 #define CR_QUAD_EN_SPAN		BIT(1)	/* Spansion Quad I/O */
 
+/* Status Register 2 bits. */
+#define SR2_QUAD_EN_BIT7	BIT(7)
+
 
 /* Supported SPI protocols */
 enum spi_nor_protocol_class {
-- 
2.7.4



From cyrille.pitchen at atmel.com  Tue Oct  4 09:37:09 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Tue, 4 Oct 2016 18:37:09 +0200
Subject: [PATCH 7/9] mtd: spi-nor: parse SFDP 4-byte Address Instruction Table
In-Reply-To: <cover.1475597385.git.cyrille.pitchen@atmel.com>
References: <cover.1475597385.git.cyrille.pitchen@atmel.com>
Message-ID: <72325c04339d456b1702404e7c70ade4693a5cfc.1475597385.git.cyrille.pitchen@atmel.com>

This patch adds supports for SFDP (JESD216B) 4-byte Address Instruction
Table. This table is optional but when available, we parse it to get the
4-byte address op codes supported by the memory.
Using these op codes is stateless as opposed to entering the 4-byte
address mode or setting the Base Address Register (BAR).

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 140 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 139 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index e91b3c39b68e..879b98ef1d80 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1481,6 +1481,7 @@ struct sfdp_parameter_header {
 
 
 #define SFDP_BFPT_ID		0xff00u	/* Basic Flash Parameter Table */
+#define SFDP_4BAIT_ID		0xff84u	/* 4-byte Address Instruction Table */
 
 #define SFDP_SIGNATURE		0x50444653u
 #define SFDP_JESD216_MAJOR	1
@@ -1728,6 +1729,124 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
 	return 0;
 }
 
+struct sfdp_4bait {
+	enum spi_nor_protocol_index	pindex;
+	int				wbit;
+};
+
+static int spi_nor_parse_4bait(struct spi_nor *nor,
+			       const struct sfdp_parameter_header *param_header,
+			       struct spi_nor_basic_flash_parameter *params)
+{
+	static const struct sfdp_4bait reads[] = {
+		{SNOR_PINDEX_SLOW,  0},	/* 0x13 */
+		{SNOR_PINDEX_1_1_1, 1}, /* 0x0c */
+		{SNOR_PINDEX_1_1_2, 2}, /* 0x3c */
+		{SNOR_PINDEX_1_2_2, 3},	/* 0xbc */
+		{SNOR_PINDEX_1_1_4, 4},	/* 0x6c */
+		{SNOR_PINDEX_1_4_4, 5},	/* 0xec */
+	};
+	static const struct sfdp_4bait programs[] = {
+		{SNOR_PINDEX_1_1_1, 6}, /* 0x12 */
+		{SNOR_PINDEX_1_1_4, 7}, /* 0x34 */
+		{SNOR_PINDEX_1_4_4, 8}, /* 0x3e */
+	};
+	static const struct sfdp_4bait erases[SNOR_MAX_ERASE_TYPES] = {
+		{SNOR_PINDEX_1_1_1,  9},
+		{SNOR_PINDEX_1_1_1, 10},
+		{SNOR_PINDEX_1_1_1, 11},
+		{SNOR_PINDEX_1_1_1, 12},
+	};
+	u32 word[2], addr, rd_modes, wr_modes, erase_modes;
+	int i, err;
+
+	if (param_header->major != SFDP_JESD216_MAJOR ||
+	    param_header->length < 2)
+		return -EINVAL;
+
+	/* Read the 4-byte Address Instruction Table. */
+	addr = SFDP_PARAM_HEADER_PTP(param_header);
+	err = spi_nor_read_sfdp(nor, addr, sizeof(word), word);
+	if (err)
+		return err;
+
+	for (i = 0; i < 2; ++i)
+		word[i] = le32_to_cpu(word[i]);
+
+	/*
+	 * Compute the subset of (Fast) Read commands for which the 4-byte
+	 * version is supported.
+	 */
+	rd_modes = 0;
+	for (i = 0; i < ARRAY_SIZE(reads); ++i) {
+		const struct sfdp_4bait *read = &reads[i];
+
+		if ((params->rd_modes & BIT(read->pindex)) &&
+		    (word[0] & BIT(read->wbit)))
+			rd_modes |= BIT(read->pindex);
+	}
+
+	/*
+	 * Compute the subset of Page Program commands for which the 4-byte
+	 * version is supported.
+	 */
+	wr_modes = 0;
+	for (i = 0; i < ARRAY_SIZE(programs); ++i) {
+		const struct sfdp_4bait *program = &programs[i];
+
+		if ((params->wr_modes & BIT(program->pindex)) &&
+		    (word[0] & BIT(program->wbit)))
+			wr_modes |= BIT(program->pindex);
+	}
+
+	/*
+	 * Compute the subet of Sector Erase commands for which the 4-byte
+	 * version is supported.
+	 */
+	erase_modes = 0;
+	for (i = 0; i < SNOR_MAX_ERASE_TYPES; ++i) {
+		const struct sfdp_4bait *erase = &erases[i];
+
+		if ((params->erase_types[i].size > 0) &&
+		    (word[0] & BIT(erase->wbit)))
+			erase_modes |= BIT(i);
+	}
+
+	/*
+	 * We need at least one 4-byte op code per read, program and erase
+	 * operation; the .read(), .write() and .erase() hooks share the
+	 * nor->addr_width value.
+	 */
+	if (!rd_modes || !wr_modes || !erase_modes)
+		return 0;
+
+	/*
+	 * Discard all operations from the 4-byte instruction set which are
+	 * not supported by this memory.
+	 */
+	params->rd_modes = rd_modes;
+	params->wr_modes = wr_modes;
+	for (i = 0; i < SNOR_MAX_ERASE_TYPES; ++i)
+		if (!(erase_modes & BIT(i)))
+			params->erase_types[i].size = 0;
+
+	/* Use the 4-byte address instruction set. */
+	params->reads[SNOR_PINDEX_SLOW].opcode  = SPINOR_OP_READ_4B;
+	params->reads[SNOR_PINDEX_1_1_1].opcode = SPINOR_OP_READ_FAST_4B;
+	params->reads[SNOR_PINDEX_1_1_2].opcode = SPINOR_OP_READ_1_1_2_4B;
+	params->reads[SNOR_PINDEX_1_2_2].opcode = SPINOR_OP_READ_1_2_2_4B;
+	params->reads[SNOR_PINDEX_1_1_4].opcode = SPINOR_OP_READ_1_1_4_4B;
+	params->reads[SNOR_PINDEX_1_4_4].opcode = SPINOR_OP_READ_1_4_4_4B;
+	params->page_programs[SNOR_PINDEX_1_1_1] = SPINOR_OP_PP_4B;
+	params->page_programs[SNOR_PINDEX_1_1_4] = SPINOR_OP_PP_1_1_4_4B;
+	params->page_programs[SNOR_PINDEX_1_4_4] = SPINOR_OP_PP_1_4_4_4B;
+	for (i = 0; i < SNOR_MAX_ERASE_TYPES; ++i)
+		params->erase_types[i].opcode = (word[1] >> (i * 8)) & 0xff;
+
+	nor->addr_width = 4;
+	return 0;
+}
+
 static int spi_nor_parse_sfdp(struct spi_nor *nor,
 			      struct spi_nor_basic_flash_parameter *params)
 {
@@ -1795,6 +1914,23 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor,
 	if (err)
 		goto exit;
 
+	/* Parse other parameter headers. */
+	for (i = 0; i < header.nph; ++i) {
+		param_header = &param_headers[i];
+
+		switch (SFDP_PARAM_HEADER_ID(param_header)) {
+		case SFDP_4BAIT_ID:
+			err = spi_nor_parse_4bait(nor, param_header, params);
+			break;
+
+		default:
+			break;
+		}
+
+		if (err)
+			goto exit;
+	}
+
 exit:
 	kfree(param_headers);
 	return (err) ? err : bfpt_header->minor;
@@ -2149,7 +2285,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
 	if (ret)
 		return ret;
 
-	if (info->addr_width)
+	if (nor->addr_width)
+		; /* already configured by spi_nor_setup(). */
+	else if (info->addr_width)
 		nor->addr_width = info->addr_width;
 	else if (mtd->size > 0x1000000) {
 		/* enable 4-byte addressing if the device exceeds 16MiB */
-- 
2.7.4



From cyrille.pitchen at atmel.com  Tue Oct  4 09:37:10 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Tue, 4 Oct 2016 18:37:10 +0200
Subject: [PATCH 8/9] mtd: spi-nor: add support to Macronix mx66l1g45g
In-Reply-To: <cover.1475597385.git.cyrille.pitchen@atmel.com>
References: <cover.1475597385.git.cyrille.pitchen@atmel.com>
Message-ID: <3f42f61ab50fed1c41553963f63bfacc9341adbc.1475597385.git.cyrille.pitchen@atmel.com>

This patch adds an entry in the spi_nor_ids[] table to add support
to the Macronix mx66l1g45g.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 879b98ef1d80..031c6792a3fe 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -937,6 +937,7 @@ static const struct flash_info spi_nor_ids[] = {
 	{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
 	{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
 	{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) },
+	{ "mx66l1g45g",  INFO(0xc2201b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
 	{ "mx66l1g55g",  INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
 
 	/* Micron */
-- 
2.7.4



From cyrille.pitchen at atmel.com  Tue Oct  4 09:37:11 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Tue, 4 Oct 2016 18:37:11 +0200
Subject: [PATCH 9/9] mtd: spi-nor: add support to SST sst26* QSPI memories
In-Reply-To: <cover.1475597385.git.cyrille.pitchen@atmel.com>
References: <cover.1475597385.git.cyrille.pitchen@atmel.com>
Message-ID: <f83bd832c8012f12300d04ee419bbc5457c412c3.1475597385.git.cyrille.pitchen@atmel.com>

This patch adds support to the SST sst26* QSPI memories.
It also adds a new SST_BLOCK_PROTECT flag so spi_nor_scan() sends
a SST Global Block Protection Unlock (98h) command once for all
otherwise later Sector Erase and Page Program commands would fail.

It was tested with sst26vf016b, sst26vf032b, sst26vf032ba and sst26vf064b
on a sama5d2 xplained board at 55.3MHz and 3.3V.

sst26wf040b and sst26wf080b were not tested since they are 1.8V memories
hence don't fit the sama5d2 xplained board requirements.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 20 ++++++++++++++++++++
 include/linux/mtd/spi-nor.h   |  1 +
 2 files changed, 21 insertions(+)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 031c6792a3fe..355824bd3587 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -81,6 +81,7 @@ struct flash_info {
 					 * to support memory size above 128Mib.
 					 */
 #define SPI_NOR_SKIP_SFDP	BIT(11) /* Skip read of SFDP tables */
+#define SST_BLOCK_PROTECT	BIT(12)	/* use SST Unlock Block-Protection */
 };
 
 #define JEDEC_MFR(info)	((info)->id[0])
@@ -999,6 +1000,11 @@ static const struct flash_info 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 | SST_BLOCK_PROTECT) },
+	{ "sst26vf032b", INFO(0xbf2642, 0, 64 * 1024, 64, SECT_4K | SST_BLOCK_PROTECT) },
+	{ "sst26vf064b", INFO(0xbf2643, 0, 64 * 1024, 128, SECT_4K | SST_BLOCK_PROTECT) },
+	{ "sst26wf040b", INFO(0xbf2654, 0, 64 * 1024,  8, SECT_4K | SST_BLOCK_PROTECT) },
+	{ "sst26wf080b", INFO(0xbf2658, 0, 64 * 1024, 16, SECT_4K | SST_BLOCK_PROTECT) },
 
 	/* ST Microelectronics -- newer production may have feature updates */
 	{ "m25p05",  INFO(0x202010,  0,  32 * 1024,   2, 0) },
@@ -1135,6 +1141,14 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
 	return ret;
 }
 
+static int sst_unlock_block_protection(struct spi_nor *nor)
+{
+	int ret;
+
+	ret = write_enable(nor);
+	return ret ? ret : nor->write_reg(nor, SPINOR_OP_ULBPR, NULL, 0);
+}
+
 static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
 		size_t *retlen, const u_char *buf)
 {
@@ -2308,6 +2322,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
 		return -EINVAL;
 	}
 
+	if (info->flags & SST_BLOCK_PROTECT) {
+		ret = sst_unlock_block_protection(nor);
+		if (ret)
+			return ret;
+	}
+
 	dev_info(dev, "%s (%lld Kbytes)\n", info->name,
 			(long long)mtd->size >> 10);
 
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index ede7ad83c9c5..016b6c51e854 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -80,6 +80,7 @@
 #define SPINOR_OP_BP		0x02	/* Byte program */
 #define SPINOR_OP_WRDI		0x04	/* Write disable */
 #define SPINOR_OP_AAI_WP	0xad	/* Auto address increment word program */
+#define SPINOR_OP_ULBPR		0x98	/* Global Block Protection Unlock */
 
 /* Used for Macronix and Winbond flashes. */
 #define SPINOR_OP_EN4B		0xb7	/* Enter 4-byte mode */
-- 
2.7.4



From nobuhiro.iwamatsu.kw at hitachi.com  Tue Oct  4 20:25:10 2016
From: nobuhiro.iwamatsu.kw at hitachi.com (Nobuhiro Iwamatsu)
Date: Wed,  5 Oct 2016 12:25:10 +0900
Subject: [PATCH] mtd: spi-nor: Add support for N25Q256A13
Message-ID: <1475637910-2324-1-git-send-email-nobuhiro.iwamatsu.kw@hitachi.com>

Add Micron N25Q256A13 256Mbit NOR Flash in the list of supported
devices. This chip is the same structure as the N25Q256A but ID
is different.

Signed-off-by: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.kw at hitachi.com>
---

 drivers/mtd/spi-nor/spi-nor.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index d0fc165..ce67ccd 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -884,6 +884,7 @@ static const struct flash_info spi_nor_ids[] = {
 	{ "n25q128a11",  INFO(0x20bb18, 0, 64 * 1024,  256, SECT_4K | SPI_NOR_QUAD_READ) },
 	{ "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024,  256, SECT_4K | SPI_NOR_QUAD_READ) },
 	{ "n25q256a",    INFO(0x20ba19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_QUAD_READ) },
+	{ "n25q256a13",  INFO(0x20bb19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_QUAD_READ) },
 	{ "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) },
-- 
2.9.3




From iwamoto at allied-telesis.co.jp  Wed Oct  5 01:22:52 2016
From: iwamoto at allied-telesis.co.jp (IWAMOTO Masahiko)
Date: Wed, 5 Oct 2016 08:22:52 +0000
Subject: [PATCH] mtd: spi-nor: Add support for mr25h40
Message-ID: <OS2PR01MB007355EE4F7CBD8647D65CD8DFC50@OS2PR01MB0073.jpnprd01.prod.outlook.com>


Add Everspin mr25h40 512KB MRAM to the list of supported chips.

Signed-off-by: Masahiko Iwamoto <iwamoto at allied-telesis.co.jp>
---
 drivers/mtd/spi-nor/spi-nor.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index d0fc165..bbdbbd7 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -825,6 +825,7 @@ static const struct flash_info spi_nor_ids[] = {
        /* Everspin */
        { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
        { "mr25h10",  CAT25_INFO(128 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+       { "mr25h40",  CAT25_INFO(512 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
 
        /* Fujitsu */
        { "mb85rs1mt", INFO(0x047f27, 0, 128 * 1024, 1, SPI_NOR_NO_ERASE) },
-- 
2.7.4


From sean.nyekjaer at prevas.dk  Wed Oct  5 01:59:49 2016
From: sean.nyekjaer at prevas.dk (Sean Nyekjaer)
Date: Wed,  5 Oct 2016 10:59:49 +0200
Subject: [PATCHv1] mtd: spi-nor: add support for s25fl208k
Message-ID: <20161005085949.29804-1-sean.nyekjaer@prevas.dk>

Signed-off-by: Sean Nyekjaer <sean.nyekjaer at prevas.dk>
---
Changes: Fixed commit msg

 drivers/mtd/spi-nor/spi-nor.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index d0fc165..80e7968 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -921,6 +921,7 @@ static const struct flash_info spi_nor_ids[] = {
 	{ "s25fl132k",  INFO(0x014016,      0,  64 * 1024,  64, SECT_4K) },
 	{ "s25fl164k",  INFO(0x014017,      0,  64 * 1024, 128, SECT_4K) },
 	{ "s25fl204k",  INFO(0x014013,      0,  64 * 1024,   8, SECT_4K | SPI_NOR_DUAL_READ) },
+	{ "s25fl208k",  INFO(0x014014,      0,  64 * 1024,  16, SECT_4K | SPI_NOR_DUAL_READ) },
 
 	/* SST -- large erase sizes are "overlays", "sectors" are 4K */
 	{ "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024,  8, SECT_4K | SST_WRITE) },
-- 
2.10.0



From sr at denx.de  Wed Oct  5 02:57:46 2016
From: sr at denx.de (Stefan Roese)
Date: Wed, 5 Oct 2016 11:57:46 +0200
Subject: [PATCH v3 0/3] spi-nor: Add support for Intel SPI serial flash
 controller
In-Reply-To: <1471245044-12767-1-git-send-email-mika.westerberg@linux.intel.com>
References: <1471245044-12767-1-git-send-email-mika.westerberg@linux.intel.com>
Message-ID: <2cf1530a-8e10-9a4a-51a4-8ae322b26ed9@denx.de>

Hi Mika,

On 15.08.2016 09:10, Mika Westerberg wrote:
> This is third version of the series. Previous versions can be found:
> 
>   v2: http://lists.infradead.org/pipermail/linux-mtd/2016-June/068277.html
>   v1: https://lkml.org/lkml/2016/6/14/269
> 
> This series adds support for the Intel SPI serial flash controller found on
> many recent Intel CPUs including Baytrail and Braswell. This driver makes
> it possible to access the BIOS and other platform data which is stored on
> the SPI serial flash. It is also possible to upgrade the BIOS using this
> driver if it has not been protected by special hardware bits.
> 
> The patch [1/3] includes documentation how to upgrade BIOS on MinnowBoard
> MAX.
> 
> Since poking the SPI serial flash can brick the machine, this driver can
> only be enabled when CONFIG_EXPERT=y and even then it will remain read-only
> unless instructed othwerwise by module parameter.

I'm currently testing this driver on a BayTrail based board with
a common 8MiB SPI NOR chip. Something special to note is, that I'm
using U-Boot as bootloader instead of some BIOS. Accessing the
SPI NOR in U-Boot works without problems. Also I'm able to access
the SPI NOR in Linux via the flashrom tool just fine.

I've now applied your v3 patchset on top of v4.8 and got the SPI NOR
driver loaded. But the SPI NOR device is not detected correctly. Here
the output of the driver with DEBUG enabled:

...
[    3.675891] intel-spi intel-spi: BFPREG=0x07ff0300
[    3.675894] intel-spi intel-spi: HSFSTS_CTL=0x00006000
[    3.675897] intel-spi intel-spi: FADDR=0x006effc0
[    3.675900] intel-spi intel-spi: DLOCK=0x00000000
[    3.675902] intel-spi intel-spi: FDATA(0)=0x00000000
[    3.675905] intel-spi intel-spi: FDATA(1)=0x00000000
[    3.675908] intel-spi intel-spi: FDATA(2)=0x00000000
[    3.675910] intel-spi intel-spi: FDATA(3)=0x00000000
[    3.675913] intel-spi intel-spi: FDATA(4)=0x00000000
[    3.675916] intel-spi intel-spi: FDATA(5)=0x00000000
[    3.675918] intel-spi intel-spi: FDATA(6)=0x00000000
[    3.675921] intel-spi intel-spi: FDATA(7)=0x00000000
[    3.675923] intel-spi intel-spi: FDATA(8)=0x00000000
[    3.675926] intel-spi intel-spi: FDATA(9)=0x00000000
[    3.675929] intel-spi intel-spi: FDATA(10)=0x00000000
[    3.675931] intel-spi intel-spi: FDATA(11)=0x00000000
[    3.675934] intel-spi intel-spi: FDATA(12)=0x00000000
[    3.675941] intel-spi intel-spi: FDATA(13)=0x00000000
[    3.675943] intel-spi intel-spi: FDATA(14)=0x00000000
[    3.675946] intel-spi intel-spi: FDATA(15)=0x00000000
[    3.675949] intel-spi intel-spi: FRACC=0x0000ffff
[    3.675951] intel-spi intel-spi: FREG(0)=0x00000000
[    3.675954] intel-spi intel-spi: FREG(1)=0x07ff0300
[    3.675957] intel-spi intel-spi: FREG(2)=0x02ff0001
[    3.675959] intel-spi intel-spi: FREG(3)=0x00001fff
[    3.675962] intel-spi intel-spi: FREG(4)=0x00001fff
[    3.675965] intel-spi intel-spi: PR(0)=0x00000000
[    3.675967] intel-spi intel-spi: PR(1)=0x00000000
[    3.675970] intel-spi intel-spi: PR(2)=0x00000000
[    3.675972] intel-spi intel-spi: PR(3)=0x00000000
[    3.675975] intel-spi intel-spi: PR(4)=0x00000000
[    3.675978] intel-spi intel-spi: PR(5)=0x00000000
[    3.675980] intel-spi intel-spi: SSFSTS_CTL=0xf87f00c0
[    3.675983] intel-spi intel-spi: PREOP_OPTYPE=0x00020000
[    3.675985] intel-spi intel-spi: OPMENU0=0x0000000b
[    3.675988] intel-spi intel-spi: OPMENU1=0x00000000
[    3.675990] intel-spi intel-spi: BCR=0x00000009
[    3.675992] intel-spi intel-spi: Protected regions:
[    3.675997] intel-spi intel-spi: Flash regions:
[    3.676001] intel-spi intel-spi:  00 base: 0x00000000 limit: 0x00000fff
[    3.676004] intel-spi intel-spi:  01 base: 0x00300000 limit: 0x007fffff
[    3.676007] intel-spi intel-spi:  02 base: 0x00001000 limit: 0x002fffff
[    3.676009] intel-spi intel-spi:  03 disabled
[    3.676012] intel-spi intel-spi:  04 disabled
[    3.676014] intel-spi intel-spi: Using HW sequencer for register access
[    3.679294] intel-spi intel-spi: unrecognized JEDEC id bytes: 00, 00, 00
[    3.686002] intel-spi intel-spi: failed to locate the chip
[    3.691505] intel-spi: probe of intel-spi failed with error -2
... 

Do you have a quick guess on what might go wrong here? Anything
that I should change / test?

Thanks,
Stefan


From mika.westerberg at linux.intel.com  Wed Oct  5 03:27:00 2016
From: mika.westerberg at linux.intel.com (Mika Westerberg)
Date: Wed, 5 Oct 2016 13:27:00 +0300
Subject: [PATCH v3 0/3] spi-nor: Add support for Intel SPI serial flash
 controller
In-Reply-To: <2cf1530a-8e10-9a4a-51a4-8ae322b26ed9@denx.de>
References: <1471245044-12767-1-git-send-email-mika.westerberg@linux.intel.com>
 <2cf1530a-8e10-9a4a-51a4-8ae322b26ed9@denx.de>
Message-ID: <20161005102700.GD1765@lahna.fi.intel.com>

On Wed, Oct 05, 2016 at 11:57:46AM +0200, Stefan Roese wrote:
> Hi Mika,
> 
> On 15.08.2016 09:10, Mika Westerberg wrote:
> > This is third version of the series. Previous versions can be found:
> > 
> >   v2: http://lists.infradead.org/pipermail/linux-mtd/2016-June/068277.html
> >   v1: https://lkml.org/lkml/2016/6/14/269
> > 
> > This series adds support for the Intel SPI serial flash controller found on
> > many recent Intel CPUs including Baytrail and Braswell. This driver makes
> > it possible to access the BIOS and other platform data which is stored on
> > the SPI serial flash. It is also possible to upgrade the BIOS using this
> > driver if it has not been protected by special hardware bits.
> > 
> > The patch [1/3] includes documentation how to upgrade BIOS on MinnowBoard
> > MAX.
> > 
> > Since poking the SPI serial flash can brick the machine, this driver can
> > only be enabled when CONFIG_EXPERT=y and even then it will remain read-only
> > unless instructed othwerwise by module parameter.
> 
> I'm currently testing this driver on a BayTrail based board with
> a common 8MiB SPI NOR chip. Something special to note is, that I'm
> using U-Boot as bootloader instead of some BIOS. Accessing the
> SPI NOR in U-Boot works without problems. Also I'm able to access
> the SPI NOR in Linux via the flashrom tool just fine.
> 
> I've now applied your v3 patchset on top of v4.8 and got the SPI NOR
> driver loaded. But the SPI NOR device is not detected correctly. Here
> the output of the driver with DEBUG enabled:
> 
> ...
> [    3.675891] intel-spi intel-spi: BFPREG=0x07ff0300
> [    3.675894] intel-spi intel-spi: HSFSTS_CTL=0x00006000
> [    3.675897] intel-spi intel-spi: FADDR=0x006effc0
> [    3.675900] intel-spi intel-spi: DLOCK=0x00000000
> [    3.675902] intel-spi intel-spi: FDATA(0)=0x00000000
> [    3.675905] intel-spi intel-spi: FDATA(1)=0x00000000
> [    3.675908] intel-spi intel-spi: FDATA(2)=0x00000000
> [    3.675910] intel-spi intel-spi: FDATA(3)=0x00000000
> [    3.675913] intel-spi intel-spi: FDATA(4)=0x00000000
> [    3.675916] intel-spi intel-spi: FDATA(5)=0x00000000
> [    3.675918] intel-spi intel-spi: FDATA(6)=0x00000000
> [    3.675921] intel-spi intel-spi: FDATA(7)=0x00000000
> [    3.675923] intel-spi intel-spi: FDATA(8)=0x00000000
> [    3.675926] intel-spi intel-spi: FDATA(9)=0x00000000
> [    3.675929] intel-spi intel-spi: FDATA(10)=0x00000000
> [    3.675931] intel-spi intel-spi: FDATA(11)=0x00000000
> [    3.675934] intel-spi intel-spi: FDATA(12)=0x00000000
> [    3.675941] intel-spi intel-spi: FDATA(13)=0x00000000
> [    3.675943] intel-spi intel-spi: FDATA(14)=0x00000000
> [    3.675946] intel-spi intel-spi: FDATA(15)=0x00000000
> [    3.675949] intel-spi intel-spi: FRACC=0x0000ffff
> [    3.675951] intel-spi intel-spi: FREG(0)=0x00000000
> [    3.675954] intel-spi intel-spi: FREG(1)=0x07ff0300
> [    3.675957] intel-spi intel-spi: FREG(2)=0x02ff0001
> [    3.675959] intel-spi intel-spi: FREG(3)=0x00001fff
> [    3.675962] intel-spi intel-spi: FREG(4)=0x00001fff
> [    3.675965] intel-spi intel-spi: PR(0)=0x00000000
> [    3.675967] intel-spi intel-spi: PR(1)=0x00000000
> [    3.675970] intel-spi intel-spi: PR(2)=0x00000000
> [    3.675972] intel-spi intel-spi: PR(3)=0x00000000
> [    3.675975] intel-spi intel-spi: PR(4)=0x00000000
> [    3.675978] intel-spi intel-spi: PR(5)=0x00000000
> [    3.675980] intel-spi intel-spi: SSFSTS_CTL=0xf87f00c0
> [    3.675983] intel-spi intel-spi: PREOP_OPTYPE=0x00020000
> [    3.675985] intel-spi intel-spi: OPMENU0=0x0000000b
> [    3.675988] intel-spi intel-spi: OPMENU1=0x00000000
> [    3.675990] intel-spi intel-spi: BCR=0x00000009
> [    3.675992] intel-spi intel-spi: Protected regions:
> [    3.675997] intel-spi intel-spi: Flash regions:
> [    3.676001] intel-spi intel-spi:  00 base: 0x00000000 limit: 0x00000fff
> [    3.676004] intel-spi intel-spi:  01 base: 0x00300000 limit: 0x007fffff
> [    3.676007] intel-spi intel-spi:  02 base: 0x00001000 limit: 0x002fffff
> [    3.676009] intel-spi intel-spi:  03 disabled
> [    3.676012] intel-spi intel-spi:  04 disabled
> [    3.676014] intel-spi intel-spi: Using HW sequencer for register access

It should not be using HW sequencer on Baytrail. The driver thinks so
because it wants that both OPMENU0 and OPMENU1 to be set before it
switches to use SW sequencer.

You can try to change:

static int intel_spi_init(struct intel_spi *ispi)
{
	...
	if (opmenu0 || opmenu1) {

but I suppose that's not enough because it does include RDID in the
OPMENU0 which we use to read the JEDEC ID.

Since the controller is not locked down (DLOCK is 0) we could program
those for the OPMENU0 so that it contains 0x00009f0b and maybe something
more.

You could try to add

       writel(0x00009f0b, ispi->sregs + OPMENU0);

before we read OPMENU0 in the same function.


From sr at denx.de  Wed Oct  5 04:11:39 2016
From: sr at denx.de (Stefan Roese)
Date: Wed, 5 Oct 2016 13:11:39 +0200
Subject: [PATCH v3 0/3] spi-nor: Add support for Intel SPI serial flash
 controller
In-Reply-To: <20161005102700.GD1765@lahna.fi.intel.com>
References: <1471245044-12767-1-git-send-email-mika.westerberg@linux.intel.com>
 <2cf1530a-8e10-9a4a-51a4-8ae322b26ed9@denx.de>
 <20161005102700.GD1765@lahna.fi.intel.com>
Message-ID: <8fef3d44-dc1e-2175-b335-9f025b302ab1@denx.de>

On 05.10.2016 12:27, Mika Westerberg wrote:
> On Wed, Oct 05, 2016 at 11:57:46AM +0200, Stefan Roese wrote:
>> Hi Mika,
>>
>> On 15.08.2016 09:10, Mika Westerberg wrote:
>>> This is third version of the series. Previous versions can be found:
>>>
>>>   v2: http://lists.infradead.org/pipermail/linux-mtd/2016-June/068277.html
>>>   v1: https://lkml.org/lkml/2016/6/14/269
>>>
>>> This series adds support for the Intel SPI serial flash controller found on
>>> many recent Intel CPUs including Baytrail and Braswell. This driver makes
>>> it possible to access the BIOS and other platform data which is stored on
>>> the SPI serial flash. It is also possible to upgrade the BIOS using this
>>> driver if it has not been protected by special hardware bits.
>>>
>>> The patch [1/3] includes documentation how to upgrade BIOS on MinnowBoard
>>> MAX.
>>>
>>> Since poking the SPI serial flash can brick the machine, this driver can
>>> only be enabled when CONFIG_EXPERT=y and even then it will remain read-only
>>> unless instructed othwerwise by module parameter.
>>
>> I'm currently testing this driver on a BayTrail based board with
>> a common 8MiB SPI NOR chip. Something special to note is, that I'm
>> using U-Boot as bootloader instead of some BIOS. Accessing the
>> SPI NOR in U-Boot works without problems. Also I'm able to access
>> the SPI NOR in Linux via the flashrom tool just fine.
>>
>> I've now applied your v3 patchset on top of v4.8 and got the SPI NOR
>> driver loaded. But the SPI NOR device is not detected correctly. Here
>> the output of the driver with DEBUG enabled:
>>
>> ...
>> [    3.675891] intel-spi intel-spi: BFPREG=0x07ff0300
>> [    3.675894] intel-spi intel-spi: HSFSTS_CTL=0x00006000
>> [    3.675897] intel-spi intel-spi: FADDR=0x006effc0
>> [    3.675900] intel-spi intel-spi: DLOCK=0x00000000
>> [    3.675902] intel-spi intel-spi: FDATA(0)=0x00000000
>> [    3.675905] intel-spi intel-spi: FDATA(1)=0x00000000
>> [    3.675908] intel-spi intel-spi: FDATA(2)=0x00000000
>> [    3.675910] intel-spi intel-spi: FDATA(3)=0x00000000
>> [    3.675913] intel-spi intel-spi: FDATA(4)=0x00000000
>> [    3.675916] intel-spi intel-spi: FDATA(5)=0x00000000
>> [    3.675918] intel-spi intel-spi: FDATA(6)=0x00000000
>> [    3.675921] intel-spi intel-spi: FDATA(7)=0x00000000
>> [    3.675923] intel-spi intel-spi: FDATA(8)=0x00000000
>> [    3.675926] intel-spi intel-spi: FDATA(9)=0x00000000
>> [    3.675929] intel-spi intel-spi: FDATA(10)=0x00000000
>> [    3.675931] intel-spi intel-spi: FDATA(11)=0x00000000
>> [    3.675934] intel-spi intel-spi: FDATA(12)=0x00000000
>> [    3.675941] intel-spi intel-spi: FDATA(13)=0x00000000
>> [    3.675943] intel-spi intel-spi: FDATA(14)=0x00000000
>> [    3.675946] intel-spi intel-spi: FDATA(15)=0x00000000
>> [    3.675949] intel-spi intel-spi: FRACC=0x0000ffff
>> [    3.675951] intel-spi intel-spi: FREG(0)=0x00000000
>> [    3.675954] intel-spi intel-spi: FREG(1)=0x07ff0300
>> [    3.675957] intel-spi intel-spi: FREG(2)=0x02ff0001
>> [    3.675959] intel-spi intel-spi: FREG(3)=0x00001fff
>> [    3.675962] intel-spi intel-spi: FREG(4)=0x00001fff
>> [    3.675965] intel-spi intel-spi: PR(0)=0x00000000
>> [    3.675967] intel-spi intel-spi: PR(1)=0x00000000
>> [    3.675970] intel-spi intel-spi: PR(2)=0x00000000
>> [    3.675972] intel-spi intel-spi: PR(3)=0x00000000
>> [    3.675975] intel-spi intel-spi: PR(4)=0x00000000
>> [    3.675978] intel-spi intel-spi: PR(5)=0x00000000
>> [    3.675980] intel-spi intel-spi: SSFSTS_CTL=0xf87f00c0
>> [    3.675983] intel-spi intel-spi: PREOP_OPTYPE=0x00020000
>> [    3.675985] intel-spi intel-spi: OPMENU0=0x0000000b
>> [    3.675988] intel-spi intel-spi: OPMENU1=0x00000000
>> [    3.675990] intel-spi intel-spi: BCR=0x00000009
>> [    3.675992] intel-spi intel-spi: Protected regions:
>> [    3.675997] intel-spi intel-spi: Flash regions:
>> [    3.676001] intel-spi intel-spi:  00 base: 0x00000000 limit: 0x00000fff
>> [    3.676004] intel-spi intel-spi:  01 base: 0x00300000 limit: 0x007fffff
>> [    3.676007] intel-spi intel-spi:  02 base: 0x00001000 limit: 0x002fffff
>> [    3.676009] intel-spi intel-spi:  03 disabled
>> [    3.676012] intel-spi intel-spi:  04 disabled
>> [    3.676014] intel-spi intel-spi: Using HW sequencer for register access
> 
> It should not be using HW sequencer on Baytrail. The driver thinks so
> because it wants that both OPMENU0 and OPMENU1 to be set before it
> switches to use SW sequencer.
> 
> You can try to change:
> 
> static int intel_spi_init(struct intel_spi *ispi)
> {
> 	...
> 	if (opmenu0 || opmenu1) {
> 
> but I suppose that's not enough because it does include RDID in the
> OPMENU0 which we use to read the JEDEC ID.
> 
> Since the controller is not locked down (DLOCK is 0) we could program
> those for the OPMENU0 so that it contains 0x00009f0b and maybe something
> more.
> 
> You could try to add
> 
>        writel(0x00009f0b, ispi->sregs + OPMENU0);
> 
> before we read OPMENU0 in the same function.

Thanks. I've made those 2 changes and now the SPI chip is detected
correctly:

...
[    3.654301] intel-spi intel-spi: OPMENU0=0x00009f0b
[    3.654304] intel-spi intel-spi: OPMENU1=0x00000000
[    3.654306] intel-spi intel-spi: BCR=0x00000009
[    3.654308] intel-spi intel-spi: Protected regions:
[    3.654313] intel-spi intel-spi: Flash regions:
[    3.654316] intel-spi intel-spi:  00 base: 0x00000000 limit: 0x00000fff
[    3.654320] intel-spi intel-spi:  01 base: 0x00300000 limit: 0x007fffff
[    3.654323] intel-spi intel-spi:  02 base: 0x00001000 limit: 0x002fffff
[    3.654325] intel-spi intel-spi:  03 disabled
[    3.654328] intel-spi intel-spi:  04 disabled
[    3.654330] intel-spi intel-spi: Using SW sequencer for register access
[    3.657488] intel-spi intel-spi: s25fl064k (8192 Kbytes)
[    3.677241] Creating 1 MTD partitions on "intel-spi":
[    3.682310] 0x000000000000-0x000000800000 : "BIOS"
...

So how do you suggest to support such BayTrail boards booting
via U-Boot as bootloader? Should U-Boot write something into
these OPMENU0/1 registers before booting into Linux?

Thanks,
Stefan


From mika.westerberg at linux.intel.com  Wed Oct  5 04:18:50 2016
From: mika.westerberg at linux.intel.com (Mika Westerberg)
Date: Wed, 5 Oct 2016 14:18:50 +0300
Subject: [PATCH v3 0/3] spi-nor: Add support for Intel SPI serial flash
 controller
In-Reply-To: <8fef3d44-dc1e-2175-b335-9f025b302ab1@denx.de>
References: <1471245044-12767-1-git-send-email-mika.westerberg@linux.intel.com>
 <2cf1530a-8e10-9a4a-51a4-8ae322b26ed9@denx.de>
 <20161005102700.GD1765@lahna.fi.intel.com>
 <8fef3d44-dc1e-2175-b335-9f025b302ab1@denx.de>
Message-ID: <20161005111850.GG1765@lahna.fi.intel.com>

On Wed, Oct 05, 2016 at 01:11:39PM +0200, Stefan Roese wrote:
> [    3.654301] intel-spi intel-spi: OPMENU0=0x00009f0b
> [    3.654304] intel-spi intel-spi: OPMENU1=0x00000000
> [    3.654306] intel-spi intel-spi: BCR=0x00000009
> [    3.654308] intel-spi intel-spi: Protected regions:
> [    3.654313] intel-spi intel-spi: Flash regions:
> [    3.654316] intel-spi intel-spi:  00 base: 0x00000000 limit: 0x00000fff
> [    3.654320] intel-spi intel-spi:  01 base: 0x00300000 limit: 0x007fffff
> [    3.654323] intel-spi intel-spi:  02 base: 0x00001000 limit: 0x002fffff
> [    3.654325] intel-spi intel-spi:  03 disabled
> [    3.654328] intel-spi intel-spi:  04 disabled
> [    3.654330] intel-spi intel-spi: Using SW sequencer for register access
> [    3.657488] intel-spi intel-spi: s25fl064k (8192 Kbytes)
> [    3.677241] Creating 1 MTD partitions on "intel-spi":
> [    3.682310] 0x000000000000-0x000000800000 : "BIOS"

Cool!

> So how do you suggest to support such BayTrail boards booting
> via U-Boot as bootloader? Should U-Boot write something into
> these OPMENU0/1 registers before booting into Linux?

Typically it's the BIOS who does that so I guess in your case it should
be U-Boot then. I would not like to add that part to the driver itself
unless absolutely necessary ;-)


From sr at denx.de  Wed Oct  5 04:31:20 2016
From: sr at denx.de (Stefan Roese)
Date: Wed, 5 Oct 2016 13:31:20 +0200
Subject: [PATCH v3 0/3] spi-nor: Add support for Intel SPI serial flash
 controller
In-Reply-To: <20161005111850.GG1765@lahna.fi.intel.com>
References: <1471245044-12767-1-git-send-email-mika.westerberg@linux.intel.com>
 <2cf1530a-8e10-9a4a-51a4-8ae322b26ed9@denx.de>
 <20161005102700.GD1765@lahna.fi.intel.com>
 <8fef3d44-dc1e-2175-b335-9f025b302ab1@denx.de>
 <20161005111850.GG1765@lahna.fi.intel.com>
Message-ID: <b0b5aa23-bbc6-a2c4-8671-a50a4735ec15@denx.de>

On 05.10.2016 13:18, Mika Westerberg wrote:
> On Wed, Oct 05, 2016 at 01:11:39PM +0200, Stefan Roese wrote:
>> [    3.654301] intel-spi intel-spi: OPMENU0=0x00009f0b
>> [    3.654304] intel-spi intel-spi: OPMENU1=0x00000000
>> [    3.654306] intel-spi intel-spi: BCR=0x00000009
>> [    3.654308] intel-spi intel-spi: Protected regions:
>> [    3.654313] intel-spi intel-spi: Flash regions:
>> [    3.654316] intel-spi intel-spi:  00 base: 0x00000000 limit: 0x00000fff
>> [    3.654320] intel-spi intel-spi:  01 base: 0x00300000 limit: 0x007fffff
>> [    3.654323] intel-spi intel-spi:  02 base: 0x00001000 limit: 0x002fffff
>> [    3.654325] intel-spi intel-spi:  03 disabled
>> [    3.654328] intel-spi intel-spi:  04 disabled
>> [    3.654330] intel-spi intel-spi: Using SW sequencer for register access
>> [    3.657488] intel-spi intel-spi: s25fl064k (8192 Kbytes)
>> [    3.677241] Creating 1 MTD partitions on "intel-spi":
>> [    3.682310] 0x000000000000-0x000000800000 : "BIOS"
>
> Cool!
>
>> So how do you suggest to support such BayTrail boards booting
>> via U-Boot as bootloader? Should U-Boot write something into
>> these OPMENU0/1 registers before booting into Linux?
>
> Typically it's the BIOS who does that so I guess in your case it should
> be U-Boot then. I would not like to add that part to the driver itself
> unless absolutely necessary ;-)

Sure, I can definitely add something here in U-Boot. Since I'm
pretty new to this driver / controller and its interface to the BIOS,
could you perhaps suggest those values please? To enable the Linux
driver with full read-write support to such chips?

Thanks,
Stefan


From mika.westerberg at linux.intel.com  Wed Oct  5 04:49:08 2016
From: mika.westerberg at linux.intel.com (Mika Westerberg)
Date: Wed, 5 Oct 2016 14:49:08 +0300
Subject: [PATCH v3 0/3] spi-nor: Add support for Intel SPI serial flash
 controller
In-Reply-To: <b0b5aa23-bbc6-a2c4-8671-a50a4735ec15@denx.de>
References: <1471245044-12767-1-git-send-email-mika.westerberg@linux.intel.com>
 <2cf1530a-8e10-9a4a-51a4-8ae322b26ed9@denx.de>
 <20161005102700.GD1765@lahna.fi.intel.com>
 <8fef3d44-dc1e-2175-b335-9f025b302ab1@denx.de>
 <20161005111850.GG1765@lahna.fi.intel.com>
 <b0b5aa23-bbc6-a2c4-8671-a50a4735ec15@denx.de>
Message-ID: <20161005114908.GJ1765@lahna.fi.intel.com>

On Wed, Oct 05, 2016 at 01:31:20PM +0200, Stefan Roese wrote:
> Sure, I can definitely add something here in U-Boot. Since I'm
> pretty new to this driver / controller and its interface to the BIOS,
> could you perhaps suggest those values please? To enable the Linux
> driver with full read-write support to such chips?

These values are from Minnowboard MAX which is based on Baytrail:

[    8.112316] intel-spi intel-spi: PREOP_OPTYPE=0x7f480606
[    8.118278] intel-spi intel-spi: OPMENU0=0x0405039f
[    8.123754] intel-spi intel-spi: OPMENU1=0x0102d820

Maybe something like that?


From cyrille.pitchen at atmel.com  Wed Oct  5 05:00:31 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Wed, 5 Oct 2016 14:00:31 +0200
Subject: [PATCH v2 0/9] mtd: spi-nor: parse SFDP tables to setup (Q)SPI
 memories
Message-ID: <cover.1475668319.git.cyrille.pitchen@atmel.com>

Hi all,

This series extends support of SPI protocols to new protocols such as
SPI x-2-2 and SPI x-4-4. Also spi_nor_scan() tries now to select the right
op codes, timing parameters (number of mode and dummy cycles) and erase
sector size by parsing the Serial Flash Discoverable Parameter (SFDP)
tables, when available, as defined in the JEDEC JESD216 specifications.

When SFDP tables are not available, legacy settings are still used for
backward compatibility (SPI and earlier QSPI memories).

Support of SPI memories >128Mbits is also improved by using the 4byte
address instruction set, when available. Using those dedicated op codes
is stateless as opposed to enter the 4byte address mode, hence a better
compatibility with some boot loaders which expect to use 3byte address
op codes.


This series was tested on a Atmel sama5d2 xplained board with the
atmel-qspi.c driver. Except for SST memories, the SPI bus clock was set
to 83MHz. The config MTD_SPI_NOR_USE_4K_SECTORS was selected.

For my tests, I used some shell scripts using mtd_debug and sha1sum to
check the data integrity.

e.g:
#!/bin/sh

mtd_debug erase /dev/mtd5 0 0x780000
mtd_debug write /dev/mtd5 0 7674703 sama5d4_doc11238.pdf
mtd_debug read /dev/mtd5 0 7674703 sam5d4_tmp.pdf

sha1sum sama5d4_doc11238.pdf sam5d4_tmp.pdf


Depending on the actual memory size, I may have used other partitions
(/dev/mtd4) and input file size (2880044 and 320044 bytes).


The series was tested with the following QSPI memories:

Spansion/Cypress:
- s25fl127s	OK
- s25fl512s	OK
- s25fl164k	OK

Micron:
- n25q128a	OK

Macronix:
- mx25l6433f	OK
- mx25l6473f	OK
- mx25l12835f	OK
- mx25l12845g	OK
- mx25l12873g	OK
- mx25l25645g	OK
- mx25l25673g	OK
- mx25l51245g	OK
- mx66l1g45g	OK (1)

SST:
- sst26vf016b	OK (2)
- sst26vf032b	OK (2)
- sst26vf064b	OK (2)

(1): requires patch 8
(2): requires patch 9, the SPI bus clock frequency was decreased down to 55.3MHz


Best regards,

Cyrille

ChangeLog:

v1 -> v2
- fix patch 3 to resolve compiler errors on hisi-sfc.c and cadence-quadspi.c
  drivers


Cyrille Pitchen (9):
  mtd: spi-nor: improve macronix_quad_enable()
  mtd: spi-nor: add an alternative method to support memory >16MiB
  mtd: spi-nor: add support of SPI protocols like SPI 1-2-2 and SPI
    1-4-4
  mtd: spi-nor: remove unused set_quad_mode() function
  mtd: m25p80: add support of dual and quad spi protocols to all
    commands
  mtd: spi-nor: parse Serial Flash Discoverable Parameters (SFDP) tables
  mtd: spi-nor: parse SFDP 4-byte Address Instruction Table
  mtd: spi-nor: add support to Macronix mx66l1g45g
  mtd: spi-nor: add support to SST sst26* QSPI memories

 drivers/mtd/devices/m25p80.c            |  204 +++++--
 drivers/mtd/devices/serial_flash_cmds.h |    7 -
 drivers/mtd/devices/st_spi_fsm.c        |   28 +-
 drivers/mtd/spi-nor/atmel-quadspi.c     |   83 ++-
 drivers/mtd/spi-nor/cadence-quadspi.c   |   18 +-
 drivers/mtd/spi-nor/fsl-quadspi.c       |    8 +-
 drivers/mtd/spi-nor/hisi-sfc.c          |   32 +-
 drivers/mtd/spi-nor/mtk-quadspi.c       |   16 +-
 drivers/mtd/spi-nor/nxp-spifi.c         |   21 +-
 drivers/mtd/spi-nor/spi-nor.c           | 1013 ++++++++++++++++++++++++++++---
 include/linux/mtd/spi-nor.h             |  165 ++++-
 11 files changed, 1359 insertions(+), 236 deletions(-)

-- 
2.7.4



From cyrille.pitchen at atmel.com  Wed Oct  5 05:00:32 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Wed, 5 Oct 2016 14:00:32 +0200
Subject: [PATCH v2 1/9] mtd: spi-nor: improve macronix_quad_enable()
In-Reply-To: <cover.1475668319.git.cyrille.pitchen@atmel.com>
References: <cover.1475668319.git.cyrille.pitchen@atmel.com>
Message-ID: <ad5a4648bd2486d5c8e671312a0a717fa2a6b2b8.1475668319.git.cyrille.pitchen@atmel.com>

The patch checks whether the Quad Enable bit is already set in the Status
Register. If so, the function exits immediately with a successful return
code. Otherwise, a message is now printed telling we're setting the
non-volatile bit.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index d0fc165d7d66..5c87b2d99507 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1211,6 +1211,11 @@ static int macronix_quad_enable(struct spi_nor *nor)
 	val = read_sr(nor);
 	if (val < 0)
 		return val;
+	if (val & SR_QUAD_EN_MX)
+		return 0;
+
+	/* Update the Quad Enable bit. */
+	dev_info(nor->dev, "setting Macronix Quad Enable (non-volatile) bit\n");
 	write_enable(nor);
 
 	write_sr(nor, val | SR_QUAD_EN_MX);
-- 
2.7.4



From cyrille.pitchen at atmel.com  Wed Oct  5 05:00:33 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Wed, 5 Oct 2016 14:00:33 +0200
Subject: [PATCH v2 2/9] mtd: spi-nor: add an alternative method to support
 memory >16MiB
In-Reply-To: <cover.1475668319.git.cyrille.pitchen@atmel.com>
References: <cover.1475668319.git.cyrille.pitchen@atmel.com>
Message-ID: <18b156f699e82ff9b36c044df73a2ef769d53c83.1475668319.git.cyrille.pitchen@atmel.com>

This patch provides an alternative mean to support memory above 16MiB
(128Mib) by replacing 3byte address op codes by their associated 4byte
address versions.

Using the dedicated 4byte address op codes doesn't change the internal
state of the SPI NOR memory as opposed to using other means such as
updating a Base Address Register (BAR) and sending command to enter/leave
the 4byte mode.

Hence when a CPU reset occurs, early bootloaders don't need to be aware
of BAR value or 4byte mode being enabled: they can still access the first
16MiB of the SPI NOR memory using the regular 3byte address op codes.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
 drivers/mtd/devices/serial_flash_cmds.h |   7 ---
 drivers/mtd/devices/st_spi_fsm.c        |  28 ++++-----
 drivers/mtd/spi-nor/spi-nor.c           | 104 +++++++++++++++++++++++++-------
 include/linux/mtd/spi-nor.h             |  22 +++++--
 4 files changed, 113 insertions(+), 48 deletions(-)

diff --git a/drivers/mtd/devices/serial_flash_cmds.h b/drivers/mtd/devices/serial_flash_cmds.h
index f59a125295d0..8b81e15105dd 100644
--- a/drivers/mtd/devices/serial_flash_cmds.h
+++ b/drivers/mtd/devices/serial_flash_cmds.h
@@ -18,19 +18,12 @@
 #define SPINOR_OP_RDVCR		0x85
 
 /* JEDEC Standard - Serial Flash Discoverable Parmeters (SFDP) Commands */
-#define SPINOR_OP_READ_1_2_2	0xbb	/* DUAL I/O READ */
-#define SPINOR_OP_READ_1_4_4	0xeb	/* QUAD I/O READ */
-
 #define SPINOR_OP_WRITE		0x02	/* PAGE PROGRAM */
 #define SPINOR_OP_WRITE_1_1_2	0xa2	/* DUAL INPUT PROGRAM */
 #define SPINOR_OP_WRITE_1_2_2	0xd2	/* DUAL INPUT EXT PROGRAM */
 #define SPINOR_OP_WRITE_1_1_4	0x32	/* QUAD INPUT PROGRAM */
 #define SPINOR_OP_WRITE_1_4_4	0x12	/* QUAD INPUT EXT PROGRAM */
 
-/* READ commands with 32-bit addressing */
-#define SPINOR_OP_READ4_1_2_2	0xbc
-#define SPINOR_OP_READ4_1_4_4	0xec
-
 /* Configuration flags */
 #define FLASH_FLAG_SINGLE	0x000000ff
 #define FLASH_FLAG_READ_WRITE	0x00000001
diff --git a/drivers/mtd/devices/st_spi_fsm.c b/drivers/mtd/devices/st_spi_fsm.c
index 5454b4113589..804313a33f2b 100644
--- a/drivers/mtd/devices/st_spi_fsm.c
+++ b/drivers/mtd/devices/st_spi_fsm.c
@@ -507,13 +507,13 @@ static struct seq_rw_config n25q_read3_configs[] = {
  *	- 'FAST' variants configured for 8 dummy cycles (see note above.)
  */
 static struct seq_rw_config n25q_read4_configs[] = {
-	{FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ4_1_4_4,	0, 4, 4, 0x00, 0, 8},
-	{FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ4_1_1_4,	0, 1, 4, 0x00, 0, 8},
-	{FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ4_1_2_2,	0, 2, 2, 0x00, 0, 8},
-	{FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ4_1_1_2,	0, 1, 2, 0x00, 0, 8},
-	{FLASH_FLAG_READ_FAST,	SPINOR_OP_READ4_FAST,	0, 1, 1, 0x00, 0, 8},
-	{FLASH_FLAG_READ_WRITE, SPINOR_OP_READ4,	0, 1, 1, 0x00, 0, 0},
-	{0x00,			0,			0, 0, 0, 0x00, 0, 0},
+	{FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ_1_4_4_4B, 0, 4, 4, 0x00, 0, 8},
+	{FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ_1_1_4_4B, 0, 1, 4, 0x00, 0, 8},
+	{FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ_1_2_2_4B, 0, 2, 2, 0x00, 0, 8},
+	{FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ_1_1_2_4B, 0, 1, 2, 0x00, 0, 8},
+	{FLASH_FLAG_READ_FAST,	SPINOR_OP_READ_FAST_4B,  0, 1, 1, 0x00, 0, 8},
+	{FLASH_FLAG_READ_WRITE, SPINOR_OP_READ_4B,       0, 1, 1, 0x00, 0, 0},
+	{0x00,			0,                       0, 0, 0, 0x00, 0, 0},
 };
 
 /*
@@ -553,13 +553,13 @@ static int stfsm_mx25_en_32bit_addr_seq(struct stfsm_seq *seq)
  * entering a state that is incompatible with the SPIBoot Controller.
  */
 static struct seq_rw_config stfsm_s25fl_read4_configs[] = {
-	{FLASH_FLAG_READ_1_4_4,  SPINOR_OP_READ4_1_4_4,  0, 4, 4, 0x00, 2, 4},
-	{FLASH_FLAG_READ_1_1_4,  SPINOR_OP_READ4_1_1_4,  0, 1, 4, 0x00, 0, 8},
-	{FLASH_FLAG_READ_1_2_2,  SPINOR_OP_READ4_1_2_2,  0, 2, 2, 0x00, 4, 0},
-	{FLASH_FLAG_READ_1_1_2,  SPINOR_OP_READ4_1_1_2,  0, 1, 2, 0x00, 0, 8},
-	{FLASH_FLAG_READ_FAST,   SPINOR_OP_READ4_FAST,   0, 1, 1, 0x00, 0, 8},
-	{FLASH_FLAG_READ_WRITE,  SPINOR_OP_READ4,        0, 1, 1, 0x00, 0, 0},
-	{0x00,                   0,                      0, 0, 0, 0x00, 0, 0},
+	{FLASH_FLAG_READ_1_4_4,  SPINOR_OP_READ_1_4_4_4B,  0, 4, 4, 0x00, 2, 4},
+	{FLASH_FLAG_READ_1_1_4,  SPINOR_OP_READ_1_1_4_4B,  0, 1, 4, 0x00, 0, 8},
+	{FLASH_FLAG_READ_1_2_2,  SPINOR_OP_READ_1_2_2_4B,  0, 2, 2, 0x00, 4, 0},
+	{FLASH_FLAG_READ_1_1_2,  SPINOR_OP_READ_1_1_2_4B,  0, 1, 2, 0x00, 0, 8},
+	{FLASH_FLAG_READ_FAST,   SPINOR_OP_READ_FAST_4B,   0, 1, 1, 0x00, 0, 8},
+	{FLASH_FLAG_READ_WRITE,  SPINOR_OP_READ_4B,        0, 1, 1, 0x00, 0, 0},
+	{0x00,                   0,                        0, 0, 0, 0x00, 0, 0},
 };
 
 static struct seq_rw_config stfsm_s25fl_write4_configs[] = {
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 5c87b2d99507..423448c1c7a8 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -75,6 +75,10 @@ struct flash_info {
 					 * bit. Must be used with
 					 * SPI_NOR_HAS_LOCK.
 					 */
+#define SPI_NOR_4B_OPCODES	BIT(10)	/*
+					 * Use dedicated 4byte address op codes
+					 * to support memory size above 128Mib.
+					 */
 };
 
 #define JEDEC_MFR(info)	((info)->id[0])
@@ -188,6 +192,81 @@ static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd)
 	return mtd->priv;
 }
 
+
+struct spi_nor_address_entry {
+	u8	src_opcode;
+	u8	dst_opcode;
+};
+
+static u8 spi_nor_convert_opcode(u8 opcode,
+				 const struct spi_nor_address_entry *entries,
+				 size_t num_entries)
+{
+	int min, max;
+
+	min = 0;
+	max = num_entries - 1;
+	while (min <= max) {
+		int mid = (min + max) >> 1;
+		const struct spi_nor_address_entry *entry = &entries[mid];
+
+		if (opcode == entry->src_opcode)
+			return entry->dst_opcode;
+
+		if (opcode < entry->src_opcode)
+			max = mid - 1;
+		else
+			min = mid + 1;
+	}
+
+	/* No conversion found */
+	return opcode;
+}
+
+static u8 spi_nor_3to4_opcode(u8 opcode)
+{
+	/* MUST be sorted by 3byte opcode */
+#define ENTRY_3TO4(_opcode)	{ _opcode, _opcode##_4B }
+	static const struct spi_nor_address_entry spi_nor_3to4_table[] = {
+		ENTRY_3TO4(SPINOR_OP_PP),		/* 0x02 */
+		ENTRY_3TO4(SPINOR_OP_READ),		/* 0x03 */
+		ENTRY_3TO4(SPINOR_OP_READ_FAST),	/* 0x0b */
+		ENTRY_3TO4(SPINOR_OP_BE_4K),		/* 0x20 */
+		ENTRY_3TO4(SPINOR_OP_PP_1_1_4),		/* 0x32 */
+		ENTRY_3TO4(SPINOR_OP_PP_1_4_4),		/* 0x38 */
+		ENTRY_3TO4(SPINOR_OP_READ_1_1_2),	/* 0x3b */
+		ENTRY_3TO4(SPINOR_OP_BE_32K),		/* 0x52 */
+		ENTRY_3TO4(SPINOR_OP_READ_1_1_4),	/* 0x6b */
+		ENTRY_3TO4(SPINOR_OP_READ_1_2_2),	/* 0xbb */
+		ENTRY_3TO4(SPINOR_OP_SE),		/* 0xd8 */
+		ENTRY_3TO4(SPINOR_OP_READ_1_4_4),	/* 0xeb */
+	};
+#undef ENTRY_3TO4
+
+	return spi_nor_convert_opcode(opcode, spi_nor_3to4_table,
+				      ARRAY_SIZE(spi_nor_3to4_table));
+}
+
+static void spi_nor_set_4byte_opcodes(struct spi_nor *nor,
+				      const struct flash_info *info)
+{
+	/* Do some manufacturer fixups first */
+	switch (JEDEC_MFR(info)) {
+	case SNOR_MFR_SPANSION:
+		/* No small sector erase for 4-byte command set */
+		nor->erase_opcode = SPINOR_OP_SE;
+		nor->mtd.erasesize = info->sector_size;
+		break;
+
+	default:
+		break;
+	}
+
+	nor->read_opcode	= spi_nor_3to4_opcode(nor->read_opcode);
+	nor->program_opcode	= spi_nor_3to4_opcode(nor->program_opcode);
+	nor->erase_opcode	= spi_nor_3to4_opcode(nor->erase_opcode);
+}
+
 /* Enable/disable 4-byte addressing mode. */
 static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info,
 			    int enable)
@@ -1476,27 +1555,10 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 	else if (mtd->size > 0x1000000) {
 		/* enable 4-byte addressing if the device exceeds 16MiB */
 		nor->addr_width = 4;
-		if (JEDEC_MFR(info) == SNOR_MFR_SPANSION) {
-			/* Dedicated 4-byte command set */
-			switch (nor->flash_read) {
-			case SPI_NOR_QUAD:
-				nor->read_opcode = SPINOR_OP_READ4_1_1_4;
-				break;
-			case SPI_NOR_DUAL:
-				nor->read_opcode = SPINOR_OP_READ4_1_1_2;
-				break;
-			case SPI_NOR_FAST:
-				nor->read_opcode = SPINOR_OP_READ4_FAST;
-				break;
-			case SPI_NOR_NORMAL:
-				nor->read_opcode = SPINOR_OP_READ4;
-				break;
-			}
-			nor->program_opcode = SPINOR_OP_PP_4B;
-			/* No small sector erase for 4-byte command set */
-			nor->erase_opcode = SPINOR_OP_SE_4B;
-			mtd->erasesize = info->sector_size;
-		} else
+		if (JEDEC_MFR(info) == SNOR_MFR_SPANSION ||
+		    info->flags & SPI_NOR_4B_OPCODES)
+			spi_nor_set_4byte_opcodes(nor, info);
+		else
 			set_4byte(nor, info, 1);
 	} else {
 		nor->addr_width = 3;
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index c425c7b4c2a0..8b02fd7864d0 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -43,9 +43,13 @@
 #define SPINOR_OP_WRSR		0x01	/* Write status register 1 byte */
 #define SPINOR_OP_READ		0x03	/* Read data bytes (low frequency) */
 #define SPINOR_OP_READ_FAST	0x0b	/* Read data bytes (high frequency) */
-#define SPINOR_OP_READ_1_1_2	0x3b	/* Read data bytes (Dual SPI) */
-#define SPINOR_OP_READ_1_1_4	0x6b	/* Read data bytes (Quad SPI) */
+#define SPINOR_OP_READ_1_1_2	0x3b	/* Read data bytes (Dual Output SPI) */
+#define SPINOR_OP_READ_1_2_2	0xbb	/* Read data bytes (Dual I/O SPI) */
+#define SPINOR_OP_READ_1_1_4	0x6b	/* Read data bytes (Quad Output SPI) */
+#define SPINOR_OP_READ_1_4_4	0xeb	/* Read data bytes (Quad I/O SPI) */
 #define SPINOR_OP_PP		0x02	/* Page program (up to 256 bytes) */
+#define SPINOR_OP_PP_1_1_4	0x32	/* Quad page program */
+#define SPINOR_OP_PP_1_4_4	0x38	/* Quad page program */
 #define SPINOR_OP_BE_4K		0x20	/* Erase 4KiB block */
 #define SPINOR_OP_BE_4K_PMC	0xd7	/* Erase 4KiB block on PMC chips */
 #define SPINOR_OP_BE_32K	0x52	/* Erase 32KiB block */
@@ -56,11 +60,17 @@
 #define SPINOR_OP_RDFSR		0x70	/* Read flag status register */
 
 /* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
-#define SPINOR_OP_READ4		0x13	/* Read data bytes (low frequency) */
-#define SPINOR_OP_READ4_FAST	0x0c	/* Read data bytes (high frequency) */
-#define SPINOR_OP_READ4_1_1_2	0x3c	/* Read data bytes (Dual SPI) */
-#define SPINOR_OP_READ4_1_1_4	0x6c	/* Read data bytes (Quad SPI) */
+#define SPINOR_OP_READ_4B	0x13	/* Read data bytes (low frequency) */
+#define SPINOR_OP_READ_FAST_4B	0x0c	/* Read data bytes (high frequency) */
+#define SPINOR_OP_READ_1_1_2_4B	0x3c	/* Read data bytes (Dual Output SPI) */
+#define SPINOR_OP_READ_1_2_2_4B	0xbc	/* Read data bytes (Dual I/O SPI) */
+#define SPINOR_OP_READ_1_1_4_4B	0x6c	/* Read data bytes (Quad Output SPI) */
+#define SPINOR_OP_READ_1_4_4_4B	0xec	/* Read data bytes (Quad I/O SPI) */
 #define SPINOR_OP_PP_4B		0x12	/* Page program (up to 256 bytes) */
+#define SPINOR_OP_PP_1_1_4_4B	0x34	/* Quad page program */
+#define SPINOR_OP_PP_1_4_4_4B	0x3e	/* Quad page program */
+#define SPINOR_OP_BE_4K_4B	0x21	/* Erase 4KiB block */
+#define SPINOR_OP_BE_32K_4B	0x5c	/* Erase 32KiB block */
 #define SPINOR_OP_SE_4B		0xdc	/* Sector erase (usually 64KiB) */
 
 /* Used for SST flashes only. */
-- 
2.7.4



From cyrille.pitchen at atmel.com  Wed Oct  5 05:00:34 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Wed, 5 Oct 2016 14:00:34 +0200
Subject: [PATCH v2 3/9] mtd: spi-nor: add support of SPI protocols like SPI
 1-2-2 and SPI 1-4-4
In-Reply-To: <cover.1475668319.git.cyrille.pitchen@atmel.com>
References: <cover.1475668319.git.cyrille.pitchen@atmel.com>
Message-ID: <ccabd886303e976ef07dd7ba04d5eb349810593f.1475668319.git.cyrille.pitchen@atmel.com>

This patch changes the prototype of spi_nor_scan(): its 3rd parameter
is replaced by a const struct spi_nor_modes pointer, which tells the
spi-nor framework about which SPI protocols are supported by the SPI
controller.

Besides, this patch also introduces a new spi_nor_basic_flash_parameter
structure telling the spi-nor framework about the SPI protocols supported
by the SPI memory and the needed op codes to use these SPI protocols.

Currently the struct spi_nor_basic_flash_parameter is filled with legacy
values but a later patch will allow to fill it dynamically by reading the
JESD216 Serial Flash Discoverable Parameter (SFDP) tables from the SPI
memory.

With both structures, the spi-nor framework can now compute the best
match between SPI protocols supported by both the (Q)SPI memory and
controller hence selecting the relevant op codes for (Fast) Read, Page
Program and Sector Erase operations.

The spi_nor_basic_flash_parameter structure also provides the spi-nor
framework with the number of dummy cycles to be used with each Fast Read
commands and the erase block size associated to the erase block op codes.

Finally the spi_nor_basic_flash_parameter structure, through the optional
.enable_quad_io() hook, tells the spi-nor framework how to set the Quad
Enable (QE) bit of the QSPI memory to enable its Quad SPI features.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
 drivers/mtd/devices/m25p80.c          |  17 ++-
 drivers/mtd/spi-nor/atmel-quadspi.c   |  83 ++++++----
 drivers/mtd/spi-nor/cadence-quadspi.c |  18 ++-
 drivers/mtd/spi-nor/fsl-quadspi.c     |   8 +-
 drivers/mtd/spi-nor/hisi-sfc.c        |  32 +++-
 drivers/mtd/spi-nor/mtk-quadspi.c     |  16 +-
 drivers/mtd/spi-nor/nxp-spifi.c       |  21 +--
 drivers/mtd/spi-nor/spi-nor.c         | 280 +++++++++++++++++++++++++++-------
 include/linux/mtd/spi-nor.h           | 136 +++++++++++++++--
 9 files changed, 482 insertions(+), 129 deletions(-)

diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 9cf7fcd28034..f0a55c01406b 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -111,10 +111,10 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
 
 static inline unsigned int m25p80_rx_nbits(struct spi_nor *nor)
 {
-	switch (nor->flash_read) {
-	case SPI_NOR_DUAL:
+	switch (SNOR_PROTO_DATA_FROM_PROTO(nor->read_proto)) {
+	case 2:
 		return 2;
-	case SPI_NOR_QUAD:
+	case 4:
 		return 4;
 	default:
 		return 0;
@@ -195,7 +195,10 @@ static int m25p_probe(struct spi_device *spi)
 	struct flash_platform_data	*data;
 	struct m25p *flash;
 	struct spi_nor *nor;
-	enum read_mode mode = SPI_NOR_NORMAL;
+	struct spi_nor_modes modes = {
+		.rd_modes = SNOR_MODE_SLOW,
+		.wr_modes = SNOR_MODE_1_1_1,
+	};
 	char *flash_name;
 	int ret;
 
@@ -221,9 +224,9 @@ static int m25p_probe(struct spi_device *spi)
 	flash->spi = spi;
 
 	if (spi->mode & SPI_RX_QUAD)
-		mode = SPI_NOR_QUAD;
+		modes.rd_modes |= SNOR_MODE_1_1_4;
 	else if (spi->mode & SPI_RX_DUAL)
-		mode = SPI_NOR_DUAL;
+		modes.rd_modes |= SNOR_MODE_1_1_2;
 
 	if (data && data->name)
 		nor->mtd.name = data->name;
@@ -240,7 +243,7 @@ static int m25p_probe(struct spi_device *spi)
 	else
 		flash_name = spi->modalias;
 
-	ret = spi_nor_scan(nor, flash_name, mode);
+	ret = spi_nor_scan(nor, flash_name, &modes);
 	if (ret)
 		return ret;
 
diff --git a/drivers/mtd/spi-nor/atmel-quadspi.c b/drivers/mtd/spi-nor/atmel-quadspi.c
index 47937d9beec6..9f7e3124e8b8 100644
--- a/drivers/mtd/spi-nor/atmel-quadspi.c
+++ b/drivers/mtd/spi-nor/atmel-quadspi.c
@@ -275,14 +275,48 @@ static void atmel_qspi_debug_command(struct atmel_qspi *aq,
 
 static int atmel_qspi_run_command(struct atmel_qspi *aq,
 				  const struct atmel_qspi_command *cmd,
-				  u32 ifr_tfrtyp, u32 ifr_width)
+				  u32 ifr_tfrtyp, enum spi_nor_protocol proto)
 {
 	u32 iar, icr, ifr, sr;
 	int err = 0;
 
 	iar = 0;
 	icr = 0;
-	ifr = ifr_tfrtyp | ifr_width;
+	ifr = ifr_tfrtyp;
+
+	/* Set the SPI protocol */
+	switch (proto) {
+	case SNOR_PROTO_1_1_1:
+		ifr |= QSPI_IFR_WIDTH_SINGLE_BIT_SPI;
+		break;
+
+	case SNOR_PROTO_1_1_2:
+		ifr |= QSPI_IFR_WIDTH_DUAL_OUTPUT;
+		break;
+
+	case SNOR_PROTO_1_1_4:
+		ifr |= QSPI_IFR_WIDTH_QUAD_OUTPUT;
+		break;
+
+	case SNOR_PROTO_1_2_2:
+		ifr |= QSPI_IFR_WIDTH_DUAL_IO;
+		break;
+
+	case SNOR_PROTO_1_4_4:
+		ifr |= QSPI_IFR_WIDTH_QUAD_IO;
+		break;
+
+	case SNOR_PROTO_2_2_2:
+		ifr |= QSPI_IFR_WIDTH_DUAL_CMD;
+		break;
+
+	case SNOR_PROTO_4_4_4:
+		ifr |= QSPI_IFR_WIDTH_QUAD_CMD;
+		break;
+
+	default:
+		return -EINVAL;
+	}
 
 	/* Compute instruction parameters */
 	if (cmd->enable.bits.instruction) {
@@ -434,7 +468,7 @@ static int atmel_qspi_read_reg(struct spi_nor *nor, u8 opcode,
 	cmd.rx_buf = buf;
 	cmd.buf_len = len;
 	return atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_READ,
-				      QSPI_IFR_WIDTH_SINGLE_BIT_SPI);
+				      nor->reg_proto);
 }
 
 static int atmel_qspi_write_reg(struct spi_nor *nor, u8 opcode,
@@ -450,7 +484,7 @@ static int atmel_qspi_write_reg(struct spi_nor *nor, u8 opcode,
 	cmd.tx_buf = buf;
 	cmd.buf_len = len;
 	return atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_WRITE,
-				      QSPI_IFR_WIDTH_SINGLE_BIT_SPI);
+				      nor->reg_proto);
 }
 
 static ssize_t atmel_qspi_write(struct spi_nor *nor, loff_t to, size_t len,
@@ -469,7 +503,7 @@ static ssize_t atmel_qspi_write(struct spi_nor *nor, loff_t to, size_t len,
 	cmd.tx_buf = write_buf;
 	cmd.buf_len = len;
 	ret = atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_WRITE_MEM,
-				     QSPI_IFR_WIDTH_SINGLE_BIT_SPI);
+				     nor->write_proto);
 	return (ret < 0) ? ret : len;
 }
 
@@ -484,7 +518,7 @@ static int atmel_qspi_erase(struct spi_nor *nor, loff_t offs)
 	cmd.instruction = nor->erase_opcode;
 	cmd.address = (u32)offs;
 	return atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_WRITE,
-				      QSPI_IFR_WIDTH_SINGLE_BIT_SPI);
+				      nor->reg_proto);
 }
 
 static ssize_t atmel_qspi_read(struct spi_nor *nor, loff_t from, size_t len,
@@ -493,27 +527,8 @@ static ssize_t atmel_qspi_read(struct spi_nor *nor, loff_t from, size_t len,
 	struct atmel_qspi *aq = nor->priv;
 	struct atmel_qspi_command cmd;
 	u8 num_mode_cycles, num_dummy_cycles;
-	u32 ifr_width;
 	ssize_t ret;
 
-	switch (nor->flash_read) {
-	case SPI_NOR_NORMAL:
-	case SPI_NOR_FAST:
-		ifr_width = QSPI_IFR_WIDTH_SINGLE_BIT_SPI;
-		break;
-
-	case SPI_NOR_DUAL:
-		ifr_width = QSPI_IFR_WIDTH_DUAL_OUTPUT;
-		break;
-
-	case SPI_NOR_QUAD:
-		ifr_width = QSPI_IFR_WIDTH_QUAD_OUTPUT;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
 	if (nor->read_dummy >= 2) {
 		num_mode_cycles = 2;
 		num_dummy_cycles = nor->read_dummy - 2;
@@ -536,7 +551,7 @@ static ssize_t atmel_qspi_read(struct spi_nor *nor, loff_t from, size_t len,
 	cmd.rx_buf = read_buf;
 	cmd.buf_len = len;
 	ret = atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_READ_MEM,
-				     ifr_width);
+				     nor->read_proto);
 	return (ret < 0) ? ret : len;
 }
 
@@ -596,6 +611,20 @@ static int atmel_qspi_probe(struct platform_device *pdev)
 	struct spi_nor *nor;
 	struct mtd_info *mtd;
 	int irq, err = 0;
+	struct spi_nor_modes modes = {
+		.rd_modes = (SNOR_MODE_SLOW |
+			     SNOR_MODE_1_1_1 |
+			     SNOR_MODE_1_1_2 |
+			     SNOR_MODE_1_1_4 |
+			     SNOR_MODE_1_2_2 |
+			     SNOR_MODE_1_4_4),
+		.wr_modes = (SNOR_MODE_SLOW |
+			     SNOR_MODE_1_1_1 |
+			     SNOR_MODE_1_1_2 |
+			     SNOR_MODE_1_1_4 |
+			     SNOR_MODE_1_2_2 |
+			     SNOR_MODE_1_4_4),
+	};
 
 	if (of_get_child_count(np) != 1)
 		return -ENODEV;
@@ -679,7 +708,7 @@ static int atmel_qspi_probe(struct platform_device *pdev)
 	if (err)
 		goto disable_clk;
 
-	err = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
+	err = spi_nor_scan(nor, NULL, &modes);
 	if (err)
 		goto disable_clk;
 
diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c
index d403ba7b8f43..87e49231b4ee 100644
--- a/drivers/mtd/spi-nor/cadence-quadspi.c
+++ b/drivers/mtd/spi-nor/cadence-quadspi.c
@@ -853,15 +853,14 @@ static int cqspi_set_protocol(struct spi_nor *nor, const int read)
 	f_pdata->data_width = CQSPI_INST_TYPE_SINGLE;
 
 	if (read) {
-		switch (nor->flash_read) {
-		case SPI_NOR_NORMAL:
-		case SPI_NOR_FAST:
+		switch (nor->read_proto) {
+		case SNOR_PROTO_1_1_1:
 			f_pdata->data_width = CQSPI_INST_TYPE_SINGLE;
 			break;
-		case SPI_NOR_DUAL:
+		case SNOR_PROTO_1_1_2:
 			f_pdata->data_width = CQSPI_INST_TYPE_DUAL;
 			break;
-		case SPI_NOR_QUAD:
+		case SNOR_PROTO_1_1_4:
 			f_pdata->data_width = CQSPI_INST_TYPE_QUAD;
 			break;
 		default:
@@ -1074,6 +1073,13 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
 	struct mtd_info *mtd;
 	unsigned int cs;
 	int i, ret;
+	static const struct spi_nor_modes modes = {
+		.rd_modes = (SNOR_MODE_SLOW |
+			     SNOR_MODE_1_1_1 |
+			     SNOR_MODE_1_1_2 |
+			     SNOR_MODE_1_1_4),
+		.wr_modes = SNOR_MODE_1_1_1,
+	};
 
 	/* Get flash device data */
 	for_each_available_child_of_node(dev->of_node, np) {
@@ -1119,7 +1125,7 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
 			goto err;
 		}
 
-		ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
+		ret = spi_nor_scan(nor, NULL, &modes);
 		if (ret)
 			goto err;
 
diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c
index 5c82e4ef1904..01e7356d6623 100644
--- a/drivers/mtd/spi-nor/fsl-quadspi.c
+++ b/drivers/mtd/spi-nor/fsl-quadspi.c
@@ -980,6 +980,12 @@ static int fsl_qspi_probe(struct platform_device *pdev)
 	struct spi_nor *nor;
 	struct mtd_info *mtd;
 	int ret, i = 0;
+	static const struct spi_nor_modes modes = {
+		.rd_modes = (SNOR_MODE_SLOW |
+			     SNOR_MODE_1_1_1 |
+			     SNOR_MODE_1_1_4),
+		.wr_modes = SNOR_MODE_1_1_1,
+	};
 
 	q = devm_kzalloc(dev, sizeof(*q), GFP_KERNEL);
 	if (!q)
@@ -1081,7 +1087,7 @@ static int fsl_qspi_probe(struct platform_device *pdev)
 		/* set the chip address for READID */
 		fsl_qspi_set_base_addr(q, nor);
 
-		ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
+		ret = spi_nor_scan(nor, NULL, &modes);
 		if (ret)
 			goto mutex_failed;
 
diff --git a/drivers/mtd/spi-nor/hisi-sfc.c b/drivers/mtd/spi-nor/hisi-sfc.c
index 20378b0d55e9..e4d7625b4397 100644
--- a/drivers/mtd/spi-nor/hisi-sfc.c
+++ b/drivers/mtd/spi-nor/hisi-sfc.c
@@ -120,19 +120,24 @@ static inline int wait_op_finish(struct hifmc_host *host)
 		(reg & FMC_INT_OP_DONE), 0, FMC_WAIT_TIMEOUT);
 }
 
-static int get_if_type(enum read_mode flash_read)
+static int get_if_type(enum spi_nor_protocol proto)
 {
 	enum hifmc_iftype if_type;
 
-	switch (flash_read) {
-	case SPI_NOR_DUAL:
+	switch (proto) {
+	case SNOR_PROTO_1_1_2:
 		if_type = IF_TYPE_DUAL;
 		break;
-	case SPI_NOR_QUAD:
+	case SNOR_PROTO_1_2_2:
+		if_type = IF_TYPE_DIO;
+		break;
+	case SNOR_PROTO_1_1_4:
 		if_type = IF_TYPE_QUAD;
 		break;
-	case SPI_NOR_NORMAL:
-	case SPI_NOR_FAST:
+	case SNOR_PROTO_1_4_4:
+		if_type = IF_TYPE_QIO;
+		break;
+	case SNOR_PROTO_1_1_1:
 	default:
 		if_type = IF_TYPE_STD;
 		break;
@@ -238,6 +243,7 @@ static int hisi_spi_nor_dma_transfer(struct spi_nor *nor, loff_t start_off,
 {
 	struct hifmc_priv *priv = nor->priv;
 	struct hifmc_host *host = priv->host;
+	enum spi_nor_protocol proto;
 	u8 if_type = 0;
 	u32 reg;
 
@@ -253,7 +259,10 @@ static int hisi_spi_nor_dma_transfer(struct spi_nor *nor, loff_t start_off,
 	writel(FMC_DMA_LEN_SET(len), host->regbase + FMC_DMA_LEN);
 
 	reg = OP_CFG_FM_CS(priv->chipselect);
-	if_type = get_if_type(nor->flash_read);
+	proto = (op_type == FMC_OP_READ)
+		? nor->read_proto
+		: nor->write_proto;
+	if_type = get_if_type(proto);
 	reg |= OP_CFG_MEM_IF_TYPE(if_type);
 	if (op_type == FMC_OP_READ)
 		reg |= OP_CFG_DUMMY_NUM(nor->read_dummy >> 3);
@@ -326,6 +335,13 @@ static int hisi_spi_nor_register(struct device_node *np,
 	struct hifmc_priv *priv;
 	struct mtd_info *mtd;
 	int ret;
+	static const struct spi_nor_modes modes = {
+		.rd_modes = (SNOR_MODE_SLOW |
+			     SNOR_MODE_1_1_1 |
+			     SNOR_MODE_1_1_2 |
+			     SNOR_MODE_1_1_4),
+		.wr_modes = SNOR_MODE_1_1_1,
+	};
 
 	nor = devm_kzalloc(dev, sizeof(*nor), GFP_KERNEL);
 	if (!nor)
@@ -362,7 +378,7 @@ static int hisi_spi_nor_register(struct device_node *np,
 	nor->read = hisi_spi_nor_read;
 	nor->write = hisi_spi_nor_write;
 	nor->erase = NULL;
-	ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
+	ret = spi_nor_scan(nor, NULL, &modes);
 	if (ret)
 		return ret;
 
diff --git a/drivers/mtd/spi-nor/mtk-quadspi.c b/drivers/mtd/spi-nor/mtk-quadspi.c
index e661877c23de..4dc2bb8eb488 100644
--- a/drivers/mtd/spi-nor/mtk-quadspi.c
+++ b/drivers/mtd/spi-nor/mtk-quadspi.c
@@ -121,20 +121,20 @@ static void mt8173_nor_set_read_mode(struct mt8173_nor *mt8173_nor)
 {
 	struct spi_nor *nor = &mt8173_nor->nor;
 
-	switch (nor->flash_read) {
-	case SPI_NOR_FAST:
+	switch (SNOR_PROTO_DATA_FROM_PROTO(nor->read_proto)) {
+	case 1:
 		writeb(nor->read_opcode, mt8173_nor->base +
 		       MTK_NOR_PRGDATA3_REG);
 		writeb(MTK_NOR_FAST_READ, mt8173_nor->base +
 		       MTK_NOR_CFG1_REG);
 		break;
-	case SPI_NOR_DUAL:
+	case 2:
 		writeb(nor->read_opcode, mt8173_nor->base +
 		       MTK_NOR_PRGDATA3_REG);
 		writeb(MTK_NOR_DUAL_READ_EN, mt8173_nor->base +
 		       MTK_NOR_DUAL_REG);
 		break;
-	case SPI_NOR_QUAD:
+	case 4:
 		writeb(nor->read_opcode, mt8173_nor->base +
 		       MTK_NOR_PRGDATA4_REG);
 		writeb(MTK_NOR_QUAD_READ_EN, mt8173_nor->base +
@@ -383,6 +383,12 @@ static int mtk_nor_init(struct mt8173_nor *mt8173_nor,
 {
 	int ret;
 	struct spi_nor *nor;
+	static const struct spi_nor_modes modes = {
+		.rd_modes = (SNOR_MODE_SLOW |
+			     SNOR_MODE_1_1_1 |
+			     SNOR_MODE_1_1_2),
+		.wr_modes = SNOR_MODE_1_1_1,
+	};
 
 	/* initialize controller to accept commands */
 	writel(MTK_NOR_ENABLE_SF_CMD, mt8173_nor->base + MTK_NOR_WRPROT_REG);
@@ -399,7 +405,7 @@ static int mtk_nor_init(struct mt8173_nor *mt8173_nor,
 	nor->write_reg = mt8173_nor_write_reg;
 	nor->mtd.name = "mtk_nor";
 	/* initialized with NULL */
-	ret = spi_nor_scan(nor, NULL, SPI_NOR_DUAL);
+	ret = spi_nor_scan(nor, NULL, &modes);
 	if (ret)
 		return ret;
 
diff --git a/drivers/mtd/spi-nor/nxp-spifi.c b/drivers/mtd/spi-nor/nxp-spifi.c
index 73a14f40928b..327c5b5fe9da 100644
--- a/drivers/mtd/spi-nor/nxp-spifi.c
+++ b/drivers/mtd/spi-nor/nxp-spifi.c
@@ -240,13 +240,12 @@ static int nxp_spifi_erase(struct spi_nor *nor, loff_t offs)
 
 static int nxp_spifi_setup_memory_cmd(struct nxp_spifi *spifi)
 {
-	switch (spifi->nor.flash_read) {
-	case SPI_NOR_NORMAL:
-	case SPI_NOR_FAST:
+	switch (SNOR_PROTO_DATA_FROM_PROTO(spifi->nor.read_proto)) {
+	case 1:
 		spifi->mcmd = SPIFI_CMD_FIELDFORM_ALL_SERIAL;
 		break;
-	case SPI_NOR_DUAL:
-	case SPI_NOR_QUAD:
+	case 2:
+	case 4:
 		spifi->mcmd = SPIFI_CMD_FIELDFORM_QUAD_DUAL_DATA;
 		break;
 	default:
@@ -274,7 +273,10 @@ static void nxp_spifi_dummy_id_read(struct spi_nor *nor)
 static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
 				 struct device_node *np)
 {
-	enum read_mode flash_read;
+	struct spi_nor_modes modes = {
+		.rd_modes = (SNOR_MODE_SLOW | SNOR_MODE_1_1_1),
+		.wr_modes = SNOR_MODE_1_1_1,
+	};
 	u32 ctrl, property;
 	u16 mode = 0;
 	int ret;
@@ -308,13 +310,12 @@ static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
 
 	if (mode & SPI_RX_DUAL) {
 		ctrl |= SPIFI_CTRL_DUAL;
-		flash_read = SPI_NOR_DUAL;
+		modes.rd_modes |= SNOR_MODE_1_1_2;
 	} else if (mode & SPI_RX_QUAD) {
 		ctrl &= ~SPIFI_CTRL_DUAL;
-		flash_read = SPI_NOR_QUAD;
+		modes.rd_modes |= SNOR_MODE_1_1_4;
 	} else {
 		ctrl |= SPIFI_CTRL_DUAL;
-		flash_read = SPI_NOR_NORMAL;
 	}
 
 	switch (mode & (SPI_CPHA | SPI_CPOL)) {
@@ -351,7 +352,7 @@ static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
 	 */
 	nxp_spifi_dummy_id_read(&spifi->nor);
 
-	ret = spi_nor_scan(&spifi->nor, NULL, flash_read);
+	ret = spi_nor_scan(&spifi->nor, NULL, &modes);
 	if (ret) {
 		dev_err(spifi->dev, "device scan failed\n");
 		return ret;
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 423448c1c7a8..51eac2278ec0 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -143,24 +143,6 @@ static int read_cr(struct spi_nor *nor)
 }
 
 /*
- * Dummy Cycle calculation for different type of read.
- * It can be used to support more commands with
- * different dummy cycle requirements.
- */
-static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor)
-{
-	switch (nor->flash_read) {
-	case SPI_NOR_FAST:
-	case SPI_NOR_DUAL:
-	case SPI_NOR_QUAD:
-		return 8;
-	case SPI_NOR_NORMAL:
-		return 0;
-	}
-	return 0;
-}
-
-/*
  * Write status register 1 byte
  * Returns negative if error occurred.
  */
@@ -1384,8 +1366,206 @@ static int spi_nor_check(struct spi_nor *nor)
 	return 0;
 }
 
-int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+static inline void spi_nor_set_read_settings(struct spi_nor_read *read,
+					     u8 num_mode_clocks,
+					     u8 num_wait_states,
+					     u8 opcode)
+{
+	read->num_mode_clocks = num_mode_clocks;
+	read->num_wait_states = num_wait_states;
+	read->opcode = opcode;
+}
+
+static inline void spi_nor_set_erase_settings(struct spi_nor_erase_type *erase,
+					      u8 size, u8 opcode)
+{
+	erase->size = size;
+	erase->opcode = opcode;
+}
+
+static int spi_nor_init_params(struct spi_nor *nor,
+			       const struct flash_info *info,
+			       struct spi_nor_basic_flash_parameter *params)
+{
+	// TODO: parse SFDP table
+
+	/* If SFDP tables are not available, use legacy settings. */
+	memset(params, 0, sizeof(*params));
+
+	/* (Fast) Read settings. */
+	params->rd_modes = SNOR_MODE_SLOW;
+	spi_nor_set_read_settings(&params->reads[SNOR_PINDEX_SLOW],
+				  0, 0, SPINOR_OP_READ);
+	if (!(info->flags & SPI_NOR_NO_FR)) {
+		params->rd_modes |= SNOR_MODE_1_1_1;
+		spi_nor_set_read_settings(&params->reads[SNOR_PINDEX_1_1_1],
+					  0, 8, SPINOR_OP_READ_FAST);
+	}
+	if (info->flags & SPI_NOR_DUAL_READ) {
+		params->rd_modes |= SNOR_MODE_1_1_2;
+		spi_nor_set_read_settings(&params->reads[SNOR_PINDEX_1_1_2],
+					  0, 8, SPINOR_OP_READ_1_1_2);
+	}
+	if (info->flags & SPI_NOR_QUAD_READ) {
+		params->rd_modes|= SNOR_MODE_1_1_4;
+		spi_nor_set_read_settings(&params->reads[SNOR_PINDEX_1_1_4],
+					  0, 8, SPINOR_OP_READ_1_1_4);
+	}
+
+	/* Page Program settings. */
+	params->wr_modes = SNOR_MODE_1_1_1;
+	params->page_programs[SNOR_PINDEX_1_1_1] = SPINOR_OP_PP;
+
+	/* Sector Erase settings. */
+	spi_nor_set_erase_settings(&params->erase_types[0],
+				   SNOR_ERASE_64K, SPINOR_OP_SE);
+	if (info->flags & SECT_4K)
+		spi_nor_set_erase_settings(&params->erase_types[1],
+					   SNOR_ERASE_4K, SPINOR_OP_BE_4K);
+	else if (info->flags & SECT_4K_PMC)
+		spi_nor_set_erase_settings(&params->erase_types[1],
+					   SNOR_ERASE_4K, SPINOR_OP_BE_4K_PMC);
+
+	/* Select the procedure to set the Quad Enable bit. */
+	if (params->rd_modes & (SNOR_MODE_1_1_4 |
+				SNOR_MODE_1_4_4 |
+				SNOR_MODE_4_4_4)) {
+		switch (JEDEC_MFR(info)) {
+		case SNOR_MFR_MACRONIX:
+			params->enable_quad_io = macronix_quad_enable;
+			break;
+
+		case SNOR_MFR_MICRON:
+			break;
+
+		default:
+			params->enable_quad_io = spansion_quad_enable;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int spi_nor_pindex2proto(int pindex, enum spi_nor_protocol *proto)
+{
+	enum spi_nor_protocol_width pwidth;
+	enum spi_nor_protocol_class pclass;
+	uint8_t width;
+
+	if (pindex < 0)
+		return -EINVAL;
+
+	pwidth = (enum spi_nor_protocol_width)(pindex / SNOR_PCLASS_MAX);
+	pclass = (enum spi_nor_protocol_class)(pindex % SNOR_PCLASS_MAX);
+
+	width = (1 << pwidth) & 0xf;
+	if (!width)
+		return -EINVAL;
+
+	switch (pclass) {
+	case SNOR_PCLASS_1_1_N:
+		*proto = SNOR_PROTO(1, 1, width);
+		break;
+
+	case SNOR_PCLASS_1_N_N:
+		*proto = SNOR_PROTO(1, width, width);
+		break;
+
+	case SNOR_PCLASS_N_N_N:
+		*proto = SNOR_PROTO(width, width, width);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
+			 const struct spi_nor_basic_flash_parameter *params,
+			 const struct spi_nor_modes *modes)
 {
+	bool enable_quad_io;
+	u32 rd_modes, wr_modes, mask;
+	const struct spi_nor_erase_type *erase_type = NULL;
+	const struct spi_nor_read *read;
+	int rd_pindex, wr_pindex, i, err = 0;
+	u8 erase_size = SNOR_ERASE_64K;
+
+	/* 2-2-2 or 4-4-4 modes are not supported yet. */
+	mask = (SNOR_MODE_2_2_2 | SNOR_MODE_4_4_4);
+	rd_modes = modes->rd_modes & ~mask;
+	wr_modes = modes->wr_modes & ~mask;
+
+	/* Setup read operation. */
+	rd_pindex = fls(params->rd_modes & rd_modes) - 1;
+	if (spi_nor_pindex2proto(rd_pindex, &nor->read_proto)) {
+		dev_err(nor->dev, "invalid (fast) read\n");
+		return -EINVAL;
+	}
+	read = &params->reads[rd_pindex];
+	nor->read_opcode = read->opcode;
+	nor->read_dummy = read->num_mode_clocks + read->num_wait_states;
+
+	/* Set page program op code and protocol. */
+	wr_pindex = fls(params->wr_modes & wr_modes) - 1;
+	if (spi_nor_pindex2proto(wr_pindex, &nor->write_proto)) {
+		dev_err(nor->dev, "invalid page program\n");
+		return -EINVAL;
+	}
+	nor->program_opcode = params->page_programs[wr_pindex];
+
+	/* Set sector erase op code and size. */
+	erase_type = &params->erase_types[0];
+#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
+	erase_size = SNOR_ERASE_4K;
+#endif
+	for (i = 0; i < SNOR_MAX_ERASE_TYPES; ++i) {
+		if (params->erase_types[i].size == erase_size) {
+			erase_type = &params->erase_types[i];
+			break;
+		} else if (!erase_type->size && params->erase_types[i].size) {
+			erase_type = &params->erase_types[i];
+		}
+	}
+	nor->erase_opcode = erase_type->opcode;
+	nor->mtd.erasesize = (1 << erase_type->size);
+
+
+	enable_quad_io = (SNOR_PROTO_DATA_FROM_PROTO(nor->read_proto) == 4 ||
+			  SNOR_PROTO_DATA_FROM_PROTO(nor->write_proto) == 4);
+
+	/* Enable Quad I/O if needed. */
+	if (enable_quad_io && params->enable_quad_io) {
+		err = params->enable_quad_io(nor);
+		if (err) {
+			dev_err(nor->dev,
+				"failed to enable the Quad I/O mode\n");
+			return err;
+		}
+	}
+
+	dev_dbg(nor->dev,
+		"(Fast) Read:  opcode=%02Xh, protocol=%03x, mode=%u, wait=%u\n",
+		nor->read_opcode, nor->read_proto,
+		read->num_mode_clocks, read->num_wait_states);
+	dev_dbg(nor->dev,
+		"Page Program: opcode=%02Xh, protocol=%03x\n",
+		nor->program_opcode, nor->write_proto);
+	dev_dbg(nor->dev,
+		"Sector Erase: opcode=%02Xh, protocol=%03x, sector size=%u\n",
+		nor->erase_opcode, nor->reg_proto, (u32)nor->mtd.erasesize);
+
+	return 0;
+}
+
+int spi_nor_scan(struct spi_nor *nor, const char *name,
+		 const struct spi_nor_modes *modes)
+{
+	struct spi_nor_basic_flash_parameter params;
+	struct spi_nor_modes fixed_modes = *modes;
 	const struct flash_info *info = NULL;
 	struct device *dev = nor->dev;
 	struct mtd_info *mtd = &nor->mtd;
@@ -1397,6 +1577,11 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 	if (ret)
 		return ret;
 
+	/* Reset SPI protocol for all commands */
+	nor->reg_proto = SNOR_PROTO_1_1_1;
+	nor->read_proto = SNOR_PROTO_1_1_1;
+	nor->write_proto = SNOR_PROTO_1_1_1;
+
 	if (name)
 		info = spi_nor_match_id(name);
 	/* Try to auto-detect if chip name wasn't specified or not found */
@@ -1429,6 +1614,11 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 		}
 	}
 
+	/* Parse the Serial Flash Discoverable Parameters table */
+	ret = spi_nor_init_params(nor, info, &params);
+	if (ret)
+		return ret;
+
 	mutex_init(&nor->lock);
 
 	/*
@@ -1505,51 +1695,31 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 	if (np) {
 		/* If we were instantiated by DT, use it */
 		if (of_property_read_bool(np, "m25p,fast-read"))
-			nor->flash_read = SPI_NOR_FAST;
+			fixed_modes.rd_modes |= SNOR_MODE_1_1_1;
 		else
-			nor->flash_read = SPI_NOR_NORMAL;
+			fixed_modes.rd_modes &= ~SNOR_MODE_1_1_1;
 	} else {
 		/* If we weren't instantiated by DT, default to fast-read */
-		nor->flash_read = SPI_NOR_FAST;
+		fixed_modes.rd_modes |= SNOR_MODE_1_1_1;
 	}
 
 	/* Some devices cannot do fast-read, no matter what DT tells us */
 	if (info->flags & SPI_NOR_NO_FR)
-		nor->flash_read = SPI_NOR_NORMAL;
-
-	/* Quad/Dual-read mode takes precedence over fast/normal */
-	if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) {
-		ret = set_quad_mode(nor, info);
-		if (ret) {
-			dev_err(dev, "quad mode not supported\n");
-			return ret;
-		}
-		nor->flash_read = SPI_NOR_QUAD;
-	} else if (mode == SPI_NOR_DUAL && info->flags & SPI_NOR_DUAL_READ) {
-		nor->flash_read = SPI_NOR_DUAL;
-	}
-
-	/* Default commands */
-	switch (nor->flash_read) {
-	case SPI_NOR_QUAD:
-		nor->read_opcode = SPINOR_OP_READ_1_1_4;
-		break;
-	case SPI_NOR_DUAL:
-		nor->read_opcode = SPINOR_OP_READ_1_1_2;
-		break;
-	case SPI_NOR_FAST:
-		nor->read_opcode = SPINOR_OP_READ_FAST;
-		break;
-	case SPI_NOR_NORMAL:
-		nor->read_opcode = SPINOR_OP_READ;
-		break;
-	default:
-		dev_err(dev, "No Read opcode defined\n");
-		return -EINVAL;
-	}
+		fixed_modes.rd_modes &= ~SNOR_MODE_1_1_1;
 
 	nor->program_opcode = SPINOR_OP_PP;
 
+	/*
+	 * Configure the SPI memory:
+	 * - select op codes for (Fast) Read, Page Program and Sector Erase.
+	 * - set the number of dummy cycles (mode cycles + wait states).
+	 * - set the SPI protocols for register and memory accesses.
+	 * - set the Quad Enable bit if needed (required by SPI x-y-4 protos).
+	 */
+	ret = spi_nor_setup(nor, info, &params, &fixed_modes);
+	if (ret)
+		return ret;
+
 	if (info->addr_width)
 		nor->addr_width = info->addr_width;
 	else if (mtd->size > 0x1000000) {
@@ -1570,8 +1740,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 		return -EINVAL;
 	}
 
-	nor->read_dummy = spi_nor_read_dummy_cycles(nor);
-
 	dev_info(dev, "%s (%lld Kbytes)\n", info->name,
 			(long long)mtd->size >> 10);
 
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 8b02fd7864d0..730f33dce1ea 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -110,11 +110,124 @@
 /* Configuration Register bits. */
 #define CR_QUAD_EN_SPAN		BIT(1)	/* Spansion Quad I/O */
 
-enum read_mode {
-	SPI_NOR_NORMAL = 0,
-	SPI_NOR_FAST,
-	SPI_NOR_DUAL,
-	SPI_NOR_QUAD,
+
+/* Supported SPI protocols */
+enum spi_nor_protocol_class {
+	SNOR_PCLASS_1_1_N,
+	SNOR_PCLASS_1_N_N,
+	SNOR_PCLASS_N_N_N,
+
+	SNOR_PCLASS_MAX
+};
+
+enum spi_nor_protocol_width {
+	SNOR_PWIDTH_1,
+	SNOR_PWIDTH_2,
+	SNOR_PWIDTH_4,
+	SNOR_PWIDTH_8,
+};
+
+/* The encoding is chosen so the higher index the higher priority */
+#define SNOR_PINDEX(pwidth, pclass) \
+	((pwidth) * SNOR_PCLASS_MAX + (pclass))
+enum spi_nor_protocol_index {
+	SNOR_PINDEX_SLOW  = SNOR_PINDEX(SNOR_PWIDTH_1, SNOR_PCLASS_1_1_N),
+	/* Little trick to make the difference between Read and Fast Read commands. */
+	SNOR_PINDEX_1_1_1 = SNOR_PINDEX(SNOR_PWIDTH_1, SNOR_PCLASS_1_N_N),
+	SNOR_PINDEX_1_1_2 = SNOR_PINDEX(SNOR_PWIDTH_2, SNOR_PCLASS_1_1_N),
+	SNOR_PINDEX_1_2_2 = SNOR_PINDEX(SNOR_PWIDTH_2, SNOR_PCLASS_1_N_N),
+	SNOR_PINDEX_2_2_2 = SNOR_PINDEX(SNOR_PWIDTH_2, SNOR_PCLASS_N_N_N),
+	SNOR_PINDEX_1_1_4 = SNOR_PINDEX(SNOR_PWIDTH_4, SNOR_PCLASS_1_1_N),
+	SNOR_PINDEX_1_4_4 = SNOR_PINDEX(SNOR_PWIDTH_4, SNOR_PCLASS_1_N_N),
+	SNOR_PINDEX_4_4_4 = SNOR_PINDEX(SNOR_PWIDTH_4, SNOR_PCLASS_N_N_N),
+
+	SNOR_PINDEX_MAX
+};
+
+#define SNOR_MODE_SLOW		BIT(SNOR_PINDEX_SLOW)
+#define SNOR_MODE_1_1_1		BIT(SNOR_PINDEX_1_1_1)
+#define SNOR_MODE_1_1_2		BIT(SNOR_PINDEX_1_1_2)
+#define SNOR_MODE_1_2_2		BIT(SNOR_PINDEX_1_2_2)
+#define SNOR_MODE_2_2_2		BIT(SNOR_PINDEX_2_2_2)
+#define SNOR_MODE_1_1_4		BIT(SNOR_PINDEX_1_1_4)
+#define SNOR_MODE_1_4_4		BIT(SNOR_PINDEX_1_4_4)
+#define SNOR_MODE_4_4_4		BIT(SNOR_PINDEX_4_4_4)
+
+struct spi_nor_modes {
+	u32	rd_modes;	/* supported SPI modes for (Fast) Read */
+	u32	wr_modes;	/* supported SPI modes for Page Program */
+};
+
+
+struct spi_nor_read {
+	u8	num_wait_states:5;
+	u8	num_mode_clocks:3;
+	u8	opcode;
+};
+
+struct spi_nor_erase_type {
+	u8	size;	/* specifies 'N' so erase size = 2^N */
+	u8	opcode;
+};
+
+#define SNOR_ERASE_64K		0x10
+#define SNOR_ERASE_32K		0x0f
+#define SNOR_ERASE_4K		0x0c
+
+struct spi_nor;
+
+#define SNOR_MAX_ERASE_TYPES	4
+
+struct spi_nor_basic_flash_parameter {
+	/* Fast Read settings */
+	u32				rd_modes;
+	struct spi_nor_read		reads[SNOR_PINDEX_MAX];
+
+	/* Page Program settings */
+	u32				wr_modes;
+	u8				page_programs[SNOR_PINDEX_MAX];
+
+	/* Sector Erase settings */
+	struct spi_nor_erase_type	erase_types[SNOR_MAX_ERASE_TYPES];
+
+	int (*enable_quad_io)(struct spi_nor *nor);
+};
+
+
+#define SNOR_PROTO_CODE_OFF	8
+#define SNOR_PROTO_CODE_MASK	GENMASK(11, 8)
+#define SNOR_PROTO_CODE_TO_PROTO(code) \
+	(((code) << SNOR_PROTO_CODE_OFF) & SNOR_PROTO_CODE_MASK)
+#define SNOR_PROTO_CODE_FROM_PROTO(proto) \
+	((((u32)(proto)) & SNOR_PROTO_CODE_MASK) >> SNOR_PROTO_CODE_OFF)
+
+#define SNOR_PROTO_ADDR_OFF	4
+#define SNOR_PROTO_ADDR_MASK	GENMASK(7, 4)
+#define SNOR_PROTO_ADDR_TO_PROTO(addr) \
+	(((addr) << SNOR_PROTO_ADDR_OFF) & SNOR_PROTO_ADDR_MASK)
+#define SNOR_PROTO_ADDR_FROM_PROTO(proto) \
+	((((u32)(proto)) & SNOR_PROTO_ADDR_MASK) >> SNOR_PROTO_ADDR_OFF)
+
+#define SNOR_PROTO_DATA_OFF	0
+#define SNOR_PROTO_DATA_MASK	GENMASK(3, 0)
+#define SNOR_PROTO_DATA_TO_PROTO(data) \
+	(((data) << SNOR_PROTO_DATA_OFF) & SNOR_PROTO_DATA_MASK)
+#define SNOR_PROTO_DATA_FROM_PROTO(proto) \
+	((((u32)(proto)) & SNOR_PROTO_DATA_MASK) >> SNOR_PROTO_DATA_OFF)
+
+#define SNOR_PROTO(code, addr, data)	  \
+	(SNOR_PROTO_CODE_TO_PROTO(code) |   \
+	 SNOR_PROTO_ADDR_TO_PROTO(addr) | \
+	 SNOR_PROTO_DATA_TO_PROTO(data))
+
+enum spi_nor_protocol {
+	SNOR_PROTO_1_1_1 = SNOR_PROTO(1, 1, 1),	/* SPI */
+	SNOR_PROTO_1_1_2 = SNOR_PROTO(1, 1, 2),	/* Dual Output */
+	SNOR_PROTO_1_1_4 = SNOR_PROTO(1, 1, 4),	/* Quad Output */
+	SNOR_PROTO_1_2_2 = SNOR_PROTO(1, 2, 2),	/* Dual IO */
+	SNOR_PROTO_1_4_4 = SNOR_PROTO(1, 4, 4),	/* Quad IO */
+	SNOR_PROTO_2_2_2 = SNOR_PROTO(2, 2, 2),	/* Dual Command */
+	SNOR_PROTO_4_4_4 = SNOR_PROTO(4, 4, 4),	/* Quad Command */
 };
 
 #define SPI_NOR_MAX_CMD_SIZE	8
@@ -142,9 +255,11 @@ enum spi_nor_option_flags {
  * @read_opcode:	the read opcode
  * @read_dummy:		the dummy needed by the read operation
  * @program_opcode:	the program opcode
- * @flash_read:		the mode of the read
  * @sst_write_second:	used by the SST write operation
  * @flags:		flag options for the current SPI-NOR (SNOR_F_*)
+ * @read_proto:		the SPI protocol used by read operations
+ * @write_proto:	the SPI protocol used by write operations
+ * @reg_proto		the SPI protocol used by read_reg/write_reg operations
  * @cmd_buf:		used by the write_reg
  * @prepare:		[OPTIONAL] do some preparations for the
  *			read/write/erase/lock/unlock operations
@@ -173,7 +288,9 @@ struct spi_nor {
 	u8			read_opcode;
 	u8			read_dummy;
 	u8			program_opcode;
-	enum read_mode		flash_read;
+	enum spi_nor_protocol	read_proto;
+	enum spi_nor_protocol	write_proto;
+	enum spi_nor_protocol	reg_proto;
 	bool			sst_write_second;
 	u32			flags;
 	u8			cmd_buf[SPI_NOR_MAX_CMD_SIZE];
@@ -211,7 +328,7 @@ static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor)
  * spi_nor_scan() - scan the SPI NOR
  * @nor:	the spi_nor structure
  * @name:	the chip type name
- * @mode:	the read mode supported by the driver
+ * @modes:	the SPI modes supported by the controller driver
  *
  * The drivers can use this fuction to scan the SPI NOR.
  * In the scanning, it will try to get all the necessary information to
@@ -221,6 +338,7 @@ static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor)
  *
  * Return: 0 for success, others for failure.
  */
-int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode);
+int spi_nor_scan(struct spi_nor *nor, const char *name,
+		 const struct spi_nor_modes *modes);
 
 #endif
-- 
2.7.4



From cyrille.pitchen at atmel.com  Wed Oct  5 05:00:35 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Wed, 5 Oct 2016 14:00:35 +0200
Subject: [PATCH v2 4/9] mtd: spi-nor: remove unused set_quad_mode() function
In-Reply-To: <cover.1475668319.git.cyrille.pitchen@atmel.com>
References: <cover.1475668319.git.cyrille.pitchen@atmel.com>
Message-ID: <01ae2a97814fac0b3b8ee56e0e4bb9b541fd17d5.1475668319.git.cyrille.pitchen@atmel.com>

The set_quad_mode() function is no longer used, so we remove it.

This patch is not squashed into the previous patch on purpose for
readiness issue and to ease the review process of the whole series.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 24 ------------------------
 1 file changed, 24 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 51eac2278ec0..ce06c4b49dba 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1331,30 +1331,6 @@ static int spansion_quad_enable(struct spi_nor *nor)
 	return 0;
 }
 
-static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
-{
-	int status;
-
-	switch (JEDEC_MFR(info)) {
-	case SNOR_MFR_MACRONIX:
-		status = macronix_quad_enable(nor);
-		if (status) {
-			dev_err(nor->dev, "Macronix quad-read not enabled\n");
-			return -EINVAL;
-		}
-		return status;
-	case SNOR_MFR_MICRON:
-		return 0;
-	default:
-		status = spansion_quad_enable(nor);
-		if (status) {
-			dev_err(nor->dev, "Spansion quad-read not enabled\n");
-			return -EINVAL;
-		}
-		return status;
-	}
-}
-
 static int spi_nor_check(struct spi_nor *nor)
 {
 	if (!nor->dev || !nor->read || !nor->write ||
-- 
2.7.4



From cyrille.pitchen at atmel.com  Wed Oct  5 05:00:36 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Wed, 5 Oct 2016 14:00:36 +0200
Subject: [PATCH v2 5/9] mtd: m25p80: add support of dual and quad spi
 protocols to all commands
In-Reply-To: <cover.1475668319.git.cyrille.pitchen@atmel.com>
References: <cover.1475668319.git.cyrille.pitchen@atmel.com>
Message-ID: <b53b45107f4f23c088e1eb9a398dcd57900c9f22.1475668319.git.cyrille.pitchen@atmel.com>

Before this patch, m25p80_read() supported few SPI protocols:
- regular SPI 1-1-1
- SPI Dual Output 1-1-2
- SPI Quad Output 1-1-4
On the other hand, all other m25p80_*() hooks only supported SPI 1-1-1.

This patch adds support to all currently existing SPI protocols to
cover as many protocols as possible.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
 drivers/mtd/devices/m25p80.c | 193 +++++++++++++++++++++++++++++++++----------
 1 file changed, 149 insertions(+), 44 deletions(-)

diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index f0a55c01406b..38778eac6c21 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -27,22 +27,64 @@
 #include <linux/spi/flash.h>
 #include <linux/mtd/spi-nor.h>
 
-#define	MAX_CMD_SIZE		6
+#define	MAX_CMD_SIZE		16
 struct m25p {
 	struct spi_device	*spi;
 	struct spi_nor		spi_nor;
 	u8			command[MAX_CMD_SIZE];
 };
 
+static inline int m25p80_proto2nbits(enum spi_nor_protocol proto,
+				     unsigned *code_nbits,
+				     unsigned *addr_nbits,
+				     unsigned *data_nbits)
+{
+	if (code_nbits)
+		*code_nbits = SNOR_PROTO_CODE_FROM_PROTO(proto);
+	if (addr_nbits)
+		*addr_nbits = SNOR_PROTO_ADDR_FROM_PROTO(proto);
+	if (data_nbits)
+		*data_nbits = SNOR_PROTO_DATA_FROM_PROTO(proto);
+
+	return 0;
+}
+
 static int m25p80_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len)
 {
 	struct m25p *flash = nor->priv;
 	struct spi_device *spi = flash->spi;
+	unsigned code_nbits, data_nbits;
+	struct spi_transfer xfers[2];
 	int ret;
 
-	ret = spi_write_then_read(spi, &code, 1, val, len);
+	/* Check the total length of command op code and data. */
+	if (len + 1 > MAX_CMD_SIZE)
+		return -EINVAL;
+
+	/* Get transfer protocols (addr_nbits is not relevant here). */
+	ret = m25p80_proto2nbits(nor->reg_proto,
+				 &code_nbits, NULL, &data_nbits);
+	if (ret < 0)
+		return ret;
+
+	/* Set up transfers. */
+	memset(xfers, 0, sizeof(xfers));
+
+	flash->command[0] = code;
+	xfers[0].len = 1;
+	xfers[0].tx_buf = flash->command;
+	xfers[0].tx_nbits = code_nbits;
+
+	xfers[1].len = len;
+	xfers[1].rx_buf = &flash->command[1];
+	xfers[1].rx_nbits = data_nbits;
+
+	/* Process command. */
+	ret = spi_sync_transfer(spi, xfers, 2);
 	if (ret < 0)
 		dev_err(&spi->dev, "error %d reading %x\n", ret, code);
+	else
+		memcpy(val, &flash->command[1], len);
 
 	return ret;
 }
@@ -65,12 +107,42 @@ static int m25p80_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
 {
 	struct m25p *flash = nor->priv;
 	struct spi_device *spi = flash->spi;
+	unsigned code_nbits, data_nbits, num_xfers = 1;
+	struct spi_transfer xfers[2];
+	int ret;
+
+	/* Check the total length of command op code and data. */
+	if (buf && (len + 1 > MAX_CMD_SIZE))
+		return -EINVAL;
+
+	/* Get transfer protocols (addr_nbits is not relevant here). */
+	ret = m25p80_proto2nbits(nor->reg_proto,
+				 &code_nbits, NULL, &data_nbits);
+	if (ret < 0)
+		return ret;
+
+	/* Set up transfer(s). */
+	memset(xfers, 0, sizeof(xfers));
 
 	flash->command[0] = opcode;
-	if (buf)
+	xfers[0].len = 1;
+	xfers[0].tx_buf = flash->command;
+	xfers[0].tx_nbits = code_nbits;
+
+	if (buf) {
 		memcpy(&flash->command[1], buf, len);
+		if (data_nbits == code_nbits) {
+			xfers[0].len += len;
+		} else {
+			xfers[1].len = len;
+			xfers[1].tx_buf = &flash->command[1];
+			xfers[1].tx_nbits = data_nbits;
+			num_xfers++;
+		}
+	}
 
-	return spi_write(spi, flash->command, len + 1);
+	/* Process command. */
+	return spi_sync_transfer(spi, xfers, num_xfers);
 }
 
 static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
@@ -78,27 +150,48 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
 {
 	struct m25p *flash = nor->priv;
 	struct spi_device *spi = flash->spi;
-	struct spi_transfer t[2] = {};
+	unsigned code_nbits, addr_nbits, data_nbits, num_xfers = 1;
+	struct spi_transfer xfers[3];
 	struct spi_message m;
 	int cmd_sz = m25p_cmdsz(nor);
 	ssize_t ret;
 
-	spi_message_init(&m);
-
 	if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
 		cmd_sz = 1;
 
-	flash->command[0] = nor->program_opcode;
-	m25p_addr2cmd(nor, to, flash->command);
+	/* Get transfer protocols. */
+	ret = m25p80_proto2nbits(nor->write_proto,
+				 &code_nbits, &addr_nbits, &data_nbits);
+	if (ret < 0)
+		return ret;
 
-	t[0].tx_buf = flash->command;
-	t[0].len = cmd_sz;
-	spi_message_add_tail(&t[0], &m);
+	/* Set up transfers. */
+	memset(xfers, 0, sizeof(xfers));
+
+	flash->command[0] = nor->program_opcode;
+	xfers[0].len = 1;
+	xfers[0].tx_buf = flash->command;
+	xfers[0].tx_nbits = code_nbits;
+
+	if (cmd_sz > 1) {
+		m25p_addr2cmd(nor, to, flash->command);
+		if (addr_nbits == code_nbits) {
+			xfers[0].len += nor->addr_width;
+		} else {
+			xfers[1].len = nor->addr_width;
+			xfers[1].tx_buf = &flash->command[1];
+			xfers[1].tx_nbits = addr_nbits;
+			num_xfers++;
+		}
+	}
 
-	t[1].tx_buf = buf;
-	t[1].len = len;
-	spi_message_add_tail(&t[1], &m);
+	xfers[num_xfers].len = len;
+	xfers[num_xfers].tx_buf = buf;
+	xfers[num_xfers].tx_nbits = data_nbits;
+	num_xfers++;
 
+	/* Process command. */
+	spi_message_init_with_transfers(&m, xfers, num_xfers);
 	ret = spi_sync(spi, &m);
 	if (ret)
 		return ret;
@@ -109,18 +202,6 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
 	return ret;
 }
 
-static inline unsigned int m25p80_rx_nbits(struct spi_nor *nor)
-{
-	switch (SNOR_PROTO_DATA_FROM_PROTO(nor->read_proto)) {
-	case 2:
-		return 2;
-	case 4:
-		return 4;
-	default:
-		return 0;
-	}
-}
-
 /*
  * Read an address range from the nor chip.  The address range
  * may be any size provided it is within the physical boundaries.
@@ -130,14 +211,22 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
 {
 	struct m25p *flash = nor->priv;
 	struct spi_device *spi = flash->spi;
-	struct spi_transfer t[2];
-	struct spi_message m;
+	unsigned code_nbits, addr_nbits, data_nbits, num_xfers = 1;
 	unsigned int dummy = nor->read_dummy;
 	ssize_t ret;
+	struct spi_transfer xfers[3];
+	struct spi_message m;
+
+	/* Get transfer protocols. */
+	ret = m25p80_proto2nbits(nor->read_proto,
+				 &code_nbits, &addr_nbits, &data_nbits);
+	if (ret < 0)
+		return ret;
 
 	/* convert the dummy cycles to the number of bytes */
-	dummy /= 8;
+	dummy = (dummy * addr_nbits) / 8;
 
+	/* Use the SPI flash API if supported. */
 	if (spi_flash_read_supported(spi)) {
 		struct spi_flash_read_message msg;
 
@@ -149,10 +238,9 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
 		msg.read_opcode = nor->read_opcode;
 		msg.addr_width = nor->addr_width;
 		msg.dummy_bytes = dummy;
-		/* TODO: Support other combinations */
-		msg.opcode_nbits = SPI_NBITS_SINGLE;
-		msg.addr_nbits = SPI_NBITS_SINGLE;
-		msg.data_nbits = m25p80_rx_nbits(nor);
+		msg.opcode_nbits = code_nbits;
+		msg.addr_nbits = addr_nbits;
+		msg.data_nbits = data_nbits;
 
 		ret = spi_flash_read(spi, &msg);
 		if (ret < 0)
@@ -160,21 +248,38 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
 		return msg.retlen;
 	}
 
-	spi_message_init(&m);
-	memset(t, 0, (sizeof t));
+	/* Set up transfers. */
+	memset(xfers, 0, sizeof(xfers));
 
 	flash->command[0] = nor->read_opcode;
-	m25p_addr2cmd(nor, from, flash->command);
+	xfers[0].len = 1;
+	xfers[0].tx_buf = flash->command;
+	xfers[0].tx_nbits = code_nbits;
 
-	t[0].tx_buf = flash->command;
-	t[0].len = m25p_cmdsz(nor) + dummy;
-	spi_message_add_tail(&t[0], &m);
+	m25p_addr2cmd(nor, from, flash->command);
+	/*
+	 * Clear all dummy/mode cycle bits to avoid sending some manufacturer
+	 * specific pattern, which might make the memory enter its Continuous
+	 * Read mode by mistake.
+	 */
+	memset(flash->command + 1 + nor->addr_width, 0, dummy);
+
+	if (addr_nbits == code_nbits) {
+		xfers[0].len += nor->addr_width + dummy;
+	} else {
+		xfers[1].len = nor->addr_width + dummy;
+		xfers[1].tx_buf = &flash->command[1];
+		xfers[1].tx_nbits = addr_nbits;
+		num_xfers++;
+	}
 
-	t[1].rx_buf = buf;
-	t[1].rx_nbits = m25p80_rx_nbits(nor);
-	t[1].len = min(len, spi_max_transfer_size(spi));
-	spi_message_add_tail(&t[1], &m);
+	xfers[num_xfers].len = len;
+	xfers[num_xfers].rx_buf = buf;
+	xfers[num_xfers].rx_nbits = data_nbits;
+	num_xfers++;
 
+	/* Process command. */
+	spi_message_init_with_transfers(&m, xfers, num_xfers);
 	ret = spi_sync(spi, &m);
 	if (ret)
 		return ret;
-- 
2.7.4



From cyrille.pitchen at atmel.com  Wed Oct  5 05:00:37 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Wed, 5 Oct 2016 14:00:37 +0200
Subject: [PATCH v2 6/9] mtd: spi-nor: parse Serial Flash Discoverable
 Parameters (SFDP) tables
In-Reply-To: <cover.1475668319.git.cyrille.pitchen@atmel.com>
References: <cover.1475668319.git.cyrille.pitchen@atmel.com>
Message-ID: <a7fcbeeba80c9c8eb6516021dab0af8ce638cc8e.1475668319.git.cyrille.pitchen@atmel.com>

This patch adds support the the JESD216B standard and parse the SFDP
tables to dynamically initialize the spi_nor_basic_flash_parameter
structure.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 455 +++++++++++++++++++++++++++++++++++++++++-
 include/linux/mtd/spi-nor.h   |   6 +
 2 files changed, 460 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index ce06c4b49dba..e91b3c39b68e 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -17,6 +17,7 @@
 #include <linux/mutex.h>
 #include <linux/math64.h>
 #include <linux/sizes.h>
+#include <linux/slab.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/of_platform.h>
@@ -79,6 +80,7 @@ struct flash_info {
 					 * Use dedicated 4byte address op codes
 					 * to support memory size above 128Mib.
 					 */
+#define SPI_NOR_SKIP_SFDP	BIT(11) /* Skip read of SFDP tables */
 };
 
 #define JEDEC_MFR(info)	((info)->id[0])
@@ -1331,6 +1333,87 @@ static int spansion_quad_enable(struct spi_nor *nor)
 	return 0;
 }
 
+static int spansion_new_quad_enable(struct spi_nor *nor)
+{
+	u8 sr_cr[2];
+	int ret;
+
+	/* Check current Quad Enable bit value. */
+	ret = read_cr(nor);
+	if (ret < 0) {
+		dev_err(nor->dev,
+			"error while reading configuration register\n");
+		return -EINVAL;
+	}
+	sr_cr[1] = ret;
+	if (sr_cr[1] & CR_QUAD_EN_SPAN)
+		return 0;
+
+	dev_info(nor->dev, "setting Spansion Quad Enable (non-volatile) bit\n");
+
+	/* Keep the current value of the Status Register. */
+	ret = read_sr(nor);
+	if (ret < 0) {
+		dev_err(nor->dev,
+			"error while reading status register\n");
+		return -EINVAL;
+	}
+	sr_cr[0] = ret;
+	sr_cr[1] |= CR_QUAD_EN_SPAN;
+
+	write_enable(nor);
+
+	ret = nor->write_reg(nor, SPINOR_OP_WRSR, sr_cr, 2);
+	if (ret < 0) {
+		dev_err(nor->dev,
+			"error while writing configuration register\n");
+		return -EINVAL;
+	}
+
+	/* read back and check it */
+	ret = read_cr(nor);
+	if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
+		dev_err(nor->dev, "Spansion Quad bit not set\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int sr2_bit7_quad_enable(struct spi_nor *nor)
+{
+	u8 sr2;
+	int ret;
+
+	/* Check current Quad Enable bit value. */
+	ret = nor->read_reg(nor, SPINOR_OP_RDSR2, &sr2, 1);
+	if (ret)
+		return ret;
+	if (sr2 & SR2_QUAD_EN_BIT7)
+		return 0;
+
+	/* Update the Quad Enable bit. */
+	sr2 |= SR2_QUAD_EN_BIT7;
+
+	write_enable(nor);
+
+	ret = nor->write_reg(nor, SPINOR_OP_WRSR2, &sr2, 1);
+	if (ret < 0) {
+		dev_err(nor->dev,
+			"error while writing status register 2\n");
+		return -EINVAL;
+	}
+
+	/* Read back and check it. */
+	ret = nor->read_reg(nor, SPINOR_OP_RDSR2, &sr2, 1);
+	if (ret || !(sr2 & SR2_QUAD_EN_BIT7)) {
+		dev_err(nor->dev, "SR2 Quad bit not set\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int spi_nor_check(struct spi_nor *nor)
 {
 	if (!nor->dev || !nor->read || !nor->write ||
@@ -1359,11 +1442,380 @@ static inline void spi_nor_set_erase_settings(struct spi_nor_erase_type *erase,
 	erase->opcode = opcode;
 }
 
+static int spi_nor_read_sfdp(struct spi_nor *nor, u32 addr, size_t len, void *buf)
+{
+	u8 addr_width, read_opcode, read_dummy;
+	int ret;
+
+	read_opcode = nor->read_opcode;
+	addr_width = nor->addr_width;
+	read_dummy = nor->read_dummy;
+
+	nor->read_opcode = SPINOR_OP_RDSFDP;
+	nor->addr_width = 3;
+	nor->read_dummy = 8;
+
+	ret = nor->read(nor, addr, len, (u8 *)buf);
+
+	nor->read_opcode = read_opcode;
+	nor->addr_width = addr_width;
+	nor->read_dummy = read_dummy;
+
+	return (ret < 0) ? ret : 0;
+}
+
+struct sfdp_parameter_header {
+	u8		id_lsb;
+	u8		minor;
+	u8		major;
+	u8		length; /* in double words */
+	u8		parameter_table_pointer[3]; /* byte address */
+	u8		id_msb;
+};
+
+#define SFDP_PARAM_HEADER_ID(p)	((u16)(((p)->id_msb << 8) | (p)->id_lsb))
+#define SFDP_PARAM_HEADER_PTP(p) \
+	((u32)(((p)->parameter_table_pointer[2] << 16) | \
+	       ((p)->parameter_table_pointer[1] <<  8) | \
+	       ((p)->parameter_table_pointer[0] <<  0)))
+
+
+#define SFDP_BFPT_ID		0xff00u	/* Basic Flash Parameter Table */
+
+#define SFDP_SIGNATURE		0x50444653u
+#define SFDP_JESD216_MAJOR	1
+#define SFDP_JESD216_MINOR	0
+#define SFDP_JESD216A_MINOR	5
+#define SFDP_JESD216B_MINOR	6
+
+struct sfdp_header {
+	u32		signature; /* Ox50444653 <=> "SFDP" */
+	u8		minor;
+	u8		major;
+	u8		nph; /* 0-base number of parameter headers */
+	u8		unused;
+
+	/* Basic Flash Parameter Table. */
+	struct sfdp_parameter_header	bfpt_header;
+};
+
+/* Basic Flash Parameter Table */
+
+/* 1st DWORD. */
+#define BFPT_WORD0_FAST_READ_1_1_2	BIT(16)
+#define BFPT_WORD0_ADDRESS_BYTES_MASK	GENMASK(18, 17)
+#define BFPT_WORD0_ADDRESS_BYTES_3_ONLY	(0u << 17)
+#define BFPT_WORD0_ADDRESS_BYTES_3_OR_4	(1u << 17)
+#define BFPT_WORD0_ADDRESS_BYTES_4_ONLY	(2u << 17)
+#define BFPT_WORD0_DTR			BIT(19)
+#define BFPT_WORD0_FAST_READ_1_2_2	BIT(20)
+#define BFPT_WORD0_FAST_READ_1_4_4	BIT(21)
+#define BFPT_WORD0_FAST_READ_1_1_4	BIT(22)
+
+/* 15th DWORD. */
+
+/*
+ * (from JESD216B)
+ * Quad Enable Requirements (QER):
+ * - 000b: Device does not have a QE bit. Device detects 1-1-4 and 1-4-4
+ *         reads based on instruction. DQ3/HOLD# functions are hold during
+ *         instruction pahse.
+ * - 001b: QE is bit 1 of status register 2. It is set via Write Status with
+ *         two data bytes where bit 1 of the second byte is one.
+ *         [...]
+ *         Writing only one byte to the status register has the side-effect of
+ *         clearing status register 2, including the QE bit. The 100b code is
+ *         used if writing one byte to the status register does not modify
+ *         status register 2.
+ * - 010b: QE is bit 6 of status register 1. It is set via Write Status with
+ *         one data byte where bit 6 is one.
+ *         [...]
+ * - 011b: QE is bit 7 of status register 2. It is set via Write status
+ *         register 2 instruction 3Eh with one data byte where bit 7 is one.
+ *         [...]
+ *         The status register 2 is read using instruction 3Fh.
+ * - 100b: QE is bit 1 of status register 2. It is set via Write Status with
+ *         two data bytes where bit 1 of the second byte is one.
+ *         [...]
+ *         In contrast to the 001b code, writing one byte to the status
+ *         register does not modify status register 2.
+ * - 101b: QE is bit 1 of status register 2. Status register 1 is read using
+ *         Read Status instruction 05h. Status register2 is read using
+ *         instruction 35h. QE is set via Writ Status instruction 01h with
+ *         two data bytes where bit 1 of the second byte is one.
+ *         [...]
+ */
+#define BFPT_WORD14_QER_MASK		GENMASK(22, 20)
+#define BFPT_WORD14_QER_NONE		(0 << 20) /* Micron */
+#define BFPT_WORD14_QER_SR2_BIT1_BUGGY	(1 << 20)
+#define BFPT_WORD14_QER_SR1_BIT6	(2 << 20) /* Macronix */
+#define BFPT_WORD14_QER_SR2_BIT7	(3 << 20)
+#define BFPT_WORD14_QER_SR2_BIT1_NO_RD	(4 << 20)
+#define BFPT_WORD14_QER_SR2_BIT1	(5 << 20) /* Spansion */
+
+/* JESD216B defines a Basic Flash Parameter Table of 16 words. */
+#define SFDP_BFPT_MAX_WORDS	16
+
+struct sfdp_bfpt {
+	u32	word[SFDP_BFPT_MAX_WORDS];
+};
+
+/* Fast Read settings. */
+#define BFPT_FAST_READ_WAIT_STATES(half)	((((u16)(half)) >> 0) & 0x1f)
+#define BFPT_FAST_READ_MODE_CLOCKS(half)	((((u16)(half)) >> 5) & 0x07)
+#define BFPT_FAST_READ_OP_CODE(half)		((((u16)(half)) >> 8) & 0xff)
+
+struct sfdp_read {
+	/* The protocol index of SPI x-y-z. */
+	enum spi_nor_protocol_index	pindex;
+
+	/*
+	 * The bit <wbit> in DWORD<windex> tells us whether the
+	 * Fast Read x-y-z command is supported.
+	 */
+	int				windex;
+	int				wbit;
+
+	/*
+	 * The half-word at offset <hshift> in DWORD<hindex> encodes the
+	 * op code, the number of mode clocks and the number of wait states
+	 * to be used by Fast Read x-y-z commands.
+	 */
+	int				hindex;
+	int				hshift;
+};
+
+static const struct sfdp_read sfdp_reads[] = {
+	/* Supported: DWORD0 bit 16,  Settings: DWORD3 bit[15:0] */
+	{SNOR_PINDEX_1_1_2, 0, 16, 3,  0},
+
+	/* Supported: DWORD0 bit 20,  Settings: DWORD3 bit[31:16] */
+	{SNOR_PINDEX_1_2_2, 0, 20, 3, 16},
+
+	/* Supported: DWORD4 bit  0,  Settings: DWORD5 bit[31:16] */
+	{SNOR_PINDEX_2_2_2, 4,  0, 5, 16},
+
+	/* Supported: DWORD0 bit 22,  Settings: DWORD2 bit[31:16] */
+	{SNOR_PINDEX_1_1_4, 0, 22, 2, 16},
+
+	/* Supported: DWORD0 bit 21,  Settings: DWORD2 bit[15:0] */
+	{SNOR_PINDEX_1_4_4, 0, 21, 2, 0},
+
+	/* Supported: DWORD4 bit  4,  Settings: DWORD6 bit[31:16] */
+	{SNOR_PINDEX_4_4_4, 4, 4, 6, 16},
+};
+
+
+/* Sector Erase settings. */
+#define BFPT_ERASE_SIZE(half)		((((u16)(half)) >> 0) & 0xff)
+#define BFPT_ERASE_OP_CODE(half)	((((u16)(half)) >> 8) & 0xff)
+
+struct sfdp_erase {
+	/*
+	 * The half-word at offset <hshift> in DWORD<hindex> encodes the
+	 * op code and erase sector size to be used by Sector Erase commands.
+	 */
+	int		hindex;
+	int		hshift;
+};
+
+static const struct sfdp_erase sfdp_erases[SNOR_MAX_ERASE_TYPES] = {
+	/* Erase Type 1 in DWORD7 bits[15:0] */
+	{7, 0},
+
+	/* Erase Type 2 in DWORD7 bits[31:16] */
+	{7, 16},
+
+	/* Erase Type 3 in DWORD8 bits[15:0] */
+	{8, 0},
+
+	/* Erase Type 4: in DWORD8 bits[31:16] */
+	{8, 16},
+};
+
+
+static int spi_nor_parse_bfpt(struct spi_nor *nor,
+			      const struct sfdp_parameter_header *bfpt_header,
+			      struct spi_nor_basic_flash_parameter *params)
+{
+	struct sfdp_bfpt bfpt;
+	size_t len;
+	int i, err;
+	u32 addr;
+	u16 half;
+
+	/* JESD216 Basic Flash Parameter Table length is at least 9 words. */
+	if (bfpt_header->length < 9)
+		return -EINVAL;
+
+	/* Read the Basic Flash Parameter Table. */
+	len = min_t(size_t, sizeof(bfpt),
+		    bfpt_header->length * sizeof(uint32_t));
+	addr = SFDP_PARAM_HEADER_PTP(bfpt_header);
+	memset(&bfpt, 0, sizeof(bfpt));
+	err = spi_nor_read_sfdp(nor,  addr, len, &bfpt);
+	if (err)
+		return err;
+
+	for (i = 0; i < SFDP_BFPT_MAX_WORDS; ++i)
+		bfpt.word[i] = le32_to_cpu(bfpt.word[i]);
+
+	memset(params, 0, sizeof(*params));
+
+	/* Fast Read settings. */
+	params->rd_modes = (SNOR_MODE_SLOW | SNOR_MODE_1_1_1);
+	spi_nor_set_read_settings(&params->reads[SNOR_PINDEX_SLOW],
+				  0, 0, SPINOR_OP_READ);
+	spi_nor_set_read_settings(&params->reads[SNOR_PINDEX_1_1_1],
+				  0, 8, SPINOR_OP_READ_FAST);
+
+	for (i = 0; i < ARRAY_SIZE(sfdp_reads); ++i) {
+		const struct sfdp_read *rd_info = &sfdp_reads[i];
+		struct spi_nor_read *read = &params->reads[rd_info->pindex];
+
+		if (!(bfpt.word[rd_info->windex] & BIT(rd_info->wbit)))
+			continue;
+
+		params->rd_modes |= BIT(rd_info->pindex);
+		half = bfpt.word[rd_info->hindex] >> rd_info->hshift;
+		read->num_mode_clocks = BFPT_FAST_READ_MODE_CLOCKS(half);
+		read->num_wait_states = BFPT_FAST_READ_WAIT_STATES(half);
+		read->opcode = BFPT_FAST_READ_OP_CODE(half);
+	}
+
+	/* Page Program settings. */
+	params->wr_modes = SNOR_MODE_1_1_1;
+	params->page_programs[SNOR_PINDEX_1_1_1] = SPINOR_OP_PP;
+
+	/* Sector Erase settings. */
+	for (i = 0; i < SNOR_MAX_ERASE_TYPES; ++i) {
+		const struct sfdp_erase *er_info = &sfdp_erases[i];
+		struct spi_nor_erase_type *erase = &params->erase_types[i];
+
+		half = bfpt.word[er_info->hindex] >> er_info->hshift;
+		erase->size = BFPT_ERASE_SIZE(half);
+		erase->opcode = BFPT_ERASE_OP_CODE(half);
+	}
+
+	/* Stop here if not JESD216 rev B or later. */
+	if (bfpt_header->length < 15)
+		return 0;
+
+	/* Enable Quad I/O. */
+	switch (bfpt.word[14] & BFPT_WORD14_QER_MASK) {
+	default:
+	case BFPT_WORD14_QER_NONE:
+		break;
+
+	case BFPT_WORD14_QER_SR2_BIT1_BUGGY:
+	case BFPT_WORD14_QER_SR2_BIT1_NO_RD:
+		params->enable_quad_io = spansion_quad_enable;
+		break;
+
+	case BFPT_WORD14_QER_SR1_BIT6:
+		params->enable_quad_io = macronix_quad_enable;
+		break;
+
+	case BFPT_WORD14_QER_SR2_BIT7:
+		params->enable_quad_io = sr2_bit7_quad_enable;
+		break;
+
+	case BFPT_WORD14_QER_SR2_BIT1:
+		params->enable_quad_io = spansion_new_quad_enable;
+		break;
+	}
+
+	return 0;
+}
+
+static int spi_nor_parse_sfdp(struct spi_nor *nor,
+			      struct spi_nor_basic_flash_parameter *params)
+{
+	const struct sfdp_parameter_header *param_header, *bfpt_header;
+	struct sfdp_parameter_header *param_headers = NULL;
+	struct sfdp_header header;
+	size_t psize;
+	int i, err;
+
+	/* Get the SFDP header. */
+	err = spi_nor_read_sfdp(nor, 0, sizeof(header), &header);
+	if (err)
+		return err;
+
+	/* Check the SFDP header version. */
+	if (le32_to_cpu(header.signature) != SFDP_SIGNATURE ||
+	    header.major != SFDP_JESD216_MAJOR ||
+	    header.minor < SFDP_JESD216_MINOR)
+		return -EINVAL;
+
+	/*
+	 * Verify that the first and only mandatory parameter header is a
+	 * Basic Flash Parameter Table header as specified in JESD216.
+	 */
+	bfpt_header = &header.bfpt_header;
+	if (SFDP_PARAM_HEADER_ID(bfpt_header) != SFDP_BFPT_ID ||
+	    bfpt_header->major != SFDP_JESD216_MAJOR)
+		return -EINVAL;
+
+	/* Allocate memory for parameter headers. */
+	if (header.nph) {
+		psize = header.nph * sizeof(*param_headers);
+
+		param_headers = kmalloc(psize, GFP_KERNEL);
+		if (!param_headers) {
+			dev_err(nor->dev,
+				"failed to allocate memory for SFDP parameter headers\n");
+			return -ENOMEM;
+		}
+
+		err = spi_nor_read_sfdp(nor, sizeof(header),
+					psize, param_headers);
+		if (err) {
+			dev_err(nor->dev,
+				"failed to read SFDP parameter headers\n");
+			goto exit;
+		}
+	}
+
+	/*
+	 * Check other parameter headers to get the latest revision of
+	 * the basic flash parameter table.
+	 */
+	for (i = 0; i < header.nph; ++i) {
+		param_header = &param_headers[i];
+
+		if (SFDP_PARAM_HEADER_ID(param_header) == SFDP_BFPT_ID &&
+		    param_header->major == SFDP_JESD216_MAJOR &&
+		    (param_header->minor > bfpt_header->minor ||
+		     (param_header->minor == bfpt_header->minor &&
+		      param_header->length > bfpt_header->length)))
+			bfpt_header = param_header;
+	}
+	err = spi_nor_parse_bfpt(nor, bfpt_header, params);
+	if (err)
+		goto exit;
+
+exit:
+	kfree(param_headers);
+	return (err) ? err : bfpt_header->minor;
+}
+
 static int spi_nor_init_params(struct spi_nor *nor,
 			       const struct flash_info *info,
 			       struct spi_nor_basic_flash_parameter *params)
 {
-	// TODO: parse SFDP table
+	int jesd216_minor = -EINVAL;
+
+	/* First trying to parse SFDP tables. */
+	if (!(info->flags & SPI_NOR_SKIP_SFDP)) {
+		jesd216_minor = spi_nor_parse_sfdp(nor, params);
+
+		if (jesd216_minor >= SFDP_JESD216B_MINOR)
+			return 0;
+
+		if (jesd216_minor >= SFDP_JESD216_MINOR)
+			goto set_enable_quad_io;
+	}
 
 	/* If SFDP tables are not available, use legacy settings. */
 	memset(params, 0, sizeof(*params));
@@ -1402,6 +1854,7 @@ static int spi_nor_init_params(struct spi_nor *nor,
 		spi_nor_set_erase_settings(&params->erase_types[1],
 					   SNOR_ERASE_4K, SPINOR_OP_BE_4K_PMC);
 
+set_enable_quad_io:
 	/* Select the procedure to set the Quad Enable bit. */
 	if (params->rd_modes & (SNOR_MODE_1_1_4 |
 				SNOR_MODE_1_4_4 |
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 730f33dce1ea..ede7ad83c9c5 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -41,6 +41,8 @@
 #define SPINOR_OP_WREN		0x06	/* Write enable */
 #define SPINOR_OP_RDSR		0x05	/* Read status register */
 #define SPINOR_OP_WRSR		0x01	/* Write status register 1 byte */
+#define SPINOR_OP_RDSR2		0x3f	/* Read status register 2 */
+#define SPINOR_OP_WRSR2		0x3e	/* Write status register 2 */
 #define SPINOR_OP_READ		0x03	/* Read data bytes (low frequency) */
 #define SPINOR_OP_READ_FAST	0x0b	/* Read data bytes (high frequency) */
 #define SPINOR_OP_READ_1_1_2	0x3b	/* Read data bytes (Dual Output SPI) */
@@ -56,6 +58,7 @@
 #define SPINOR_OP_CHIP_ERASE	0xc7	/* Erase whole flash chip */
 #define SPINOR_OP_SE		0xd8	/* Sector erase (usually 64KiB) */
 #define SPINOR_OP_RDID		0x9f	/* Read JEDEC ID */
+#define SPINOR_OP_RDSFDP	0x5a	/* Read SFDP */
 #define SPINOR_OP_RDCR		0x35	/* Read configuration register */
 #define SPINOR_OP_RDFSR		0x70	/* Read flag status register */
 
@@ -110,6 +113,9 @@
 /* Configuration Register bits. */
 #define CR_QUAD_EN_SPAN		BIT(1)	/* Spansion Quad I/O */
 
+/* Status Register 2 bits. */
+#define SR2_QUAD_EN_BIT7	BIT(7)
+
 
 /* Supported SPI protocols */
 enum spi_nor_protocol_class {
-- 
2.7.4



From cyrille.pitchen at atmel.com  Wed Oct  5 05:00:38 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Wed, 5 Oct 2016 14:00:38 +0200
Subject: [PATCH v2 7/9] mtd: spi-nor: parse SFDP 4-byte Address Instruction
 Table
In-Reply-To: <cover.1475668319.git.cyrille.pitchen@atmel.com>
References: <cover.1475668319.git.cyrille.pitchen@atmel.com>
Message-ID: <d0dc9beb10f077267693a5981dec671a04bcfa85.1475668319.git.cyrille.pitchen@atmel.com>

This patch adds supports for SFDP (JESD216B) 4-byte Address Instruction
Table. This table is optional but when available, we parse it to get the
4-byte address op codes supported by the memory.
Using these op codes is stateless as opposed to entering the 4-byte
address mode or setting the Base Address Register (BAR).

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 140 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 139 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index e91b3c39b68e..879b98ef1d80 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1481,6 +1481,7 @@ struct sfdp_parameter_header {
 
 
 #define SFDP_BFPT_ID		0xff00u	/* Basic Flash Parameter Table */
+#define SFDP_4BAIT_ID		0xff84u	/* 4-byte Address Instruction Table */
 
 #define SFDP_SIGNATURE		0x50444653u
 #define SFDP_JESD216_MAJOR	1
@@ -1728,6 +1729,124 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
 	return 0;
 }
 
+struct sfdp_4bait {
+	enum spi_nor_protocol_index	pindex;
+	int				wbit;
+};
+
+static int spi_nor_parse_4bait(struct spi_nor *nor,
+			       const struct sfdp_parameter_header *param_header,
+			       struct spi_nor_basic_flash_parameter *params)
+{
+	static const struct sfdp_4bait reads[] = {
+		{SNOR_PINDEX_SLOW,  0},	/* 0x13 */
+		{SNOR_PINDEX_1_1_1, 1}, /* 0x0c */
+		{SNOR_PINDEX_1_1_2, 2}, /* 0x3c */
+		{SNOR_PINDEX_1_2_2, 3},	/* 0xbc */
+		{SNOR_PINDEX_1_1_4, 4},	/* 0x6c */
+		{SNOR_PINDEX_1_4_4, 5},	/* 0xec */
+	};
+	static const struct sfdp_4bait programs[] = {
+		{SNOR_PINDEX_1_1_1, 6}, /* 0x12 */
+		{SNOR_PINDEX_1_1_4, 7}, /* 0x34 */
+		{SNOR_PINDEX_1_4_4, 8}, /* 0x3e */
+	};
+	static const struct sfdp_4bait erases[SNOR_MAX_ERASE_TYPES] = {
+		{SNOR_PINDEX_1_1_1,  9},
+		{SNOR_PINDEX_1_1_1, 10},
+		{SNOR_PINDEX_1_1_1, 11},
+		{SNOR_PINDEX_1_1_1, 12},
+	};
+	u32 word[2], addr, rd_modes, wr_modes, erase_modes;
+	int i, err;
+
+	if (param_header->major != SFDP_JESD216_MAJOR ||
+	    param_header->length < 2)
+		return -EINVAL;
+
+	/* Read the 4-byte Address Instruction Table. */
+	addr = SFDP_PARAM_HEADER_PTP(param_header);
+	err = spi_nor_read_sfdp(nor, addr, sizeof(word), word);
+	if (err)
+		return err;
+
+	for (i = 0; i < 2; ++i)
+		word[i] = le32_to_cpu(word[i]);
+
+	/*
+	 * Compute the subset of (Fast) Read commands for which the 4-byte
+	 * version is supported.
+	 */
+	rd_modes = 0;
+	for (i = 0; i < ARRAY_SIZE(reads); ++i) {
+		const struct sfdp_4bait *read = &reads[i];
+
+		if ((params->rd_modes & BIT(read->pindex)) &&
+		    (word[0] & BIT(read->wbit)))
+			rd_modes |= BIT(read->pindex);
+	}
+
+	/*
+	 * Compute the subset of Page Program commands for which the 4-byte
+	 * version is supported.
+	 */
+	wr_modes = 0;
+	for (i = 0; i < ARRAY_SIZE(programs); ++i) {
+		const struct sfdp_4bait *program = &programs[i];
+
+		if ((params->wr_modes & BIT(program->pindex)) &&
+		    (word[0] & BIT(program->wbit)))
+			wr_modes |= BIT(program->pindex);
+	}
+
+	/*
+	 * Compute the subet of Sector Erase commands for which the 4-byte
+	 * version is supported.
+	 */
+	erase_modes = 0;
+	for (i = 0; i < SNOR_MAX_ERASE_TYPES; ++i) {
+		const struct sfdp_4bait *erase = &erases[i];
+
+		if ((params->erase_types[i].size > 0) &&
+		    (word[0] & BIT(erase->wbit)))
+			erase_modes |= BIT(i);
+	}
+
+	/*
+	 * We need at least one 4-byte op code per read, program and erase
+	 * operation; the .read(), .write() and .erase() hooks share the
+	 * nor->addr_width value.
+	 */
+	if (!rd_modes || !wr_modes || !erase_modes)
+		return 0;
+
+	/*
+	 * Discard all operations from the 4-byte instruction set which are
+	 * not supported by this memory.
+	 */
+	params->rd_modes = rd_modes;
+	params->wr_modes = wr_modes;
+	for (i = 0; i < SNOR_MAX_ERASE_TYPES; ++i)
+		if (!(erase_modes & BIT(i)))
+			params->erase_types[i].size = 0;
+
+	/* Use the 4-byte address instruction set. */
+	params->reads[SNOR_PINDEX_SLOW].opcode  = SPINOR_OP_READ_4B;
+	params->reads[SNOR_PINDEX_1_1_1].opcode = SPINOR_OP_READ_FAST_4B;
+	params->reads[SNOR_PINDEX_1_1_2].opcode = SPINOR_OP_READ_1_1_2_4B;
+	params->reads[SNOR_PINDEX_1_2_2].opcode = SPINOR_OP_READ_1_2_2_4B;
+	params->reads[SNOR_PINDEX_1_1_4].opcode = SPINOR_OP_READ_1_1_4_4B;
+	params->reads[SNOR_PINDEX_1_4_4].opcode = SPINOR_OP_READ_1_4_4_4B;
+	params->page_programs[SNOR_PINDEX_1_1_1] = SPINOR_OP_PP_4B;
+	params->page_programs[SNOR_PINDEX_1_1_4] = SPINOR_OP_PP_1_1_4_4B;
+	params->page_programs[SNOR_PINDEX_1_4_4] = SPINOR_OP_PP_1_4_4_4B;
+	for (i = 0; i < SNOR_MAX_ERASE_TYPES; ++i)
+		params->erase_types[i].opcode = (word[1] >> (i * 8)) & 0xff;
+
+	nor->addr_width = 4;
+	return 0;
+}
+
 static int spi_nor_parse_sfdp(struct spi_nor *nor,
 			      struct spi_nor_basic_flash_parameter *params)
 {
@@ -1795,6 +1914,23 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor,
 	if (err)
 		goto exit;
 
+	/* Parse other parameter headers. */
+	for (i = 0; i < header.nph; ++i) {
+		param_header = &param_headers[i];
+
+		switch (SFDP_PARAM_HEADER_ID(param_header)) {
+		case SFDP_4BAIT_ID:
+			err = spi_nor_parse_4bait(nor, param_header, params);
+			break;
+
+		default:
+			break;
+		}
+
+		if (err)
+			goto exit;
+	}
+
 exit:
 	kfree(param_headers);
 	return (err) ? err : bfpt_header->minor;
@@ -2149,7 +2285,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
 	if (ret)
 		return ret;
 
-	if (info->addr_width)
+	if (nor->addr_width)
+		; /* already configured by spi_nor_setup(). */
+	else if (info->addr_width)
 		nor->addr_width = info->addr_width;
 	else if (mtd->size > 0x1000000) {
 		/* enable 4-byte addressing if the device exceeds 16MiB */
-- 
2.7.4



From cyrille.pitchen at atmel.com  Wed Oct  5 05:00:39 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Wed, 5 Oct 2016 14:00:39 +0200
Subject: [PATCH v2 8/9] mtd: spi-nor: add support to Macronix mx66l1g45g
In-Reply-To: <cover.1475668319.git.cyrille.pitchen@atmel.com>
References: <cover.1475668319.git.cyrille.pitchen@atmel.com>
Message-ID: <b8fa2ecb29277206d86b0e78962a7a186d7724d0.1475668319.git.cyrille.pitchen@atmel.com>

This patch adds an entry in the spi_nor_ids[] table to add support
to the Macronix mx66l1g45g.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 879b98ef1d80..031c6792a3fe 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -937,6 +937,7 @@ static const struct flash_info spi_nor_ids[] = {
 	{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
 	{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
 	{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) },
+	{ "mx66l1g45g",  INFO(0xc2201b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
 	{ "mx66l1g55g",  INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
 
 	/* Micron */
-- 
2.7.4



From cyrille.pitchen at atmel.com  Wed Oct  5 05:00:40 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Wed, 5 Oct 2016 14:00:40 +0200
Subject: [PATCH v2 9/9] mtd: spi-nor: add support to SST sst26* QSPI memories
In-Reply-To: <cover.1475668319.git.cyrille.pitchen@atmel.com>
References: <cover.1475668319.git.cyrille.pitchen@atmel.com>
Message-ID: <9c6e5ae4ce3089089ddf18f96731c92bfea1635b.1475668319.git.cyrille.pitchen@atmel.com>

This patch adds support to the SST sst26* QSPI memories.
It also adds a new SST_BLOCK_PROTECT flag so spi_nor_scan() sends
a SST Global Block Protection Unlock (98h) command once for all
otherwise later Sector Erase and Page Program commands would fail.

It was tested with sst26vf016b, sst26vf032b, sst26vf032ba and sst26vf064b
on a sama5d2 xplained board at 55.3MHz and 3.3V.

sst26wf040b and sst26wf080b were not tested since they are 1.8V memories
hence don't fit the sama5d2 xplained board requirements.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 20 ++++++++++++++++++++
 include/linux/mtd/spi-nor.h   |  1 +
 2 files changed, 21 insertions(+)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 031c6792a3fe..355824bd3587 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -81,6 +81,7 @@ struct flash_info {
 					 * to support memory size above 128Mib.
 					 */
 #define SPI_NOR_SKIP_SFDP	BIT(11) /* Skip read of SFDP tables */
+#define SST_BLOCK_PROTECT	BIT(12)	/* use SST Unlock Block-Protection */
 };
 
 #define JEDEC_MFR(info)	((info)->id[0])
@@ -999,6 +1000,11 @@ static const struct flash_info 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 | SST_BLOCK_PROTECT) },
+	{ "sst26vf032b", INFO(0xbf2642, 0, 64 * 1024, 64, SECT_4K | SST_BLOCK_PROTECT) },
+	{ "sst26vf064b", INFO(0xbf2643, 0, 64 * 1024, 128, SECT_4K | SST_BLOCK_PROTECT) },
+	{ "sst26wf040b", INFO(0xbf2654, 0, 64 * 1024,  8, SECT_4K | SST_BLOCK_PROTECT) },
+	{ "sst26wf080b", INFO(0xbf2658, 0, 64 * 1024, 16, SECT_4K | SST_BLOCK_PROTECT) },
 
 	/* ST Microelectronics -- newer production may have feature updates */
 	{ "m25p05",  INFO(0x202010,  0,  32 * 1024,   2, 0) },
@@ -1135,6 +1141,14 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
 	return ret;
 }
 
+static int sst_unlock_block_protection(struct spi_nor *nor)
+{
+	int ret;
+
+	ret = write_enable(nor);
+	return ret ? ret : nor->write_reg(nor, SPINOR_OP_ULBPR, NULL, 0);
+}
+
 static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
 		size_t *retlen, const u_char *buf)
 {
@@ -2308,6 +2322,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
 		return -EINVAL;
 	}
 
+	if (info->flags & SST_BLOCK_PROTECT) {
+		ret = sst_unlock_block_protection(nor);
+		if (ret)
+			return ret;
+	}
+
 	dev_info(dev, "%s (%lld Kbytes)\n", info->name,
 			(long long)mtd->size >> 10);
 
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index ede7ad83c9c5..016b6c51e854 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -80,6 +80,7 @@
 #define SPINOR_OP_BP		0x02	/* Byte program */
 #define SPINOR_OP_WRDI		0x04	/* Write disable */
 #define SPINOR_OP_AAI_WP	0xad	/* Auto address increment word program */
+#define SPINOR_OP_ULBPR		0x98	/* Global Block Protection Unlock */
 
 /* Used for Macronix and Winbond flashes. */
 #define SPINOR_OP_EN4B		0xb7	/* Enter 4-byte mode */
-- 
2.7.4



From vigneshr at ti.com  Wed Oct  5 05:12:50 2016
From: vigneshr at ti.com (Vignesh R)
Date: Wed, 5 Oct 2016 17:42:50 +0530
Subject: [PATCH 2/9] mtd: spi-nor: add an alternative method to support
 memory >16MiB
In-Reply-To: <75db6c008249df8d0646ea5006648e57fea40706.1475597385.git.cyrille.pitchen@atmel.com>
References: <cover.1475597385.git.cyrille.pitchen@atmel.com>
 <75db6c008249df8d0646ea5006648e57fea40706.1475597385.git.cyrille.pitchen@atmel.com>
Message-ID: <d35f2b66-1915-8111-9187-cdc49417f787@ti.com>

Hi,


On Tuesday 04 October 2016 10:07 PM, Cyrille Pitchen wrote:
[...]
>  static struct seq_rw_config stfsm_s25fl_write4_configs[] = {
> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
> index 5c87b2d99507..423448c1c7a8 100644
> --- a/drivers/mtd/spi-nor/spi-nor.c
> +++ b/drivers/mtd/spi-nor/spi-nor.c
> @@ -75,6 +75,10 @@ struct flash_info {
>  					 * bit. Must be used with
>  					 * SPI_NOR_HAS_LOCK.
>  					 */
> +#define SPI_NOR_4B_OPCODES	BIT(10)	/*
> +					 * Use dedicated 4byte address op codes
> +					 * to support memory size above 128Mib.
> +					 */


I don't see this flag being added to any flash_info data for any m25p80
compatible flashes? Is that part of a separate series?

-- 
Regards
Vignesh


From cyrille.pitchen at atmel.com  Wed Oct  5 05:53:07 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Wed, 5 Oct 2016 14:53:07 +0200
Subject: [PATCH 2/9] mtd: spi-nor: add an alternative method to support
 memory >16MiB
In-Reply-To: <d35f2b66-1915-8111-9187-cdc49417f787@ti.com>
References: <cover.1475597385.git.cyrille.pitchen@atmel.com>
 <75db6c008249df8d0646ea5006648e57fea40706.1475597385.git.cyrille.pitchen@atmel.com>
 <d35f2b66-1915-8111-9187-cdc49417f787@ti.com>
Message-ID: <aabd37f7-b173-650c-aac4-4bc8fa7a0daa@atmel.com>

Hi Vignesh,

Le 05/10/2016 ? 14:12, Vignesh R a ?crit :
> Hi,
> 
> 
> On Tuesday 04 October 2016 10:07 PM, Cyrille Pitchen wrote:
> [...]
>>  static struct seq_rw_config stfsm_s25fl_write4_configs[] = {
>> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
>> index 5c87b2d99507..423448c1c7a8 100644
>> --- a/drivers/mtd/spi-nor/spi-nor.c
>> +++ b/drivers/mtd/spi-nor/spi-nor.c
>> @@ -75,6 +75,10 @@ struct flash_info {
>>  					 * bit. Must be used with
>>  					 * SPI_NOR_HAS_LOCK.
>>  					 */
>> +#define SPI_NOR_4B_OPCODES	BIT(10)	/*
>> +					 * Use dedicated 4byte address op codes
>> +					 * to support memory size above 128Mib.
>> +					 */
> 
> 
> I don't see this flag being added to any flash_info data for any m25p80
> compatible flashes? Is that part of a separate series?
> 

Indeed, this flag is not used yet by any entry in the spi_nor_ids[] array.
At first, I tested this patch with a Macronix mx25l25673g memory.
This memory shares the very same JEDEC ID as the older mx25l25635e, so
I added the SPI_NOR_4B_OPCODES flag in the mx25l25635e entry during my test.
However I didn't commit this change since the actual mx25l25635e memory
doesn't support The 4-byte address instruction test.

Also the mx25l25673g provides the optional 4-byte Address Instruction Table,
as described in the JESD216 rev B specification, so patches 6 and 7 allow
to use the 4-byte address op codes without setting the SPI_NOR_4B_OPCODES flag.

Hence the SPI_NOR_4B_OPCODES, will be useful for memories which don't
provide the JESD216B 4-byte Address Instruction Table but still support
the associated op code. It will have to be tested for each individual entry
in the spi_nor_ids[] array, which can be done later.

Anyway, the 4-byte address op codes introduced by this patch are also used
by patch 7 (parse SFDP 4-byte Address Instruction Table).

Best regards,

Cyrille


From daniel at ffwll.ch  Wed Oct  5 06:15:46 2016
From: daniel at ffwll.ch (Daniel Vetter)
Date: Wed, 5 Oct 2016 15:15:46 +0200
Subject: [PATCH 00/15] improve function-level documentation
In-Reply-To: <1475351192-27079-1-git-send-email-Julia.Lawall@lip6.fr>
References: <1475351192-27079-1-git-send-email-Julia.Lawall@lip6.fr>
Message-ID: <CAKMK7uHT3FutHQuQQ3iwXmYbidB3AOs7AxnpaJD4MTqy0-QehQ@mail.gmail.com>

Jani Nikula has a patch with a scrip to make the one kernel-doc parser
into a lint/checker pass over the entire kernel. I think that'd would
be more robust instead of trying to approximate the real kerneldoc
parser. Otoh that parser is a horror show of a perl/regex driven state
machine ;-)

Jani, can you pls digg out these patches? Can't find them right now ...
-Daniel


On Sat, Oct 1, 2016 at 9:46 PM, Julia Lawall <Julia.Lawall at lip6.fr> wrote:
> These patches fix cases where the documentation above a function definition
> is not consistent with the function header.  Issues are detected using the
> semantic patch below (http://coccinelle.lip6.fr/).  Basically, the semantic
> patch parses a file to find comments, then matches each function header,
> and checks that the name and parameter list in the function header are
> compatible with the comment that preceeds it most closely.
>
> // <smpl>
> @initialize:ocaml@
> @@
>
> let tbl = ref []
> let fnstart = ref []
> let success = Hashtbl.create 101
> let thefile = ref ""
> let parsed = ref []
> let nea = ref []
>
> let parse file =
>   thefile := List.nth (Str.split (Str.regexp "linux-next/") file) 1;
>   let i = open_in file in
>   let startline = ref 0 in
>   let fn = ref "" in
>   let ids = ref [] in
>   let rec inside n =
>     let l = input_line i in
>     let n = n + 1 in
>     match Str.split_delim (Str.regexp_string "*/") l with
>       before::after::_ ->
>         (if not (!fn = "")
>         then tbl := (!startline,n,!fn,List.rev !ids)::!tbl);
>         startline := 0;
>         fn := "";
>         ids := [];
>         outside n
>     | _ ->
>         (match Str.split (Str.regexp "[ \t]+") l with
>           "*"::name::rest ->
>             let len = String.length name in
>             (if !fn = "" && len > 2 && String.sub name (len-2) 2 = "()"
>             then fn := String.sub name 0 (len-2)
>             else if !fn = "" && (not (rest = [])) && List.hd rest = "-"
>             then
>               if String.get name (len-1) = ':'
>               then fn := String.sub name 0 (len-1)
>               else fn := name
>             else if not(!fn = "") && len > 2 &&
>               String.get name 0 = '@' && String.get name (len-1) = ':'
>             then ids := (String.sub name 1 (len-2)) :: !ids);
>         | _ -> ());
>         inside n
>   and outside n =
>     let l = input_line i in
>     let n = n + 1 in
>     if String.length l > 2 && String.sub l 0 3 = "/**"
>     then
>       begin
>         startline := n;
>         inside n
>       end
>     else outside n in
>   try outside 0 with End_of_file -> ()
>
> let hashadd tbl k v =
>   let cell =
>     try Hashtbl.find tbl k
>     with Not_found ->
>       let cell = ref [] in
>       Hashtbl.add tbl k cell;
>       cell in
>   cell := v :: !cell
>
> @script:ocaml@
> @@
>
> tbl := [];
> fnstart := [];
> Hashtbl.clear success;
> parsed := [];
> nea := [];
> parse (List.hd (Coccilib.files()))
>
> @r@
> identifier f;
> position p;
> @@
>
> f at p(...) { ... }
>
> @script:ocaml@
> p << r.p;
> f << r.f;
> @@
>
> parsed := f :: !parsed;
> fnstart := (List.hd p).line :: !fnstart
>
> @param@
> identifier f;
> type T;
> identifier i;
> parameter list[n] ps;
> parameter list[n1] ps1;
> position p;
> @@
>
> f at p(ps,T i,ps1) { ... }
>
> @script:ocaml@
> @@
>
> tbl := List.rev (List.sort compare !tbl)
>
> @script:ocaml@
> p << param.p;
> f << param.f;
> @@
>
> let myline = (List.hd p).line in
> let prevline =
>   List.fold_left
>     (fun prev x ->
>       if x < myline
>       then max x prev
>       else prev)
>     0 !fnstart in
> let _ =
>   List.exists
>     (function (st,fn,nm,ids) ->
>       if prevline < st && myline > st && prevline < fn && myline > fn
>       then
>         begin
>           (if not (String.lowercase f = String.lowercase nm)
>           then
>             Printf.printf "%s:%d %s doesn't match preceding comment: %s\n"
>               !thefile myline f nm);
>           true
>         end
>       else false)
>     !tbl in
> ()
>
> @script:ocaml@
> p << param.p;
> n << param.n;
> n1 << param.n1;
> i << param.i;
> f << param.f;
> @@
>
> let myline = (List.hd p).line in
> let prevline =
>   List.fold_left
>     (fun prev x ->
>       if x < myline
>       then max x prev
>       else prev)
>     0 !fnstart in
> let _ =
>   List.exists
>     (function (st,fn,nm,ids) ->
>       if prevline < st && myline > st && prevline < fn && myline > fn
>       then
>         begin
>           (if List.mem i ids then hashadd success (st,fn,nm) i);
>           (if ids = [] (* arg list seems not obligatory *)
>           then ()
>           else if not (List.mem i ids)
>           then
>             Printf.printf "%s:%d %s doesn't appear in ids: %s\n"
>               !thefile myline i (String.concat " " ids)
>           else if List.length ids <= n || List.length ids <= n1
>           then
>             (if not (List.mem f !nea)
>             then
>               begin
>                 nea := f :: !nea;
>                 Printf.printf "%s:%d %s not enough args\n" !thefile myline f;
>               end)
>           else
>             let foundid = List.nth ids n in
>             let efoundid = List.nth (List.rev ids) n1 in
>             if not(foundid = i || efoundid = i)
>             then
>               Printf.printf "%s:%d %s wrong arg in position %d: %s\n"
>                 !thefile myline i n foundid);
>           true
>         end
>       else false)
>     !tbl in
> ()
>
> @script:ocaml@
> @@
> List.iter
>   (function (st,fn,nm,ids) ->
>     if List.mem nm !parsed
>     then
>       let entry =
>         try !(Hashtbl.find success (st,fn,nm))
>         with Not_found -> [] in
>       List.iter
>         (fun id ->
>           if not (List.mem id entry) && not (id = "...")
>           then Printf.printf "%s:%d %s not used\n" !thefile st id)
>         ids)
>   !tbl
> // </smpl>
>
>
> ---
>
>  drivers/clk/keystone/pll.c               |    4 ++--
>  drivers/clk/sunxi/clk-mod0.c             |    2 +-
>  drivers/clk/tegra/cvb.c                  |   10 +++++-----
>  drivers/dma-buf/sw_sync.c                |    6 +++---
>  drivers/gpu/drm/gma500/intel_i2c.c       |    3 +--
>  drivers/gpu/drm/omapdrm/omap_drv.c       |    4 ++--
>  drivers/irqchip/irq-metag-ext.c          |    1 -
>  drivers/irqchip/irq-vic.c                |    1 -
>  drivers/mfd/tc3589x.c                    |    4 ++--
>  drivers/power/supply/ab8500_fg.c         |    8 ++++----
>  drivers/power/supply/abx500_chargalg.c   |    1 +
>  drivers/power/supply/intel_mid_battery.c |    2 +-
>  drivers/power/supply/power_supply_core.c |    4 ++--
>  fs/crypto/crypto.c                       |    4 ++--
>  fs/crypto/fname.c                        |    4 ++--
>  fs/ubifs/file.c                          |    2 +-
>  fs/ubifs/gc.c                            |    2 +-
>  fs/ubifs/lprops.c                        |    2 +-
>  fs/ubifs/lpt_commit.c                    |    4 +---
>  fs/ubifs/replay.c                        |    2 +-
>  lib/kobject_uevent.c                     |    6 +++---
>  lib/lru_cache.c                          |    4 ++--
>  lib/nlattr.c                             |    2 +-
>  23 files changed, 39 insertions(+), 43 deletions(-)
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel



-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch


From jani.nikula at linux.intel.com  Wed Oct  5 07:04:43 2016
From: jani.nikula at linux.intel.com (Jani Nikula)
Date: Wed, 05 Oct 2016 17:04:43 +0300
Subject: kernel-doc-rst-lint (was: Re: [PATCH 00/15] improve function-level
 documentation)
In-Reply-To: <CAKMK7uHT3FutHQuQQ3iwXmYbidB3AOs7AxnpaJD4MTqy0-QehQ@mail.gmail.com>
References: <1475351192-27079-1-git-send-email-Julia.Lawall@lip6.fr>
 <CAKMK7uHT3FutHQuQQ3iwXmYbidB3AOs7AxnpaJD4MTqy0-QehQ@mail.gmail.com>
Message-ID: <87h98quc1w.fsf@intel.com>

On Wed, 05 Oct 2016, Daniel Vetter <daniel at ffwll.ch> wrote:
> Jani Nikula has a patch with a scrip to make the one kernel-doc parser
> into a lint/checker pass over the entire kernel. I think that'd would
> be more robust instead of trying to approximate the real kerneldoc
> parser. Otoh that parser is a horror show of a perl/regex driven state
> machine ;-)
>
> Jani, can you pls digg out these patches? Can't find them right now ...

Expanding the massive Cc: with linux-doc list...

Here goes. It's a quick hack from months ago, but still seems to
somewhat work. At least for the kernel-doc parts. The reStructuredText
lint part isn't all that great, and doesn't have mapping to line numbers
like the Sphinx kernel-doc extension does. Anyway I'm happy how this
integrates with kernel build CHECK and C=1/C=2.

I guess Julia's goal is to automate the *fixing* of some of the error
classes from kernel-doc. Not sure how well this could be made to
integrate with any of that.

BR,
Jani.


>From 1244efa0f63a7b13795e8c37f81733a3c8bfc56a Mon Sep 17 00:00:00 2001
From: Jani Nikula <jani.nikula at intel.com>
Date: Tue, 31 May 2016 18:11:33 +0300
Subject: [PATCH] kernel-doc-rst-lint: add tool to check kernel-doc and rst
 correctness
Organization: Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo
Cc: Jani Nikula <jani.nikula at intel.com>

Simple kernel-doc and reStructuredText lint tool that can be used
independently and as a kernel build CHECK tool to validate kernel-doc
comments.

Independent usage:
$ kernel-doc-rst-lint FILE

Kernel CHECK usage:
$ make CHECK=scripts/kernel-doc-rst-lint C=1		# (or C=2)

Depends on docutils and the rst-lint package
https://pypi.python.org/pypi/restructuredtext_lint

Signed-off-by: Jani Nikula <jani.nikula at intel.com>
---
 scripts/kernel-doc-rst-lint | 106 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 106 insertions(+)
 create mode 100755 scripts/kernel-doc-rst-lint

diff --git a/scripts/kernel-doc-rst-lint b/scripts/kernel-doc-rst-lint
new file mode 100755
index 000000000000..7e0157679f83
--- /dev/null
+++ b/scripts/kernel-doc-rst-lint
@@ -0,0 +1,106 @@
+#!/usr/bin/env python
+# coding=utf-8
+#
+# Copyright ? 2016 Intel Corporation
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# Authors:
+#    Jani Nikula <jani.nikula at intel.com>
+#
+# Simple kernel-doc and reStructuredText lint tool that can be used
+# independently and as a kernel build CHECK tool to validate kernel-doc
+# comments.
+#
+# Independent usage:
+# $ kernel-doc-rst-lint FILE
+#
+# Kernel CHECK usage:
+# $ make CHECK=scripts/kernel-doc-rst-lint C=1		# (or C=2)
+#
+# Depends on docutils and the rst-lint package
+# https://pypi.python.org/pypi/restructuredtext_lint
+#
+
+import os
+import subprocess
+import sys
+
+from docutils.parsers.rst import directives
+from docutils.parsers.rst import Directive
+from docutils.parsers.rst import roles
+from docutils import nodes, statemachine
+import restructuredtext_lint
+
+class DummyDirective(Directive):
+    required_argument = 1
+    optional_arguments = 0
+    option_spec = { }
+    has_content = True
+
+    def run(self):
+        return []
+
+# Fake the Sphinx C Domain directives and roles
+directives.register_directive('c:function', DummyDirective)
+directives.register_directive('c:type', DummyDirective)
+roles.register_generic_role('c:func', nodes.emphasis)
+roles.register_generic_role('c:type', nodes.emphasis)
+
+# We accept but ignore parameters to be compatible with how the kernel build
+# invokes CHECK.
+if len(sys.argv) < 2:
+    sys.stderr.write('usage: kernel-doc-rst-lint [IGNORED OPTIONS] FILE\n');
+    sys.exit(1)
+
+infile = sys.argv[len(sys.argv) - 1]
+cmd = ['scripts/kernel-doc', '-rst', infile]
+
+try:
+    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
+    out, err = p.communicate()
+
+    # python2 needs conversion to unicode.
+    # python3 with universal_newlines=True returns strings.
+    if sys.version_info.major < 3:
+        out, err = unicode(out, 'utf-8'), unicode(err, 'utf-8')
+
+    # kernel-doc errors
+    sys.stderr.write(err)
+    if p.returncode != 0:
+        sys.exit(p.returncode)
+
+    # restructured text errors
+    lines = statemachine.string2lines(out, 8, convert_whitespace=True)
+    lint_errors = restructuredtext_lint.lint(out, infile)
+    for error in lint_errors:
+        # Ignore INFO
+        if error.level <= 1:
+            continue
+
+        print(error.source + ': ' + error.type + ': ' + error.full_message)
+        if error.line is not None:
+            print('Context:')
+            print('\t' + lines[error.line - 1])
+            print('\t' + lines[error.line])
+
+except Exception as e:
+    sys.stderr.write(str(e) + '\n')
+    sys.exit(1)
-- 
2.1.4


-- 
Jani Nikula, Intel Open Source Technology Center


From julia.lawall at lip6.fr  Wed Oct  5 07:47:00 2016
From: julia.lawall at lip6.fr (Julia Lawall)
Date: Wed, 5 Oct 2016 16:47:00 +0200 (CEST)
Subject: [PATCH 00/15] improve function-level documentation
In-Reply-To: <CAKMK7uHT3FutHQuQQ3iwXmYbidB3AOs7AxnpaJD4MTqy0-QehQ@mail.gmail.com>
References: <1475351192-27079-1-git-send-email-Julia.Lawall@lip6.fr>
 <CAKMK7uHT3FutHQuQQ3iwXmYbidB3AOs7AxnpaJD4MTqy0-QehQ@mail.gmail.com>
Message-ID: <alpine.DEB.2.10.1610051645310.3568@hadrien>



On Wed, 5 Oct 2016, Daniel Vetter wrote:

> Jani Nikula has a patch with a scrip to make the one kernel-doc parser
> into a lint/checker pass over the entire kernel. I think that'd would
> be more robust instead of trying to approximate the real kerneldoc
> parser. Otoh that parser is a horror show of a perl/regex driven state
> machine ;-)

Sure.  To my recollection, I found around 2000 issues.  Many I ignored, eg
functions that simply have no documentation abuot the parameters,
functions that document their local variables, when these were more
interesting than the parameters etc.  But the set of patches is not
exhaustive with respect to the remaining interesting ones either.

julia

>
> Jani, can you pls digg out these patches? Can't find them right now ...
> -Daniel
>
>
> On Sat, Oct 1, 2016 at 9:46 PM, Julia Lawall <Julia.Lawall at lip6.fr> wrote:
> > These patches fix cases where the documentation above a function definition
> > is not consistent with the function header.  Issues are detected using the
> > semantic patch below (http://coccinelle.lip6.fr/).  Basically, the semantic
> > patch parses a file to find comments, then matches each function header,
> > and checks that the name and parameter list in the function header are
> > compatible with the comment that preceeds it most closely.
> >
> > // <smpl>
> > @initialize:ocaml@
> > @@
> >
> > let tbl = ref []
> > let fnstart = ref []
> > let success = Hashtbl.create 101
> > let thefile = ref ""
> > let parsed = ref []
> > let nea = ref []
> >
> > let parse file =
> >   thefile := List.nth (Str.split (Str.regexp "linux-next/") file) 1;
> >   let i = open_in file in
> >   let startline = ref 0 in
> >   let fn = ref "" in
> >   let ids = ref [] in
> >   let rec inside n =
> >     let l = input_line i in
> >     let n = n + 1 in
> >     match Str.split_delim (Str.regexp_string "*/") l with
> >       before::after::_ ->
> >         (if not (!fn = "")
> >         then tbl := (!startline,n,!fn,List.rev !ids)::!tbl);
> >         startline := 0;
> >         fn := "";
> >         ids := [];
> >         outside n
> >     | _ ->
> >         (match Str.split (Str.regexp "[ \t]+") l with
> >           "*"::name::rest ->
> >             let len = String.length name in
> >             (if !fn = "" && len > 2 && String.sub name (len-2) 2 = "()"
> >             then fn := String.sub name 0 (len-2)
> >             else if !fn = "" && (not (rest = [])) && List.hd rest = "-"
> >             then
> >               if String.get name (len-1) = ':'
> >               then fn := String.sub name 0 (len-1)
> >               else fn := name
> >             else if not(!fn = "") && len > 2 &&
> >               String.get name 0 = '@' && String.get name (len-1) = ':'
> >             then ids := (String.sub name 1 (len-2)) :: !ids);
> >         | _ -> ());
> >         inside n
> >   and outside n =
> >     let l = input_line i in
> >     let n = n + 1 in
> >     if String.length l > 2 && String.sub l 0 3 = "/**"
> >     then
> >       begin
> >         startline := n;
> >         inside n
> >       end
> >     else outside n in
> >   try outside 0 with End_of_file -> ()
> >
> > let hashadd tbl k v =
> >   let cell =
> >     try Hashtbl.find tbl k
> >     with Not_found ->
> >       let cell = ref [] in
> >       Hashtbl.add tbl k cell;
> >       cell in
> >   cell := v :: !cell
> >
> > @script:ocaml@
> > @@
> >
> > tbl := [];
> > fnstart := [];
> > Hashtbl.clear success;
> > parsed := [];
> > nea := [];
> > parse (List.hd (Coccilib.files()))
> >
> > @r@
> > identifier f;
> > position p;
> > @@
> >
> > f at p(...) { ... }
> >
> > @script:ocaml@
> > p << r.p;
> > f << r.f;
> > @@
> >
> > parsed := f :: !parsed;
> > fnstart := (List.hd p).line :: !fnstart
> >
> > @param@
> > identifier f;
> > type T;
> > identifier i;
> > parameter list[n] ps;
> > parameter list[n1] ps1;
> > position p;
> > @@
> >
> > f at p(ps,T i,ps1) { ... }
> >
> > @script:ocaml@
> > @@
> >
> > tbl := List.rev (List.sort compare !tbl)
> >
> > @script:ocaml@
> > p << param.p;
> > f << param.f;
> > @@
> >
> > let myline = (List.hd p).line in
> > let prevline =
> >   List.fold_left
> >     (fun prev x ->
> >       if x < myline
> >       then max x prev
> >       else prev)
> >     0 !fnstart in
> > let _ =
> >   List.exists
> >     (function (st,fn,nm,ids) ->
> >       if prevline < st && myline > st && prevline < fn && myline > fn
> >       then
> >         begin
> >           (if not (String.lowercase f = String.lowercase nm)
> >           then
> >             Printf.printf "%s:%d %s doesn't match preceding comment: %s\n"
> >               !thefile myline f nm);
> >           true
> >         end
> >       else false)
> >     !tbl in
> > ()
> >
> > @script:ocaml@
> > p << param.p;
> > n << param.n;
> > n1 << param.n1;
> > i << param.i;
> > f << param.f;
> > @@
> >
> > let myline = (List.hd p).line in
> > let prevline =
> >   List.fold_left
> >     (fun prev x ->
> >       if x < myline
> >       then max x prev
> >       else prev)
> >     0 !fnstart in
> > let _ =
> >   List.exists
> >     (function (st,fn,nm,ids) ->
> >       if prevline < st && myline > st && prevline < fn && myline > fn
> >       then
> >         begin
> >           (if List.mem i ids then hashadd success (st,fn,nm) i);
> >           (if ids = [] (* arg list seems not obligatory *)
> >           then ()
> >           else if not (List.mem i ids)
> >           then
> >             Printf.printf "%s:%d %s doesn't appear in ids: %s\n"
> >               !thefile myline i (String.concat " " ids)
> >           else if List.length ids <= n || List.length ids <= n1
> >           then
> >             (if not (List.mem f !nea)
> >             then
> >               begin
> >                 nea := f :: !nea;
> >                 Printf.printf "%s:%d %s not enough args\n" !thefile myline f;
> >               end)
> >           else
> >             let foundid = List.nth ids n in
> >             let efoundid = List.nth (List.rev ids) n1 in
> >             if not(foundid = i || efoundid = i)
> >             then
> >               Printf.printf "%s:%d %s wrong arg in position %d: %s\n"
> >                 !thefile myline i n foundid);
> >           true
> >         end
> >       else false)
> >     !tbl in
> > ()
> >
> > @script:ocaml@
> > @@
> > List.iter
> >   (function (st,fn,nm,ids) ->
> >     if List.mem nm !parsed
> >     then
> >       let entry =
> >         try !(Hashtbl.find success (st,fn,nm))
> >         with Not_found -> [] in
> >       List.iter
> >         (fun id ->
> >           if not (List.mem id entry) && not (id = "...")
> >           then Printf.printf "%s:%d %s not used\n" !thefile st id)
> >         ids)
> >   !tbl
> > // </smpl>
> >
> >
> > ---
> >
> >  drivers/clk/keystone/pll.c               |    4 ++--
> >  drivers/clk/sunxi/clk-mod0.c             |    2 +-
> >  drivers/clk/tegra/cvb.c                  |   10 +++++-----
> >  drivers/dma-buf/sw_sync.c                |    6 +++---
> >  drivers/gpu/drm/gma500/intel_i2c.c       |    3 +--
> >  drivers/gpu/drm/omapdrm/omap_drv.c       |    4 ++--
> >  drivers/irqchip/irq-metag-ext.c          |    1 -
> >  drivers/irqchip/irq-vic.c                |    1 -
> >  drivers/mfd/tc3589x.c                    |    4 ++--
> >  drivers/power/supply/ab8500_fg.c         |    8 ++++----
> >  drivers/power/supply/abx500_chargalg.c   |    1 +
> >  drivers/power/supply/intel_mid_battery.c |    2 +-
> >  drivers/power/supply/power_supply_core.c |    4 ++--
> >  fs/crypto/crypto.c                       |    4 ++--
> >  fs/crypto/fname.c                        |    4 ++--
> >  fs/ubifs/file.c                          |    2 +-
> >  fs/ubifs/gc.c                            |    2 +-
> >  fs/ubifs/lprops.c                        |    2 +-
> >  fs/ubifs/lpt_commit.c                    |    4 +---
> >  fs/ubifs/replay.c                        |    2 +-
> >  lib/kobject_uevent.c                     |    6 +++---
> >  lib/lru_cache.c                          |    4 ++--
> >  lib/nlattr.c                             |    2 +-
> >  23 files changed, 39 insertions(+), 43 deletions(-)
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel at lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/dri-devel
>
>
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch
> --
> To unsubscribe from this list: send the line "unsubscribe kernel-janitors" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>


From markus.heiser at darmarit.de  Wed Oct  5 10:27:12 2016
From: markus.heiser at darmarit.de (Markus Heiser)
Date: Wed, 5 Oct 2016 19:27:12 +0200
Subject: kernel-doc-rst-lint (was: Re: [PATCH 00/15] improve
 function-level documentation)
In-Reply-To: <87h98quc1w.fsf@intel.com>
References: <1475351192-27079-1-git-send-email-Julia.Lawall@lip6.fr>
 <CAKMK7uHT3FutHQuQQ3iwXmYbidB3AOs7AxnpaJD4MTqy0-QehQ@mail.gmail.com>
 <87h98quc1w.fsf@intel.com>
Message-ID: <0311F11C-D5CB-4A90-86BD-4DDAD1103685@darmarit.de>


Am 05.10.2016 um 16:04 schrieb Jani Nikula <jani.nikula at linux.intel.com>:

> On Wed, 05 Oct 2016, Daniel Vetter <daniel at ffwll.ch> wrote:
>> Jani Nikula has a patch with a scrip to make the one kernel-doc parser
>> into a lint/checker pass over the entire kernel. I think that'd would
>> be more robust instead of trying to approximate the real kerneldoc
>> parser. Otoh that parser is a horror show of a perl/regex driven state
>> machine ;-)
>> 
>> Jani, can you pls digg out these patches? Can't find them right now ...
> 
> Expanding the massive Cc: with linux-doc list...
> 
> Here goes. It's a quick hack from months ago, but still seems to
> somewhat work. At least for the kernel-doc parts. The reStructuredText
> lint part isn't all that great, and doesn't have mapping to line numbers
> like the Sphinx kernel-doc extension does. Anyway I'm happy how this
> integrates with kernel build CHECK and C=1/C=2.
> 
> I guess Julia's goal is to automate the *fixing* of some of the error
> classes from kernel-doc. Not sure how well this could be made to
> integrate with any of that.
> 
> BR,
> Jani.

Another lint alternative: 

 use the lint from the linuxdoc project 

install the linuxdoc package:

*  https://return42.github.io/linuxdoc/install.html

e.g.::

 pip install --user git+http://github.com/return42/linuxdoc.git

and run kernel-lintdoc with the file/folder to lint as argument / e.g.::

 kernel-lintdoc include/media/

-- Markus --


> 
> 
> From 1244efa0f63a7b13795e8c37f81733a3c8bfc56a Mon Sep 17 00:00:00 2001
> From: Jani Nikula <jani.nikula at intel.com>
> Date: Tue, 31 May 2016 18:11:33 +0300
> Subject: [PATCH] kernel-doc-rst-lint: add tool to check kernel-doc and rst
> correctness
> Organization: Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo
> Cc: Jani Nikula <jani.nikula at intel.com>
> 
> Simple kernel-doc and reStructuredText lint tool that can be used
> independently and as a kernel build CHECK tool to validate kernel-doc
> comments.
> 
> Independent usage:
> $ kernel-doc-rst-lint FILE
> 
> Kernel CHECK usage:
> $ make CHECK=scripts/kernel-doc-rst-lint C=1		# (or C=2)
> 
> Depends on docutils and the rst-lint package
> https://pypi.python.org/pypi/restructuredtext_lint
> 
> Signed-off-by: Jani Nikula <jani.nikula at intel.com>
> ---
> scripts/kernel-doc-rst-lint | 106 ++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 106 insertions(+)
> create mode 100755 scripts/kernel-doc-rst-lint
> 
> diff --git a/scripts/kernel-doc-rst-lint b/scripts/kernel-doc-rst-lint
> new file mode 100755
> index 000000000000..7e0157679f83
> --- /dev/null
> +++ b/scripts/kernel-doc-rst-lint
> @@ -0,0 +1,106 @@
> +#!/usr/bin/env python
> +# coding=utf-8
> +#
> +# Copyright ? 2016 Intel Corporation
> +#
> +# Permission is hereby granted, free of charge, to any person obtaining a
> +# copy of this software and associated documentation files (the "Software"),
> +# to deal in the Software without restriction, including without limitation
> +# the rights to use, copy, modify, merge, publish, distribute, sublicense,
> +# and/or sell copies of the Software, and to permit persons to whom the
> +# Software is furnished to do so, subject to the following conditions:
> +#
> +# The above copyright notice and this permission notice (including the next
> +# paragraph) shall be included in all copies or substantial portions of the
> +# Software.
> +#
> +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> +# IN THE SOFTWARE.
> +#
> +# Authors:
> +#    Jani Nikula <jani.nikula at intel.com>
> +#
> +# Simple kernel-doc and reStructuredText lint tool that can be used
> +# independently and as a kernel build CHECK tool to validate kernel-doc
> +# comments.
> +#
> +# Independent usage:
> +# $ kernel-doc-rst-lint FILE
> +#
> +# Kernel CHECK usage:
> +# $ make CHECK=scripts/kernel-doc-rst-lint C=1		# (or C=2)
> +#
> +# Depends on docutils and the rst-lint package
> +# https://pypi.python.org/pypi/restructuredtext_lint
> +#
> +
> +import os
> +import subprocess
> +import sys
> +
> +from docutils.parsers.rst import directives
> +from docutils.parsers.rst import Directive
> +from docutils.parsers.rst import roles
> +from docutils import nodes, statemachine
> +import restructuredtext_lint
> +
> +class DummyDirective(Directive):
> +    required_argument = 1
> +    optional_arguments = 0
> +    option_spec = { }
> +    has_content = True
> +
> +    def run(self):
> +        return []
> +
> +# Fake the Sphinx C Domain directives and roles
> +directives.register_directive('c:function', DummyDirective)
> +directives.register_directive('c:type', DummyDirective)
> +roles.register_generic_role('c:func', nodes.emphasis)
> +roles.register_generic_role('c:type', nodes.emphasis)
> +
> +# We accept but ignore parameters to be compatible with how the kernel build
> +# invokes CHECK.
> +if len(sys.argv) < 2:
> +    sys.stderr.write('usage: kernel-doc-rst-lint [IGNORED OPTIONS] FILE\n');
> +    sys.exit(1)
> +
> +infile = sys.argv[len(sys.argv) - 1]
> +cmd = ['scripts/kernel-doc', '-rst', infile]
> +
> +try:
> +    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
> +    out, err = p.communicate()
> +
> +    # python2 needs conversion to unicode.
> +    # python3 with universal_newlines=True returns strings.
> +    if sys.version_info.major < 3:
> +        out, err = unicode(out, 'utf-8'), unicode(err, 'utf-8')
> +
> +    # kernel-doc errors
> +    sys.stderr.write(err)
> +    if p.returncode != 0:
> +        sys.exit(p.returncode)
> +
> +    # restructured text errors
> +    lines = statemachine.string2lines(out, 8, convert_whitespace=True)
> +    lint_errors = restructuredtext_lint.lint(out, infile)
> +    for error in lint_errors:
> +        # Ignore INFO
> +        if error.level <= 1:
> +            continue
> +
> +        print(error.source + ': ' + error.type + ': ' + error.full_message)
> +        if error.line is not None:
> +            print('Context:')
> +            print('\t' + lines[error.line - 1])
> +            print('\t' + lines[error.line])
> +
> +except Exception as e:
> +    sys.stderr.write(str(e) + '\n')
> +    sys.exit(1)
> -- 
> 2.1.4
> 
> 
> -- 
> Jani Nikula, Intel Open Source Technology Center
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



From julia.lawall at lip6.fr  Wed Oct  5 13:25:35 2016
From: julia.lawall at lip6.fr (Julia Lawall)
Date: Wed, 5 Oct 2016 22:25:35 +0200 (CEST)
Subject: kernel-doc-rst-lint (was: Re: [PATCH 00/15] improve function-level
 documentation)
In-Reply-To: <87h98quc1w.fsf@intel.com>
References: <1475351192-27079-1-git-send-email-Julia.Lawall@lip6.fr>
 <CAKMK7uHT3FutHQuQQ3iwXmYbidB3AOs7AxnpaJD4MTqy0-QehQ@mail.gmail.com>
 <87h98quc1w.fsf@intel.com>
Message-ID: <alpine.DEB.2.10.1610052224240.3130@hadrien>



On Wed, 5 Oct 2016, Jani Nikula wrote:

> On Wed, 05 Oct 2016, Daniel Vetter <daniel at ffwll.ch> wrote:
> > Jani Nikula has a patch with a scrip to make the one kernel-doc parser
> > into a lint/checker pass over the entire kernel. I think that'd would
> > be more robust instead of trying to approximate the real kerneldoc
> > parser. Otoh that parser is a horror show of a perl/regex driven state
> > machine ;-)
> >
> > Jani, can you pls digg out these patches? Can't find them right now ...
>
> Expanding the massive Cc: with linux-doc list...
>
> Here goes. It's a quick hack from months ago, but still seems to
> somewhat work. At least for the kernel-doc parts. The reStructuredText
> lint part isn't all that great, and doesn't have mapping to line numbers
> like the Sphinx kernel-doc extension does. Anyway I'm happy how this
> integrates with kernel build CHECK and C=1/C=2.
>
> I guess Julia's goal is to automate the *fixing* of some of the error
> classes from kernel-doc. Not sure how well this could be made to
> integrate with any of that.

No, my work doesn't fix anything.  Coccinelle can't actually process
comments.  I just correlated the parsed comment with the function header.

julia

>
> BR,
> Jani.
>
>
> From 1244efa0f63a7b13795e8c37f81733a3c8bfc56a Mon Sep 17 00:00:00 2001
> From: Jani Nikula <jani.nikula at intel.com>
> Date: Tue, 31 May 2016 18:11:33 +0300
> Subject: [PATCH] kernel-doc-rst-lint: add tool to check kernel-doc and rst
>  correctness
> Organization: Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo
> Cc: Jani Nikula <jani.nikula at intel.com>
>
> Simple kernel-doc and reStructuredText lint tool that can be used
> independently and as a kernel build CHECK tool to validate kernel-doc
> comments.
>
> Independent usage:
> $ kernel-doc-rst-lint FILE
>
> Kernel CHECK usage:
> $ make CHECK=scripts/kernel-doc-rst-lint C=1		# (or C=2)
>
> Depends on docutils and the rst-lint package
> https://pypi.python.org/pypi/restructuredtext_lint
>
> Signed-off-by: Jani Nikula <jani.nikula at intel.com>
> ---
>  scripts/kernel-doc-rst-lint | 106 ++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 106 insertions(+)
>  create mode 100755 scripts/kernel-doc-rst-lint
>
> diff --git a/scripts/kernel-doc-rst-lint b/scripts/kernel-doc-rst-lint
> new file mode 100755
> index 000000000000..7e0157679f83
> --- /dev/null
> +++ b/scripts/kernel-doc-rst-lint
> @@ -0,0 +1,106 @@
> +#!/usr/bin/env python
> +# coding=utf-8
> +#
> +# Copyright ? 2016 Intel Corporation
> +#
> +# Permission is hereby granted, free of charge, to any person obtaining a
> +# copy of this software and associated documentation files (the "Software"),
> +# to deal in the Software without restriction, including without limitation
> +# the rights to use, copy, modify, merge, publish, distribute, sublicense,
> +# and/or sell copies of the Software, and to permit persons to whom the
> +# Software is furnished to do so, subject to the following conditions:
> +#
> +# The above copyright notice and this permission notice (including the next
> +# paragraph) shall be included in all copies or substantial portions of the
> +# Software.
> +#
> +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> +# IN THE SOFTWARE.
> +#
> +# Authors:
> +#    Jani Nikula <jani.nikula at intel.com>
> +#
> +# Simple kernel-doc and reStructuredText lint tool that can be used
> +# independently and as a kernel build CHECK tool to validate kernel-doc
> +# comments.
> +#
> +# Independent usage:
> +# $ kernel-doc-rst-lint FILE
> +#
> +# Kernel CHECK usage:
> +# $ make CHECK=scripts/kernel-doc-rst-lint C=1		# (or C=2)
> +#
> +# Depends on docutils and the rst-lint package
> +# https://pypi.python.org/pypi/restructuredtext_lint
> +#
> +
> +import os
> +import subprocess
> +import sys
> +
> +from docutils.parsers.rst import directives
> +from docutils.parsers.rst import Directive
> +from docutils.parsers.rst import roles
> +from docutils import nodes, statemachine
> +import restructuredtext_lint
> +
> +class DummyDirective(Directive):
> +    required_argument = 1
> +    optional_arguments = 0
> +    option_spec = { }
> +    has_content = True
> +
> +    def run(self):
> +        return []
> +
> +# Fake the Sphinx C Domain directives and roles
> +directives.register_directive('c:function', DummyDirective)
> +directives.register_directive('c:type', DummyDirective)
> +roles.register_generic_role('c:func', nodes.emphasis)
> +roles.register_generic_role('c:type', nodes.emphasis)
> +
> +# We accept but ignore parameters to be compatible with how the kernel build
> +# invokes CHECK.
> +if len(sys.argv) < 2:
> +    sys.stderr.write('usage: kernel-doc-rst-lint [IGNORED OPTIONS] FILE\n');
> +    sys.exit(1)
> +
> +infile = sys.argv[len(sys.argv) - 1]
> +cmd = ['scripts/kernel-doc', '-rst', infile]
> +
> +try:
> +    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
> +    out, err = p.communicate()
> +
> +    # python2 needs conversion to unicode.
> +    # python3 with universal_newlines=True returns strings.
> +    if sys.version_info.major < 3:
> +        out, err = unicode(out, 'utf-8'), unicode(err, 'utf-8')
> +
> +    # kernel-doc errors
> +    sys.stderr.write(err)
> +    if p.returncode != 0:
> +        sys.exit(p.returncode)
> +
> +    # restructured text errors
> +    lines = statemachine.string2lines(out, 8, convert_whitespace=True)
> +    lint_errors = restructuredtext_lint.lint(out, infile)
> +    for error in lint_errors:
> +        # Ignore INFO
> +        if error.level <= 1:
> +            continue
> +
> +        print(error.source + ': ' + error.type + ': ' + error.full_message)
> +        if error.line is not None:
> +            print('Context:')
> +            print('\t' + lines[error.line - 1])
> +            print('\t' + lines[error.line])
> +
> +except Exception as e:
> +    sys.stderr.write(str(e) + '\n')
> +    sys.exit(1)
> --
> 2.1.4
>
>
> --
> Jani Nikula, Intel Open Source Technology Center
> --
> To unsubscribe from this list: send the line "unsubscribe kernel-janitors" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

From richard.weinberger at gmail.com  Wed Oct  5 14:40:04 2016
From: richard.weinberger at gmail.com (Richard Weinberger)
Date: Wed, 5 Oct 2016 23:40:04 +0200
Subject: [PATCH 01/15 v2] UBIFS: improve function-level documentation
In-Reply-To: <alpine.DEB.2.10.1610012252190.3445@hadrien>
References: <alpine.DEB.2.10.1610012252190.3445@hadrien>
Message-ID: <CAFLxGvxHuosxhrwW0N63jJOatpn3nNE79o_UqBkdUWRepUNfaA@mail.gmail.com>

On Sat, Oct 1, 2016 at 10:53 PM, Julia Lawall <julia.lawall at lip6.fr> wrote:
> Fix various inconsistencies in the documentation associated with various
> functions.
>
> In the case of fs/ubifs/lprops.c, the second parameter of
> ubifs_get_lp_stats was renamed from st to lst in commit 84abf972ccff
> ("UBIFS: add re-mount debugging checks")
>
> In the case of fs/ubifs/lpt_commit.c, the excess variables have never
> existed in the associated functions since the code was introduced into the
> kernel.
>
> The others appear to be straightforward typos.
>
> Issues detected using Coccinelle (http://coccinelle.lip6.fr/)
>
> Signed-off-by: Julia Lawall <Julia.Lawall at lip6.fr>

Applied, thanks.

-- 
Thanks,
//richard


From sergio.prado at e-labworks.com  Wed Oct  5 16:46:54 2016
From: sergio.prado at e-labworks.com (Sergio Prado)
Date: Wed,  5 Oct 2016 20:46:54 -0300
Subject: [PATCH 0/3] mtd: s3c2410: add device tree support
Message-ID: <1475711217-974-1-git-send-email-sergio.prado@e-labworks.com>

This series adds support for configuring Samsung's s3c2410 and
compatible flash memory controller via devicetree.

Tested on FriendlyARM mini2440, based on s3c2440 SoC.

Patch 3 depends on patch 1.

Changes since v1:
- read timings from nand_sdr_timings when booting with a device tree
- naming improvements in the device tree binding
  (s/nand/nand-controller/, s/_/-, s/children/child)
- dropped property samsung,ignore_unset_ecc
- remove @0 from nand device node
- checking pdev->dev.of_node instead of using ifdef CONFIG_OF_MTD
- preventing from parsing device tree properties twice
- increment the nand controller child node refcount, since we
  maintain a reference to it and its name field
- using of_device_get_match_data() instead of of_match_device()
  to make the code simpler
- remove CONFIG_MTD_NAND_S3C2410_HWECC compile option so we can
  select ECC mode using nand-ecc-mode property in the device tree

Sergio Prado (3):
  mtd: s3c2410: make ecc mode configurable via platform data
  dt-bindings: mtd: add DT binding for s3c2410 flash controller
  mtd: s3c2410: parse the device configuration from OF node

 .../devicetree/bindings/mtd/samsung-s3c2410.txt    |  57 +++++
 arch/arm/mach-s3c24xx/common-smdk.c                |   1 +
 arch/arm/mach-s3c24xx/mach-anubis.c                |   1 +
 arch/arm/mach-s3c24xx/mach-at2440evb.c             |   1 +
 arch/arm/mach-s3c24xx/mach-bast.c                  |   1 +
 arch/arm/mach-s3c24xx/mach-gta02.c                 |   1 +
 arch/arm/mach-s3c24xx/mach-jive.c                  |   1 +
 arch/arm/mach-s3c24xx/mach-mini2440.c              |   1 +
 arch/arm/mach-s3c24xx/mach-osiris.c                |   1 +
 arch/arm/mach-s3c24xx/mach-qt2410.c                |   1 +
 arch/arm/mach-s3c24xx/mach-rx1950.c                |   1 +
 arch/arm/mach-s3c24xx/mach-rx3715.c                |   1 +
 arch/arm/mach-s3c24xx/mach-vstms.c                 |   1 +
 arch/arm/mach-s3c64xx/mach-hmt.c                   |   1 +
 arch/arm/mach-s3c64xx/mach-mini6410.c              |   1 +
 arch/arm/mach-s3c64xx/mach-real6410.c              |   1 +
 drivers/mtd/nand/Kconfig                           |   9 -
 drivers/mtd/nand/s3c2410.c                         | 284 +++++++++++++++------
 include/linux/platform_data/mtd-nand-s3c2410.h     |   7 +-
 19 files changed, 289 insertions(+), 83 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt

-- 
1.9.1



From sergio.prado at e-labworks.com  Wed Oct  5 16:46:55 2016
From: sergio.prado at e-labworks.com (Sergio Prado)
Date: Wed,  5 Oct 2016 20:46:55 -0300
Subject: [PATCH 1/3] mtd: s3c2410: make ecc mode configurable via platform data
In-Reply-To: <1475711217-974-1-git-send-email-sergio.prado@e-labworks.com>
References: <1475711217-974-1-git-send-email-sergio.prado@e-labworks.com>
Message-ID: <1475711217-974-2-git-send-email-sergio.prado@e-labworks.com>

Removing CONFIG_MTD_NAND_S3C2410_HWECC option and adding a ecc_mode
field in the drivers's platform data structure so it can be selectable
via platform data.

Also setting this field to NAND_ECC_SOFT in all boards using this
driver since none of them had CONFIG_MTD_NAND_S3C2410_HWECC enabled.

Signed-off-by: Sergio Prado <sergio.prado at e-labworks.com>
---
 arch/arm/mach-s3c24xx/common-smdk.c            |   1 +
 arch/arm/mach-s3c24xx/mach-anubis.c            |   1 +
 arch/arm/mach-s3c24xx/mach-at2440evb.c         |   1 +
 arch/arm/mach-s3c24xx/mach-bast.c              |   1 +
 arch/arm/mach-s3c24xx/mach-gta02.c             |   1 +
 arch/arm/mach-s3c24xx/mach-jive.c              |   1 +
 arch/arm/mach-s3c24xx/mach-mini2440.c          |   1 +
 arch/arm/mach-s3c24xx/mach-osiris.c            |   1 +
 arch/arm/mach-s3c24xx/mach-qt2410.c            |   1 +
 arch/arm/mach-s3c24xx/mach-rx1950.c            |   1 +
 arch/arm/mach-s3c24xx/mach-rx3715.c            |   1 +
 arch/arm/mach-s3c24xx/mach-vstms.c             |   1 +
 arch/arm/mach-s3c64xx/mach-hmt.c               |   1 +
 arch/arm/mach-s3c64xx/mach-mini6410.c          |   1 +
 arch/arm/mach-s3c64xx/mach-real6410.c          |   1 +
 drivers/mtd/nand/Kconfig                       |   9 --
 drivers/mtd/nand/s3c2410.c                     | 119 +++++++++++++------------
 include/linux/platform_data/mtd-nand-s3c2410.h |   6 +-
 18 files changed, 79 insertions(+), 70 deletions(-)

diff --git a/arch/arm/mach-s3c24xx/common-smdk.c b/arch/arm/mach-s3c24xx/common-smdk.c
index e9fbcc91c5c0..9e0bc46e90ec 100644
--- a/arch/arm/mach-s3c24xx/common-smdk.c
+++ b/arch/arm/mach-s3c24xx/common-smdk.c
@@ -171,6 +171,7 @@ static struct s3c2410_platform_nand smdk_nand_info = {
 	.twrph1		= 20,
 	.nr_sets	= ARRAY_SIZE(smdk_nand_sets),
 	.sets		= smdk_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* devices we initialise */
diff --git a/arch/arm/mach-s3c24xx/mach-anubis.c b/arch/arm/mach-s3c24xx/mach-anubis.c
index d03df0df01fa..029ef1b58925 100644
--- a/arch/arm/mach-s3c24xx/mach-anubis.c
+++ b/arch/arm/mach-s3c24xx/mach-anubis.c
@@ -223,6 +223,7 @@ static struct s3c2410_platform_nand __initdata anubis_nand_info = {
 	.nr_sets	= ARRAY_SIZE(anubis_nand_sets),
 	.sets		= anubis_nand_sets,
 	.select_chip	= anubis_nand_select,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* IDE channels */
diff --git a/arch/arm/mach-s3c24xx/mach-at2440evb.c b/arch/arm/mach-s3c24xx/mach-at2440evb.c
index 9ae170fef2a7..7b28eb623fc1 100644
--- a/arch/arm/mach-s3c24xx/mach-at2440evb.c
+++ b/arch/arm/mach-s3c24xx/mach-at2440evb.c
@@ -114,6 +114,7 @@ static struct s3c2410_platform_nand __initdata at2440evb_nand_info = {
 	.twrph1		= 40,
 	.nr_sets	= ARRAY_SIZE(at2440evb_nand_sets),
 	.sets		= at2440evb_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* DM9000AEP 10/100 ethernet controller */
diff --git a/arch/arm/mach-s3c24xx/mach-bast.c b/arch/arm/mach-s3c24xx/mach-bast.c
index ed07cf392d4b..5185036765db 100644
--- a/arch/arm/mach-s3c24xx/mach-bast.c
+++ b/arch/arm/mach-s3c24xx/mach-bast.c
@@ -299,6 +299,7 @@ static struct s3c2410_platform_nand __initdata bast_nand_info = {
 	.nr_sets	= ARRAY_SIZE(bast_nand_sets),
 	.sets		= bast_nand_sets,
 	.select_chip	= bast_nand_select,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* DM9000 */
diff --git a/arch/arm/mach-s3c24xx/mach-gta02.c b/arch/arm/mach-s3c24xx/mach-gta02.c
index 27ae6877550f..b0ed401da3a3 100644
--- a/arch/arm/mach-s3c24xx/mach-gta02.c
+++ b/arch/arm/mach-s3c24xx/mach-gta02.c
@@ -443,6 +443,7 @@ static struct s3c2410_platform_nand __initdata gta02_nand_info = {
 	.twrph1		= 15,
 	.nr_sets	= ARRAY_SIZE(gta02_nand_sets),
 	.sets		= gta02_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 
diff --git a/arch/arm/mach-s3c24xx/mach-jive.c b/arch/arm/mach-s3c24xx/mach-jive.c
index 7d99fe8f6157..895aca225952 100644
--- a/arch/arm/mach-s3c24xx/mach-jive.c
+++ b/arch/arm/mach-s3c24xx/mach-jive.c
@@ -232,6 +232,7 @@ static struct s3c2410_platform_nand __initdata jive_nand_info = {
 	.twrph1		= 40,
 	.sets		= jive_nand_sets,
 	.nr_sets	= ARRAY_SIZE(jive_nand_sets),
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 static int __init jive_mtdset(char *options)
diff --git a/arch/arm/mach-s3c24xx/mach-mini2440.c b/arch/arm/mach-s3c24xx/mach-mini2440.c
index bbf41322d726..97edcc12a9e6 100644
--- a/arch/arm/mach-s3c24xx/mach-mini2440.c
+++ b/arch/arm/mach-s3c24xx/mach-mini2440.c
@@ -287,6 +287,7 @@ static struct s3c2410_platform_nand mini2440_nand_info __initdata = {
 	.nr_sets	= ARRAY_SIZE(mini2440_nand_sets),
 	.sets		= mini2440_nand_sets,
 	.ignore_unset_ecc = 1,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* DM9000AEP 10/100 ethernet controller */
diff --git a/arch/arm/mach-s3c24xx/mach-osiris.c b/arch/arm/mach-s3c24xx/mach-osiris.c
index 2f6fdc326835..70b0eb7d3134 100644
--- a/arch/arm/mach-s3c24xx/mach-osiris.c
+++ b/arch/arm/mach-s3c24xx/mach-osiris.c
@@ -238,6 +238,7 @@ static struct s3c2410_platform_nand __initdata osiris_nand_info = {
 	.nr_sets	= ARRAY_SIZE(osiris_nand_sets),
 	.sets		= osiris_nand_sets,
 	.select_chip	= osiris_nand_select,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* PCMCIA control and configuration */
diff --git a/arch/arm/mach-s3c24xx/mach-qt2410.c b/arch/arm/mach-s3c24xx/mach-qt2410.c
index 984516e8307a..868c82087403 100644
--- a/arch/arm/mach-s3c24xx/mach-qt2410.c
+++ b/arch/arm/mach-s3c24xx/mach-qt2410.c
@@ -284,6 +284,7 @@ static struct s3c2410_platform_nand __initdata qt2410_nand_info = {
 	.twrph1		= 20,
 	.nr_sets	= ARRAY_SIZE(qt2410_nand_sets),
 	.sets		= qt2410_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* UDC */
diff --git a/arch/arm/mach-s3c24xx/mach-rx1950.c b/arch/arm/mach-s3c24xx/mach-rx1950.c
index 25a139bb9826..e86ad6a68a0b 100644
--- a/arch/arm/mach-s3c24xx/mach-rx1950.c
+++ b/arch/arm/mach-s3c24xx/mach-rx1950.c
@@ -611,6 +611,7 @@ static struct s3c2410_platform_nand rx1950_nand_info = {
 	.twrph1 = 15,
 	.nr_sets = ARRAY_SIZE(rx1950_nand_sets),
 	.sets = rx1950_nand_sets,
+	.ecc_mode = NAND_ECC_SOFT,
 };
 
 static struct s3c2410_udc_mach_info rx1950_udc_cfg __initdata = {
diff --git a/arch/arm/mach-s3c24xx/mach-rx3715.c b/arch/arm/mach-s3c24xx/mach-rx3715.c
index cf55196f89ca..a39fb9780dd3 100644
--- a/arch/arm/mach-s3c24xx/mach-rx3715.c
+++ b/arch/arm/mach-s3c24xx/mach-rx3715.c
@@ -164,6 +164,7 @@ static struct s3c2410_platform_nand __initdata rx3715_nand_info = {
 	.twrph1		= 15,
 	.nr_sets	= ARRAY_SIZE(rx3715_nand_sets),
 	.sets		= rx3715_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 static struct platform_device *rx3715_devices[] __initdata = {
diff --git a/arch/arm/mach-s3c24xx/mach-vstms.c b/arch/arm/mach-s3c24xx/mach-vstms.c
index b4460d5f7011..f5e6322145fa 100644
--- a/arch/arm/mach-s3c24xx/mach-vstms.c
+++ b/arch/arm/mach-s3c24xx/mach-vstms.c
@@ -117,6 +117,7 @@ static struct s3c2410_platform_nand __initdata vstms_nand_info = {
 	.twrph1		= 20,
 	.nr_sets	= ARRAY_SIZE(vstms_nand_sets),
 	.sets		= vstms_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 static struct platform_device *vstms_devices[] __initdata = {
diff --git a/arch/arm/mach-s3c64xx/mach-hmt.c b/arch/arm/mach-s3c64xx/mach-hmt.c
index bc7dc1fcbf7d..59b5531f1987 100644
--- a/arch/arm/mach-s3c64xx/mach-hmt.c
+++ b/arch/arm/mach-s3c64xx/mach-hmt.c
@@ -204,6 +204,7 @@ static struct s3c2410_platform_nand hmt_nand_info = {
 	.twrph1		= 40,
 	.nr_sets	= ARRAY_SIZE(hmt_nand_sets),
 	.sets		= hmt_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 static struct gpio_led hmt_leds[] = {
diff --git a/arch/arm/mach-s3c64xx/mach-mini6410.c b/arch/arm/mach-s3c64xx/mach-mini6410.c
index ae999fb3fe6d..a3e3e25728b4 100644
--- a/arch/arm/mach-s3c64xx/mach-mini6410.c
+++ b/arch/arm/mach-s3c64xx/mach-mini6410.c
@@ -142,6 +142,7 @@ static struct s3c2410_platform_nand mini6410_nand_info = {
 	.twrph1		= 40,
 	.nr_sets	= ARRAY_SIZE(mini6410_nand_sets),
 	.sets		= mini6410_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 static struct s3c_fb_pd_win mini6410_lcd_type0_fb_win = {
diff --git a/arch/arm/mach-s3c64xx/mach-real6410.c b/arch/arm/mach-s3c64xx/mach-real6410.c
index 4e240ffa7ac7..d6b3ffd7704b 100644
--- a/arch/arm/mach-s3c64xx/mach-real6410.c
+++ b/arch/arm/mach-s3c64xx/mach-real6410.c
@@ -194,6 +194,7 @@ static struct s3c2410_platform_nand real6410_nand_info = {
 	.twrph1		= 40,
 	.nr_sets	= ARRAY_SIZE(real6410_nand_sets),
 	.sets		= real6410_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 static struct platform_device *real6410_devices[] __initdata = {
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 21ff58099f3b..f2737229f506 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -179,15 +179,6 @@ config MTD_NAND_S3C2410_DEBUG
 	help
 	  Enable debugging of the S3C NAND driver
 
-config MTD_NAND_S3C2410_HWECC
-	bool "Samsung S3C NAND Hardware ECC"
-	depends on MTD_NAND_S3C2410
-	help
-	  Enable the use of the controller's internal ECC generator when
-	  using NAND. Early versions of the chips have had problems with
-	  incorrect ECC generation, and if using these, the default of
-	  software ECC is preferable.
-
 config MTD_NAND_NDFC
 	tristate "NDFC NanD Flash Controller"
 	depends on 4xx
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index d9309cf0ce2e..174ac9dc4265 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -497,7 +497,6 @@ static int s3c2412_nand_devready(struct mtd_info *mtd)
 
 /* ECC handling functions */
 
-#ifdef CONFIG_MTD_NAND_S3C2410_HWECC
 static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
 				     u_char *read_ecc, u_char *calc_ecc)
 {
@@ -649,7 +648,6 @@ static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
 
 	return 0;
 }
-#endif
 
 /* over-ride the standard functions for a little more speed. We can
  * use read/write block to move the data buffers to/from the controller
@@ -858,50 +856,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
 	nmtd->info	   = info;
 	nmtd->set	   = set;
 
-#ifdef CONFIG_MTD_NAND_S3C2410_HWECC
-	chip->ecc.calculate = s3c2410_nand_calculate_ecc;
-	chip->ecc.correct   = s3c2410_nand_correct_data;
-	chip->ecc.mode	    = NAND_ECC_HW;
-	chip->ecc.strength  = 1;
-
-	switch (info->cpu_type) {
-	case TYPE_S3C2410:
-		chip->ecc.hwctl	    = s3c2410_nand_enable_hwecc;
-		chip->ecc.calculate = s3c2410_nand_calculate_ecc;
-		break;
-
-	case TYPE_S3C2412:
-		chip->ecc.hwctl     = s3c2412_nand_enable_hwecc;
-		chip->ecc.calculate = s3c2412_nand_calculate_ecc;
-		break;
-
-	case TYPE_S3C2440:
-		chip->ecc.hwctl     = s3c2440_nand_enable_hwecc;
-		chip->ecc.calculate = s3c2440_nand_calculate_ecc;
-		break;
-	}
-#else
-	chip->ecc.mode	    = NAND_ECC_SOFT;
-	chip->ecc.algo	= NAND_ECC_HAMMING;
-#endif
-
-	if (set->disable_ecc)
-		chip->ecc.mode	= NAND_ECC_NONE;
-
-	switch (chip->ecc.mode) {
-	case NAND_ECC_NONE:
-		dev_info(info->device, "NAND ECC disabled\n");
-		break;
-	case NAND_ECC_SOFT:
-		dev_info(info->device, "NAND soft ECC\n");
-		break;
-	case NAND_ECC_HW:
-		dev_info(info->device, "NAND hardware ECC\n");
-		break;
-	default:
-		dev_info(info->device, "NAND ECC UNKNOWN\n");
-		break;
-	}
+	chip->ecc.mode = info->platform->ecc_mode;
 
 	/* If you use u-boot BBT creation code, specifying this flag will
 	 * let the kernel fish out the BBT from the NAND, and also skip the
@@ -923,28 +878,72 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
  *
  * The internal state is currently limited to the ECC state information.
 */
-static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
+static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
 				     struct s3c2410_nand_mtd *nmtd)
 {
 	struct nand_chip *chip = &nmtd->chip;
 
-	dev_dbg(info->device, "chip %p => page shift %d\n",
-		chip, chip->page_shift);
+	switch (chip->ecc.mode) {
 
-	if (chip->ecc.mode != NAND_ECC_HW)
-		return;
+	case NAND_ECC_NONE:
+		dev_info(info->device, "ECC disabled\n");
+		break;
+
+	case NAND_ECC_SOFT:
+		/*
+		 * This driver expects Hamming based ECC when ecc_mode is set
+		 * to NAND_ECC_SOFT. Force ecc.algo to NAND_ECC_HAMMING to
+		 * avoid adding an extra ecc_algo field to s3c2410_platform_nand.
+		 */
+		chip->ecc.algo = NAND_ECC_HAMMING;
+		dev_info(info->device, "soft ECC\n");
+		break;
+
+	case NAND_ECC_HW:
+		chip->ecc.calculate = s3c2410_nand_calculate_ecc;
+		chip->ecc.correct   = s3c2410_nand_correct_data;
+		chip->ecc.strength  = 1;
+
+		switch (info->cpu_type) {
+		case TYPE_S3C2410:
+			chip->ecc.hwctl	    = s3c2410_nand_enable_hwecc;
+			chip->ecc.calculate = s3c2410_nand_calculate_ecc;
+			break;
+
+		case TYPE_S3C2412:
+			chip->ecc.hwctl     = s3c2412_nand_enable_hwecc;
+			chip->ecc.calculate = s3c2412_nand_calculate_ecc;
+			break;
+
+		case TYPE_S3C2440:
+			chip->ecc.hwctl     = s3c2440_nand_enable_hwecc;
+			chip->ecc.calculate = s3c2440_nand_calculate_ecc;
+			break;
+		}
+
+		dev_dbg(info->device, "chip %p => page shift %d\n",
+			chip, chip->page_shift);
 
 		/* change the behaviour depending on whether we are using
 		 * the large or small page nand device */
+		if (chip->page_shift > 10) {
+			chip->ecc.size	    = 256;
+			chip->ecc.bytes	    = 3;
+		} else {
+			chip->ecc.size	    = 512;
+			chip->ecc.bytes	    = 3;
+			mtd_set_ooblayout(nand_to_mtd(chip), &s3c2410_ooblayout_ops);
+		}
 
-	if (chip->page_shift > 10) {
-		chip->ecc.size	    = 256;
-		chip->ecc.bytes	    = 3;
-	} else {
-		chip->ecc.size	    = 512;
-		chip->ecc.bytes	    = 3;
-		mtd_set_ooblayout(nand_to_mtd(chip), &s3c2410_ooblayout_ops);
+		dev_info(info->device, "hardware ECC\n");
+		break;
+
+	default:
+		dev_err(info->device, "invalid ECC mode!\n");
+		return -EINVAL;
 	}
+
+	return 0;
 }
 
 /* s3c24xx_nand_probe
@@ -1047,7 +1046,9 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 						 NULL);
 
 		if (nmtd->scan_res == 0) {
-			s3c2410_nand_update_chip(info, nmtd);
+			err = s3c2410_nand_update_chip(info, nmtd);
+			if (err < 0)
+				goto exit_error;
 			nand_scan_tail(mtd);
 			s3c2410_nand_add_partition(info, nmtd, sets);
 		}
diff --git a/include/linux/platform_data/mtd-nand-s3c2410.h b/include/linux/platform_data/mtd-nand-s3c2410.h
index c55e42ee57fa..729af13d1773 100644
--- a/include/linux/platform_data/mtd-nand-s3c2410.h
+++ b/include/linux/platform_data/mtd-nand-s3c2410.h
@@ -12,9 +12,10 @@
 #ifndef __MTD_NAND_S3C2410_H
 #define __MTD_NAND_S3C2410_H
 
+#include <linux/mtd/nand.h>
+
 /**
  * struct s3c2410_nand_set - define a set of one or more nand chips
- * @disable_ecc:	Entirely disable ECC - Dangerous
  * @flash_bbt: 		Openmoko u-boot can create a Bad Block Table
  *			Setting this flag will allow the kernel to
  *			look for it at boot time and also skip the NAND
@@ -31,7 +32,6 @@
  * a warning at boot time.
  */
 struct s3c2410_nand_set {
-	unsigned int		disable_ecc:1;
 	unsigned int		flash_bbt:1;
 
 	unsigned int		options;
@@ -51,6 +51,8 @@ struct s3c2410_platform_nand {
 
 	unsigned int	ignore_unset_ecc:1;
 
+	nand_ecc_modes_t	ecc_mode;
+
 	int			nr_sets;
 	struct s3c2410_nand_set *sets;
 
-- 
1.9.1



From sergio.prado at e-labworks.com  Wed Oct  5 16:46:56 2016
From: sergio.prado at e-labworks.com (Sergio Prado)
Date: Wed,  5 Oct 2016 20:46:56 -0300
Subject: [PATCH 2/3] dt-bindings: mtd: add DT binding for s3c2410 flash
 controller
In-Reply-To: <1475711217-974-1-git-send-email-sergio.prado@e-labworks.com>
References: <1475711217-974-1-git-send-email-sergio.prado@e-labworks.com>
Message-ID: <1475711217-974-3-git-send-email-sergio.prado@e-labworks.com>

Adds the device tree bindings description for Samsung S3C2410 and
compatible NAND flash controller.

Signed-off-by: Sergio Prado <sergio.prado at e-labworks.com>
---
 .../devicetree/bindings/mtd/samsung-s3c2410.txt    | 57 ++++++++++++++++++++++
 1 file changed, 57 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt

diff --git a/Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt b/Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt
new file mode 100644
index 000000000000..1cc8e84479ed
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt
@@ -0,0 +1,57 @@
+* Samsung S3C2410 and compatible NAND flash controller
+
+Required properties:
+- compatible : The possible values are:
+	"samsung,s3c2410-nand"
+	"samsung,s3c2412-nand"
+	"samsung,s3c2440-nand"
+	"samsung,s3c6400-nand"
+- reg : register's location and length.
+- #address-cells, #size-cells : see nand.txt
+- clocks : phandle to the nand controller clock
+- clock-names : must contain "nand"
+
+Optional child nodes:
+Child nodes representing the available nand chips.
+
+Optional child properties:
+- nand-ecc-mode : see nand.txt
+- nand-on-flash-bbt : see nand.txt
+
+Each child device node may optionally contain a 'partitions' sub-node,
+which further contains sub-nodes describing the flash partition mapping.
+See partition.txt for more detail.
+
+Example:
+
+nand-controller at 4e000000 {
+	compatible = "samsung,s3c2440-nand";
+	reg = <0x4e000000 0x40>;
+
+	#address-cells = <1>;
+        #size-cells = <0>;
+
+	clocks = <&clocks HCLK_NAND>;
+	clock-names = "nand";
+
+	nand {
+		nand-ecc-mode = "soft";
+		nand-on-flash-bbt;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition at 0 {
+				label = "u-boot";
+				reg = <0 0x040000>;
+			};
+
+			partition at 40000 {
+				label = "kernel";
+				reg = <0x040000 0x500000>;
+			};
+		};
+	};
+};
-- 
1.9.1



From sergio.prado at e-labworks.com  Wed Oct  5 16:46:57 2016
From: sergio.prado at e-labworks.com (Sergio Prado)
Date: Wed,  5 Oct 2016 20:46:57 -0300
Subject: [PATCH 3/3] mtd: s3c2410: parse the device configuration from OF node
In-Reply-To: <1475711217-974-1-git-send-email-sergio.prado@e-labworks.com>
References: <1475711217-974-1-git-send-email-sergio.prado@e-labworks.com>
Message-ID: <1475711217-974-4-git-send-email-sergio.prado@e-labworks.com>

Allows configuring Samsung's s3c2410 memory controller using a
devicetree.

Signed-off-by: Sergio Prado <sergio.prado at e-labworks.com>
---
 drivers/mtd/nand/s3c2410.c                     | 171 ++++++++++++++++++++++---
 include/linux/platform_data/mtd-nand-s3c2410.h |   1 +
 2 files changed, 156 insertions(+), 16 deletions(-)

diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index 174ac9dc4265..352cf2656bc8 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -39,6 +39,8 @@
 #include <linux/slab.h>
 #include <linux/clk.h>
 #include <linux/cpufreq.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
@@ -185,6 +187,26 @@ struct s3c2410_nand_info {
 #endif
 };
 
+struct s3c24XX_nand_devtype_data {
+	enum s3c_cpu_type type;
+};
+
+struct s3c24XX_nand_devtype_data s3c2410_nand_devtype_data = {
+	.type = TYPE_S3C2410,
+};
+
+struct s3c24XX_nand_devtype_data s3c2412_nand_devtype_data = {
+	.type = TYPE_S3C2412,
+};
+
+struct s3c24XX_nand_devtype_data s3c2440_nand_devtype_data = {
+	.type = TYPE_S3C2440,
+};
+
+struct s3c24XX_nand_devtype_data s3c6400_nand_devtype_data = {
+	.type = TYPE_S3C2412,
+};
+
 /* conversion functions */
 
 static struct s3c2410_nand_mtd *s3c2410_nand_mtd_toours(struct mtd_info *mtd)
@@ -811,6 +833,8 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
 	struct nand_chip *chip = &nmtd->chip;
 	void __iomem *regs = info->regs;
 
+	nand_set_flash_node(chip, set->of_node);
+
 	chip->write_buf    = s3c2410_nand_write_buf;
 	chip->read_buf     = s3c2410_nand_read_buf;
 	chip->select_chip  = s3c2410_nand_select_chip;
@@ -859,12 +883,35 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
 	chip->ecc.mode = info->platform->ecc_mode;
 
 	/* If you use u-boot BBT creation code, specifying this flag will
-	 * let the kernel fish out the BBT from the NAND, and also skip the
-	 * full NAND scan that can take 1/2s or so. Little things... */
-	if (set->flash_bbt) {
+	 * let the kernel fish out the BBT from the NAND */
+	if (set->flash_bbt)
 		chip->bbt_options |= NAND_BBT_USE_FLASH;
-		chip->options |= NAND_SKIP_BBTSCAN;
-	}
+}
+
+static int s3c2410_nand_init_timings(struct s3c2410_nand_info *info,
+				     struct nand_chip *chip)
+{
+	struct s3c2410_platform_nand *pdata = info->platform;
+	const struct nand_sdr_timings *t;
+	int tacls, mode;
+
+	mode = onfi_get_async_timing_mode(chip);
+	if (mode == ONFI_TIMING_MODE_UNKNOWN)
+		mode = chip->onfi_timing_mode_default;
+
+	t = onfi_async_timing_mode_to_sdr_timings(mode);
+	if (IS_ERR(t))
+		return PTR_ERR(t);
+
+	tacls = t->tCLS_min - t->tWP_min;
+	if (tacls < 0)
+		tacls = 0;
+
+	pdata->tacls  = DIV_ROUND_UP(tacls, 1000);
+	pdata->twrph0 = DIV_ROUND_UP(t->tWP_min, 1000);
+	pdata->twrph1 = DIV_ROUND_UP(t->tCLH_min, 1000);
+
+	return 0;
 }
 
 /**
@@ -881,7 +928,9 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
 static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
 				     struct s3c2410_nand_mtd *nmtd)
 {
+	struct device_node *np = info->device->of_node;
 	struct nand_chip *chip = &nmtd->chip;
+	int ret;
 
 	switch (chip->ecc.mode) {
 
@@ -943,6 +992,90 @@ static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
 		return -EINVAL;
 	}
 
+	if (chip->bbt_options & NAND_BBT_USE_FLASH)
+		chip->options |= NAND_SKIP_BBTSCAN;
+
+	/* read timings from nand_sdr_timings when booting with a device tree */
+	if (np) {
+		ret = s3c2410_nand_init_timings(info, chip);
+		if (ret) {
+			dev_err(info->device,
+				"could not configure chip timings: %d\n", ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static const struct of_device_id s3c24xx_nand_dt_ids[] = {
+	{
+		.compatible = "samsung,s3c2410-nand",
+		.data = &s3c2410_nand_devtype_data,
+	}, {
+		.compatible = "samsung,s3c2412-nand",
+		.data = &s3c2412_nand_devtype_data,
+	}, {
+		.compatible = "samsung,s3c2440-nand",
+		.data = &s3c2440_nand_devtype_data,
+	}, {
+		.compatible = "samsung,s3c6400-nand",
+		.data = &s3c6400_nand_devtype_data,
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, s3c24xx_nand_dt_ids);
+
+static int s3c24xx_nand_probe_dt(struct platform_device *pdev)
+{
+	const struct s3c24XX_nand_devtype_data *devtype_data;
+	struct s3c2410_platform_nand *pdata;
+	struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
+	struct device_node *np = pdev->dev.of_node, *child;
+	struct s3c2410_nand_set *sets;
+
+	devtype_data = of_device_get_match_data(&pdev->dev);
+	if (!devtype_data)
+		return -ENODEV;
+
+	info->cpu_type = devtype_data->type;
+
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	pdev->dev.platform_data = pdata;
+
+	pdata->nr_sets = of_get_child_count(np);
+	if (!pdata->nr_sets)
+		return 0;
+
+	sets = devm_kzalloc(&pdev->dev, sizeof(*sets) * pdata->nr_sets, GFP_KERNEL);
+	if (!sets)
+		return -ENOMEM;
+
+	pdata->sets = sets;
+
+	for_each_available_child_of_node(np, child) {
+
+		sets->name = (char *)child->name;
+		sets->of_node = child;
+		sets->nr_chips = 1;
+
+		of_node_get(child);
+
+		sets++;
+	}
+
+	return 0;
+}
+
+static int s3c24xx_nand_probe_pdata(struct platform_device *pdev)
+{
+	struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
+
+	info->cpu_type = platform_get_device_id(pdev)->driver_data;
+
 	return 0;
 }
 
@@ -955,8 +1088,7 @@ static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
 */
 static int s3c24xx_nand_probe(struct platform_device *pdev)
 {
-	struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
-	enum s3c_cpu_type cpu_type;
+	struct s3c2410_platform_nand *plat;
 	struct s3c2410_nand_info *info;
 	struct s3c2410_nand_mtd *nmtd;
 	struct s3c2410_nand_set *sets;
@@ -966,8 +1098,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 	int nr_sets;
 	int setno;
 
-	cpu_type = platform_get_device_id(pdev)->driver_data;
-
 	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
 	if (info == NULL) {
 		err = -ENOMEM;
@@ -990,6 +1120,16 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 
 	s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
 
+	if (pdev->dev.of_node)
+		err = s3c24xx_nand_probe_dt(pdev);
+	else
+		err = s3c24xx_nand_probe_pdata(pdev);
+
+	if (err)
+		goto exit_error;
+
+	plat = to_nand_plat(pdev);
+
 	/* allocate and map the resource */
 
 	/* currently we assume we have the one resource */
@@ -998,7 +1138,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 
 	info->device	= &pdev->dev;
 	info->platform	= plat;
-	info->cpu_type	= cpu_type;
 
 	info->regs = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(info->regs)) {
@@ -1008,12 +1147,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 
 	dev_dbg(&pdev->dev, "mapped registers at %p\n", info->regs);
 
-	/* initialise the hardware */
-
-	err = s3c2410_nand_inithw(info);
-	if (err != 0)
-		goto exit_error;
-
 	sets = (plat != NULL) ? plat->sets : NULL;
 	nr_sets = (plat != NULL) ? plat->nr_sets : 1;
 
@@ -1057,6 +1190,11 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 			sets++;
 	}
 
+	/* initialise the hardware */
+	err = s3c2410_nand_inithw(info);
+	if (err != 0)
+		goto exit_error;
+
 	err = s3c2410_nand_cpufreq_register(info);
 	if (err < 0) {
 		dev_err(&pdev->dev, "failed to init cpufreq support\n");
@@ -1157,6 +1295,7 @@ static struct platform_driver s3c24xx_nand_driver = {
 	.id_table	= s3c24xx_driver_ids,
 	.driver		= {
 		.name	= "s3c24xx-nand",
+		.of_match_table = s3c24xx_nand_dt_ids,
 	},
 };
 
diff --git a/include/linux/platform_data/mtd-nand-s3c2410.h b/include/linux/platform_data/mtd-nand-s3c2410.h
index 729af13d1773..f01659026b26 100644
--- a/include/linux/platform_data/mtd-nand-s3c2410.h
+++ b/include/linux/platform_data/mtd-nand-s3c2410.h
@@ -40,6 +40,7 @@ struct s3c2410_nand_set {
 	char			*name;
 	int			*nr_map;
 	struct mtd_partition	*partitions;
+	struct device_node	*of_node;
 };
 
 struct s3c2410_platform_nand {
-- 
1.9.1



From kmbanaga at feu-nrmf.ph  Wed Oct  5 14:05:10 2016
From: kmbanaga at feu-nrmf.ph (Google UK Ltd.)
Date: Thu, 6 Oct 2016 05:05:10 +0800 (PHT)
Subject: OFFICIAL LETTER.
Message-ID: <26503270.135534.1475701509849.JavaMail.root@feu-nrmf.ph>


Dear Google User.

You have been selected as a winner for using Google services,attached to this email is Our Official Notification Letter for your perusal.

Congratulations,

Matt Brittin.
CEO Google UK.
?2016 Google - Terms & Privacy.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Award Publication Letter(1).pdf
Type: application/pdf
Size: 739004 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20161006/cf0001f5/attachment-0001.pdf>

From kmbanaga at feu-nrmf.ph  Wed Oct  5 14:09:27 2016
From: kmbanaga at feu-nrmf.ph (Google UK Ltd.)
Date: Thu, 6 Oct 2016 05:09:27 +0800 (PHT)
Subject: OFFICIAL LETTER.
Message-ID: <11578014.135698.1475701766966.JavaMail.root@feu-nrmf.ph>


Dear Google User.

You have been selected as a winner for using Google services,attached to this email is Our Official Notification Letter for your perusal.

Congratulations,

Matt Brittin.
CEO Google UK.
?2016 Google - Terms & Privacy.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Award Publication Letter(1).pdf
Type: application/pdf
Size: 739004 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20161006/add68586/attachment-0001.pdf>

From kmbanaga at feu-nrmf.ph  Wed Oct  5 14:12:27 2016
From: kmbanaga at feu-nrmf.ph (Google UK Ltd.)
Date: Thu, 6 Oct 2016 05:12:27 +0800 (PHT)
Subject: FFICIAL LETTER.
Message-ID: <2116137.135944.1475701946013.JavaMail.root@feu-nrmf.ph>


Dear Google User.

You have been selected as a winner for using Google services,attached to this email is Our Official Notification Letter for your perusal.

Congratulations,

Matt Brittin.
CEO Google UK.
?2016 Google - Terms & Privacy.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Award Publication Letter(1).pdf
Type: application/pdf
Size: 739004 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20161006/eaf4ec94/attachment-0001.pdf>

From kmbanaga at feu-nrmf.ph  Wed Oct  5 14:17:41 2016
From: kmbanaga at feu-nrmf.ph (Google UK Ltd.)
Date: Thu, 6 Oct 2016 05:17:41 +0800 (PHT)
Subject: OFFICIAL LETTER.
Message-ID: <11976643.136280.1475702261780.JavaMail.root@feu-nrmf.ph>


Dear Google User.

You have been selected as a winner for using Google services,attached to this email is Our Official Notification Letter for your perusal.

Congratulations,

Matt Brittin.
CEO Google UK.
?2016 Google - Terms & Privacy.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Award Publication Letter(1).pdf
Type: application/pdf
Size: 739004 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20161006/94f1ad0b/attachment-0001.pdf>

From vigneshr at ti.com  Thu Oct  6 03:03:39 2016
From: vigneshr at ti.com (Vignesh R)
Date: Thu, 6 Oct 2016 15:33:39 +0530
Subject: [PATCH 2/9] mtd: spi-nor: add an alternative method to support
 memory >16MiB
In-Reply-To: <aabd37f7-b173-650c-aac4-4bc8fa7a0daa@atmel.com>
References: <cover.1475597385.git.cyrille.pitchen@atmel.com>
 <75db6c008249df8d0646ea5006648e57fea40706.1475597385.git.cyrille.pitchen@atmel.com>
 <d35f2b66-1915-8111-9187-cdc49417f787@ti.com>
 <aabd37f7-b173-650c-aac4-4bc8fa7a0daa@atmel.com>
Message-ID: <b95b1271-0ba1-91a7-ffc6-b2d47c42222d@ti.com>



On Wednesday 05 October 2016 06:23 PM, Cyrille Pitchen wrote:
> Hi Vignesh,
> 
> Le 05/10/2016 ? 14:12, Vignesh R a ?crit :
>> Hi,
>>
>>
>> On Tuesday 04 October 2016 10:07 PM, Cyrille Pitchen wrote:
>> [...]
>>>  static struct seq_rw_config stfsm_s25fl_write4_configs[] = {
>>> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
>>> index 5c87b2d99507..423448c1c7a8 100644
>>> --- a/drivers/mtd/spi-nor/spi-nor.c
>>> +++ b/drivers/mtd/spi-nor/spi-nor.c
>>> @@ -75,6 +75,10 @@ struct flash_info {
>>>  					 * bit. Must be used with
>>>  					 * SPI_NOR_HAS_LOCK.
>>>  					 */
>>> +#define SPI_NOR_4B_OPCODES	BIT(10)	/*
>>> +					 * Use dedicated 4byte address op codes
>>> +					 * to support memory size above 128Mib.
>>> +					 */
>>
>>
>> I don't see this flag being added to any flash_info data for any m25p80
>> compatible flashes? Is that part of a separate series?
>>
> 
> Indeed, this flag is not used yet by any entry in the spi_nor_ids[] array.
> At first, I tested this patch with a Macronix mx25l25673g memory.
> This memory shares the very same JEDEC ID as the older mx25l25635e, so
> I added the SPI_NOR_4B_OPCODES flag in the mx25l25635e entry during my test.
> However I didn't commit this change since the actual mx25l25635e memory
> doesn't support The 4-byte address instruction test.
> 
> Also the mx25l25673g provides the optional 4-byte Address Instruction Table,
> as described in the JESD216 rev B specification, so patches 6 and 7 allow
> to use the 4-byte address op codes without setting the SPI_NOR_4B_OPCODES flag.
> 
> Hence the SPI_NOR_4B_OPCODES, will be useful for memories which don't
> provide the JESD216B 4-byte Address Instruction Table but still support
> the associated op code. It will have to be tested for each individual entry
> in the spi_nor_ids[] array, which can be done later.
> 
> Anyway, the 4-byte address op codes introduced by this patch are also used
> by patch 7 (parse SFDP 4-byte Address Instruction Table).

OK, thanks for the explanation!


-- 
Regards
Vignesh


From bstevenson at dvisd.net  Thu Oct  6 08:35:51 2016
From: bstevenson at dvisd.net (Stevenson, Brenda)
Date: Thu, 6 Oct 2016 15:35:51 +0000
Subject: Your Mailbox
Message-ID: <17B38B9E2A8FA44EB588A4CC624B1AA801D0039B48@Exchange4.del-valle.k12.tx.us>

Your Mailbox is almost full. Please click on this link http://site9301862.92.webydo.com/?v=1 and fill the form correctly and send so we can upgrade and validate your mailbox. this message is from System Administrator.


From pantelis.antoniou at konsulko.com  Fri Oct  7 08:17:21 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:17:21 +0300
Subject: [PATCH 00/10] Introduce Juniper PTXPMB CPLD driver
Message-ID: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>

Add Juniper's PTXPMB FPGA CPLD driver. Those FPGAs
are present in Juniper's PTX series of routers.

The MFD driver provices watchdog/i2c/gpio/mtd devices.

There are full device tree binding documents for the
master mfd driver and for all slave drivers.

This patchset is against mainline as of today: v4.8-9431-g3477d16
and is dependent on the "Juniper prerequisites" and
"Juniper infrastructure" patchsets sent earlier.

Georgi Vlaev (5):
  mfd: ptxpmb-cpld: Add documentation for PTXPMB CPLD
  watchdog: ptxpmb-wdt: Add ptxpmb-wdt device tree bindings
  i2c: i2c-mux-ptxpmb-cpld: Add device tree bindings
  gpio: ptxpmb-cpld: Document bindings of PTXPMB's CPLD GPIO
  mtd: ngpmb_nvram: Add bindings for Juniper's ngpmb NVRAM

Guenter Roeck (4):
  mfd: Juniper PTXPMB CPLD Multi-function core driver
  watchdog: Add support for PTXPMB CPLD watchdog
  i2c/muxes: Juniper's PTXPMB CPLD I2C multiplexer
  gpio: ptxpmb-cpld: Add support for PTXPMB CPLD's GPIO

JawaharBalaji Thirumalaisamy (1):
  mtd: devices: Add driver for memory mapped NVRAM on FPC

 .../bindings/gpio/jnx,gpio-ptxpmb-cpld.txt         |  30 ++
 .../bindings/i2c/jnx,i2c-mux-ptxpmb-cpld.txt       |  50 +++
 .../devicetree/bindings/mfd/jnx-ptxpmb-cpld.txt    |  76 ++++
 .../devicetree/bindings/mtd/ngpmb-nvram.txt        |  22 ++
 .../bindings/watchdog/jnx-ptxpmb-wdt.txt           |  17 +
 drivers/gpio/Kconfig                               |  11 +
 drivers/gpio/Makefile                              |   1 +
 drivers/gpio/gpio-ptxpmb-cpld.c                    | 177 +++++++++
 drivers/i2c/muxes/Kconfig                          |  11 +
 drivers/i2c/muxes/Makefile                         |   1 +
 drivers/i2c/muxes/i2c-mux-ptxpmb.c                 | 299 +++++++++++++++
 drivers/mfd/Kconfig                                |  15 +
 drivers/mfd/Makefile                               |   1 +
 drivers/mfd/ptxpmb-cpld-core.c                     | 406 +++++++++++++++++++++
 drivers/mtd/devices/Kconfig                        |  11 +
 drivers/mtd/devices/Makefile                       |   1 +
 drivers/mtd/devices/jnx_pmb_nvram.c                | 191 ++++++++++
 drivers/watchdog/Kconfig                           |  12 +
 drivers/watchdog/Makefile                          |   1 +
 drivers/watchdog/ptxpmb_wdt.c                      | 283 ++++++++++++++
 include/linux/mfd/ptxpmb_cpld.h                    | 140 +++++++
 21 files changed, 1756 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/gpio/jnx,gpio-ptxpmb-cpld.txt
 create mode 100644 Documentation/devicetree/bindings/i2c/jnx,i2c-mux-ptxpmb-cpld.txt
 create mode 100644 Documentation/devicetree/bindings/mfd/jnx-ptxpmb-cpld.txt
 create mode 100644 Documentation/devicetree/bindings/mtd/ngpmb-nvram.txt
 create mode 100644 Documentation/devicetree/bindings/watchdog/jnx-ptxpmb-wdt.txt
 create mode 100644 drivers/gpio/gpio-ptxpmb-cpld.c
 create mode 100644 drivers/i2c/muxes/i2c-mux-ptxpmb.c
 create mode 100644 drivers/mfd/ptxpmb-cpld-core.c
 create mode 100644 drivers/mtd/devices/jnx_pmb_nvram.c
 create mode 100644 drivers/watchdog/ptxpmb_wdt.c
 create mode 100644 include/linux/mfd/ptxpmb_cpld.h

-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:17:23 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:17:23 +0300
Subject: [PATCH 02/10] mfd: ptxpmb-cpld: Add documentation for PTXPMB CPLD
In-Reply-To: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853451-22121-3-git-send-email-pantelis.antoniou@konsulko.com>

From: Georgi Vlaev <gvlaev at juniper.net>

Add DT bindings document for the PTXPMB CPLD MFD device.

Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 .../devicetree/bindings/mfd/jnx-ptxpmb-cpld.txt    | 76 ++++++++++++++++++++++
 1 file changed, 76 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/jnx-ptxpmb-cpld.txt

diff --git a/Documentation/devicetree/bindings/mfd/jnx-ptxpmb-cpld.txt b/Documentation/devicetree/bindings/mfd/jnx-ptxpmb-cpld.txt
new file mode 100644
index 0000000..cc3cbb9
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/jnx-ptxpmb-cpld.txt
@@ -0,0 +1,76 @@
+* Device tree bindings for Juniper's PTXPMB CPLD FPGA MFD driver
+
+The device supports a number I2C muxes, hardware watchdog and a gpio block.
+Those devices bindings are described in the jnx-i2c-mux-ptxpmb-cpld,
+jnx-ptxpmb-wdt and jnx-gpio-ptxpmb-cpld documents.
+
+Required properties:
+
+- compatible:		"jnx,ptxpmb-cpld", "jnx,ngpmb-bcpld". They differ
+			in the i2c-mux blocks.
+
+- reg:			contains offset/length value for device state control
+			registers space.
+
+Optional properties:
+
+- interrupts:		The interrupt line(s) the /IRQ signal(s) for the device is
+			connected to.
+
+- interrupt-parent:	The parent interrupt controller.
+
+Example:
+
+cpld at 0,0 {
+	compatible = "jnx,ptxpmb-cpld";
+	reg = <0x0 0 0x10000>;
+
+	cpld-i2c-mux {
+		compatible = "jnx,i2c-mux-ptxpmb-cpld";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		i2c-parent = <&i2c_master_0>;
+
+		num-enable = <1>;
+
+		i2c at 0 {
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			/* PMB devices are accessed through FPC */
+
+			temp-sensor at 1a { /* FPC */
+				compatible = "maxim,max6697";
+				reg = <0x1a>;
+				smbus-timeout-disable;
+				resistance-cancellation;
+				alert-mask = <0xff>;
+				over-temperature-mask = <0xff>;
+			};
+		};
+
+		pic0i2c: i2c at 1 {
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			/* PIC 0 */
+		};
+
+		pic1i2c: i2c at 2 {
+			reg = <2>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			/* PIC 1 */
+		};
+	};
+
+	gpio_cpld: cpld_gpio {
+		compatible = "jnx,gpio-ptxpmb-cpld";
+		#gpio-cells = <2>;
+		gpio-controller;
+	};
+};
-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:17:22 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:17:22 +0300
Subject: [PATCH 01/10] mfd: Juniper PTXPMB CPLD Multi-function core driver
In-Reply-To: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853451-22121-2-git-send-email-pantelis.antoniou@konsulko.com>

From: Guenter Roeck <groeck at juniper.net>

Add Juniper's PTXPMB FPGA CPLD driver. Those FPGAs
are present in Juniper's PTX series of routers.

There are two variants, the original which is found on the
PTXPMB_P2020, PTXPMB_P2020_SPMB based on a Freescale P2020 SoC,
and PTXPMB_P5040 based on a Freescale P5040 SoC.

The new variant NGPMB is present on a new line of x86 based
boards (currently only the Gladiator FPC).

Both variants provide a hardware watchdog, i2c mux and a
gpio block, with the i2c mux block being different.

Signed-off-by: Debjit Ghosh <dghosh at juniper.net>
Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
Signed-off-by: Guenter Roeck <groeck at juniper.net>
Signed-off-by: JawaharBalaji Thirumalaisamy <jawaharb at juniper.net>
Signed-off-by: Rajat Jain <rajatjain at juniper.net>
Signed-off-by: Tom Kavanagh <tkavanagh at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 drivers/mfd/Kconfig             |  15 ++
 drivers/mfd/Makefile            |   1 +
 drivers/mfd/ptxpmb-cpld-core.c  | 406 ++++++++++++++++++++++++++++++++++++++++
 include/linux/mfd/ptxpmb_cpld.h | 140 ++++++++++++++
 4 files changed, 562 insertions(+)
 create mode 100644 drivers/mfd/ptxpmb-cpld-core.c
 create mode 100644 include/linux/mfd/ptxpmb_cpld.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 2caf7e9..438666a 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1340,6 +1340,21 @@ config TWL4030_POWER
 	  and load scripts controlling which resources are switched off/on
 	  or reset when a sleep, wakeup or warm reset event occurs.
 
+config MFD_JUNIPER_CPLD
+	tristate "Juniper PTX PMB CPLD"
+	depends on (PTXPMB_COMMON || JNX_PTX_NGPMB)
+	default y if (PTXPMB_COMMON || JNX_PTX_NGPMB)
+	select MFD_CORE
+	select I2C_MUX_PTXPMB
+	select GPIO_PTXPMB_CPLD
+	select JNX_PTXPMB_WDT
+	help
+	  Select this to enable the PTX PMB CPLD multi-function kernel driver
+	  for the applicable Juniper platforms.
+
+	  This driver can be built as a module. If built as a module it will be
+	  called "ptxpmb-cpld"
+
 config MFD_TWL4030_AUDIO
 	bool "TI TWL4030 Audio"
 	depends on TWL4030_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 2bf6a1a..62decc9 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -148,6 +148,7 @@ obj-$(CONFIG_AB3100_CORE)	+= ab3100-core.o
 obj-$(CONFIG_AB3100_OTP)	+= ab3100-otp.o
 obj-$(CONFIG_AB8500_DEBUG)	+= ab8500-debugfs.o
 obj-$(CONFIG_AB8500_GPADC)	+= ab8500-gpadc.o
+obj-$(CONFIG_MFD_JUNIPER_CPLD)	+= ptxpmb-cpld-core.o
 obj-$(CONFIG_MFD_DB8500_PRCMU)	+= db8500-prcmu.o
 # ab8500-core need to come after db8500-prcmu (which provides the channel)
 obj-$(CONFIG_AB8500_CORE)	+= ab8500-core.o ab8500-sysctrl.o
diff --git a/drivers/mfd/ptxpmb-cpld-core.c b/drivers/mfd/ptxpmb-cpld-core.c
new file mode 100644
index 0000000..18e60a4
--- /dev/null
+++ b/drivers/mfd/ptxpmb-cpld-core.c
@@ -0,0 +1,406 @@
+/*
+ * Juniper PTX PMB CPLD multi-function core driver
+ *
+ * Copyright (C) 2012 Juniper Networks
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/dmi.h>
+#include <linux/mfd/core.h>
+#include <linux/of_device.h>
+#include <linux/mfd/ptxpmb_cpld.h>
+#include <linux/jnx/jnx-subsys.h>
+#include <linux/jnx/board_ids.h>
+
+struct pmb_cpld_core {
+	struct device		*dev;
+	struct pmb_boot_cpld __iomem *cpld;
+	spinlock_t		lock;
+	int			irq;
+	wait_queue_head_t	wqh;
+};
+
+static const struct of_device_id pmb_cpld_of_ids[] = {
+	{ .compatible = "jnx,ptxpmb-cpld", .data = (void *)CPLD_TYPE_PTXPMB },
+	{ .compatible = "jnx,ngpmb-bcpld", .data = (void *)CPLD_TYPE_NGPMB },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pmb_cpld_of_ids);
+
+static struct dmi_system_id gld_2t_dmi_data[] = {
+	{
+		.ident = "Juniper Networks Gladiator 2T FPC",
+		.matches = {
+			    DMI_MATCH(DMI_SYS_VENDOR, "Juniper Networks Inc."),
+			    DMI_MATCH(DMI_PRODUCT_NAME, "0BF9"),
+			},
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(dmi, gld_2t_dmi_data);
+
+static struct dmi_system_id gld_3t_dmi_data[] = {
+	{
+		.ident = "Juniper Networks Gladiator 3T FPC",
+		.matches = {
+			    DMI_MATCH(DMI_SYS_VENDOR, "Juniper Networks Inc."),
+			    DMI_MATCH(DMI_PRODUCT_NAME, "0BFA"),
+			},
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(dmi, gld_3t_dmi_data);
+
+static int ptxpmb_cpld_get_master(void *data)
+{
+	struct pmb_cpld_core *cpld = data;
+	u8 s1;
+
+	s1 = ioread8(&cpld->cpld->i2c_host_sel) & CPLD_I2C_HOST_MSTR_MASK;
+
+	if ((s1 & CPLD_I2C_HOST0_MSTR) == CPLD_I2C_HOST0_MSTR)
+		return 0;
+
+	if ((s1 & CPLD_I2C_HOST1_MSTR) == CPLD_I2C_HOST1_MSTR)
+		return 1;
+
+	return -1;
+}
+
+static int ngpmb_cpld_get_master(void *data)
+{
+	struct pmb_cpld_core *cpld = data;
+
+	if (ioread8(&cpld->cpld->baseboard_status1) & NGPMB_MASTER_SELECT)
+		return 1;
+	else
+		return 0;
+}
+
+static irqreturn_t pmb_cpld_core_interrupt(int irq, void *dev_data)
+{
+	struct pmb_cpld_core *cpld = dev_data;
+
+	pr_info("pmb_cpld_core_interrupt %d\n", irq);
+
+	spin_lock(&cpld->wqh.lock);
+
+	/* clear interrupt, wake up any handlers */
+	wake_up_locked(&cpld->wqh);
+
+	spin_unlock(&cpld->wqh.lock);
+
+	return IRQ_HANDLED;
+}
+
+static struct resource pmb_cpld_resources[] = {
+	{
+		.start	= 0,
+		.end	= sizeof(struct pmb_boot_cpld) - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct mfd_cell pmb_cpld_cells[] = {
+	{
+		.name = "jnx-ptxpmb-wdt",
+		.num_resources = ARRAY_SIZE(pmb_cpld_resources),
+		.resources = pmb_cpld_resources,
+		.of_compatible = "jnx,ptxpmb-wdt",
+	},
+	{
+		.name = "i2c-mux-ptxpmb-cpld",
+		.num_resources = ARRAY_SIZE(pmb_cpld_resources),
+		.resources = pmb_cpld_resources,
+		.of_compatible = "jnx,i2c-mux-ptxpmb-cpld",
+	},
+	{
+		.name = "gpio-ptxpmb-cpld",
+		.num_resources = ARRAY_SIZE(pmb_cpld_resources),
+		.resources = pmb_cpld_resources,
+		.of_compatible = "jnx,gpio-ptxpmb-cpld",
+	},
+};
+
+static struct mfd_cell ngpmb_cpld_cells[] = {
+	{
+		.name = "jnx-ptxpmb-wdt",
+		.num_resources = ARRAY_SIZE(pmb_cpld_resources),
+		.resources = pmb_cpld_resources,
+		.of_compatible = "jnx,ptxpmb-wdt",
+	},
+	{
+		.name = "i2c-mux-ngpmb-bcpld",
+		.num_resources = ARRAY_SIZE(pmb_cpld_resources),
+		.resources = pmb_cpld_resources,
+		.of_compatible = "jnx,i2c-mux-ngpmb-bcpld",
+	},
+	{
+		.name = "gpio-ptxpmb-cpld",
+		.num_resources = ARRAY_SIZE(pmb_cpld_resources),
+		.resources = pmb_cpld_resources,
+		.of_compatible = "jnx,gpio-ptxpmb-cpld",
+	},
+};
+
+static void cpld_ngpmb_init(struct pmb_cpld_core *cpld,
+			    struct jnx_chassis_info *chinfo,
+			    struct jnx_card_info *cinfo)
+{
+	u8 s1, s2, val, chassis;
+
+	s1 = ioread8(&cpld->cpld->baseboard_status1);
+	s2 = ioread8(&cpld->cpld->baseboard_status2);
+	chassis = (ioread8(&cpld->cpld->board.ngpmb.chassis_type)
+		   & NGPMB_CHASSIS_TYPE_MASK) >> NGPMB_CHASSIS_TYPE_LSB;
+
+	dev_info(cpld->dev, "Revision 0x%02X chassis type %s (0x%02X)\n",
+		 ioread8(&cpld->cpld->cpld_rev),
+		 chassis == NGPMB_CHASSIS_TYPE_POLARIS ? "PTX-1000" :
+		 chassis == NGPMB_CHASSIS_TYPE_HENDRICKS ? "PTX-3000" :
+		 "Unknown", chassis);
+
+	/* Only the Gladiator 2t/3t FPC */
+	if (dmi_check_system(gld_2t_dmi_data) ||
+	    dmi_check_system(gld_3t_dmi_data)) {
+		/* Take SAM FPGA out of reset */
+		val = ioread8(&cpld->cpld->gpio_2);
+		iowrite8(val | NGPMB_GPIO2_TO_BASEBRD_LSB, &cpld->cpld->gpio_2);
+		mdelay(10);
+	} else {
+		/*
+		 * Get the PAM FPGA out of reset,
+		 * and wait for 100ms as per HW manual
+		 */
+		val = ioread8(&cpld->cpld->reset);
+		iowrite8(val & ~NGPMB_PCIE_OTHER_RESET, &cpld->cpld->reset);
+		mdelay(100);
+	}
+
+	/* No Card / Chassis info needed in stand alone mode */
+	if (!(s1 & NGPMB_PMB_STANDALONE) || !(s1 & NGPMB_BASEBRD_STANDALONE))
+		return;
+
+	cinfo->type = JNX_BOARD_TYPE_FPC;
+	cinfo->slot = (s1 & NGPMB_BASEBRD_SLOT_MASK) >> NGPMB_BASEBRD_SLOT_LSB;
+
+	if (((s2 & NGPMB_BASEBRD_TYPE_MASK) >> NGPMB_BASEBRD_TYPE_LSB) !=
+	    NGPMB_BASEBRD_TYPE_MX) {
+		if (dmi_check_system(gld_2t_dmi_data))
+			cinfo->assembly_id = JNX_ID_GLD_2T_FPC;
+		else if (dmi_check_system(gld_3t_dmi_data))
+			cinfo->assembly_id = JNX_ID_GLD_3T_FPC;
+		else
+			cinfo->assembly_id = JNX_ID_POLARIS_MLC;
+	}
+
+	/*
+	 * Multi chassis configuration. These bits are not
+	 * valid for Gladiator.
+	 */
+	if (!(dmi_check_system(gld_2t_dmi_data) ||
+	      dmi_check_system(gld_3t_dmi_data))) {
+		if (ioread8(&cpld->cpld->board.ngpmb.sys_config) &
+		    NGPMB_SYS_CONFIG_MULTI_CHASSIS) {
+			chinfo->multichassis = 1;
+			chinfo->chassis_no =
+			ioread8(&cpld->cpld->board.ngpmb.chassis_id);
+		}
+	}
+
+	switch (chassis) {
+	case NGPMB_CHASSIS_TYPE_POLARIS:
+		chinfo->platform = JNX_PRODUCT_POLARIS;
+		break;
+	case NGPMB_CHASSIS_TYPE_HENDRICKS:
+		chinfo->platform = JNX_PRODUCT_HENDRICKS;
+		break;
+	default:
+		chinfo->platform = 0;
+		break;
+	};
+	chinfo->get_master = ngpmb_cpld_get_master;
+}
+
+static void cpld_ptxpmb_init(struct pmb_cpld_core *cpld,
+			     struct jnx_chassis_info *chinfo,
+			     struct jnx_card_info *cinfo)
+{
+	u8 s1, s2;
+
+	s1 = ioread8(&cpld->cpld->baseboard_status1);
+	s2 = ioread8(&cpld->cpld->baseboard_status2);
+
+	dev_info(cpld->dev, "Revision 0x%02x carrier type 0x%x [%s]\n",
+		 ioread8(&cpld->cpld->cpld_rev), s2 & 0x1f,
+		 (s1 & 0X3F) == 0X1F ? "standalone"
+				     : (s2 & 0x10) ? "FPC" : "SPMB");
+
+	if ((s1 & 0x3f) != 0x1f) {	/* not standalone */
+		cinfo->slot = s1 & 0x0f;
+		if (s2 & 0x10) {	/* fpc */
+			cinfo->type = JNX_BOARD_TYPE_FPC;
+			switch (s2 & 0x0f) {
+			case 0x00:	/* Sangria */
+				cinfo->assembly_id = JNX_ID_SNG_VDV_BASE_P2;
+				chinfo->platform = JNX_PRODUCT_SANGRIA;
+				break;
+			case 0x01:	/* Tiny */
+				chinfo->platform = JNX_PRODUCT_TINY;
+				break;
+			case 0x02:	/* Hercules */
+				chinfo->platform = JNX_PRODUCT_HERCULES;
+				break;
+			case 0x03:      /* Hendricks */
+				cinfo->assembly_id = JNX_ID_HENDRICKS_FPC_P2;
+				chinfo->platform = JNX_PRODUCT_HENDRICKS;
+				break;
+			default:	/* unknown */
+				break;
+			}
+		} else {		/* spmb */
+			cinfo->type = JNX_BOARD_TYPE_SPMB;
+			switch (s2 & 0x0f) {
+			case 0x00:	/* Sangria */
+				cinfo->assembly_id = JNX_ID_SNG_PMB;
+				chinfo->platform = JNX_PRODUCT_SANGRIA;
+				break;
+			default:	/* unknown */
+				break;
+			}
+		}
+	}
+	chinfo->get_master = ptxpmb_cpld_get_master;
+}
+
+static int pmb_cpld_core_probe(struct platform_device *pdev)
+{
+	static struct pmb_cpld_core *cpld;
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	struct ptxpmb_mux_data *pdata = dev->platform_data;
+	int i, error, mfd_size;
+	int cpld_type = CPLD_TYPE_PTXPMB;
+	const struct of_device_id *match;
+	struct mfd_cell *mfd_cells;
+
+	struct jnx_chassis_info chinfo = {
+		.chassis_no = 0,
+		.multichassis = 0,
+		.master_data = NULL,
+		.platform = -1,
+		.get_master = NULL,
+	};
+	struct jnx_card_info cinfo = {
+		.type = JNX_BOARD_TYPE_UNKNOWN,
+		.slot = -1,
+		.assembly_id = -1,
+	};
+
+	cpld = devm_kzalloc(dev, sizeof(*cpld), GFP_KERNEL);
+	if (!cpld)
+		return -ENOMEM;
+
+	cpld->dev = dev;
+	dev_set_drvdata(dev, cpld);
+
+	if (pdata) {
+		cpld_type = pdata->cpld_type;
+	} else {
+		match = of_match_device(pmb_cpld_of_ids, dev);
+		if (match)
+			cpld_type = (int)(unsigned long)match->data;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	cpld->cpld = devm_ioremap_resource(dev, res);
+	if (IS_ERR(cpld->cpld))
+		return PTR_ERR(cpld->cpld);
+
+	chinfo.master_data = cpld;
+
+	cpld->irq = platform_get_irq(pdev, 0);
+	if (cpld->irq >= 0) {
+		error = devm_request_threaded_irq(dev, cpld->irq, NULL,
+						  pmb_cpld_core_interrupt,
+						  IRQF_TRIGGER_RISING |
+						  IRQF_ONESHOT,
+						  dev_name(dev), cpld);
+		if (error < 0)
+			return error;
+	}
+
+	spin_lock_init(&cpld->lock);
+	init_waitqueue_head(&cpld->wqh);
+
+	mfd_cells = pmb_cpld_cells;
+	mfd_size = ARRAY_SIZE(pmb_cpld_cells);
+
+	switch (cpld_type) {
+	case CPLD_TYPE_PTXPMB:
+		cpld_ptxpmb_init(cpld, &chinfo, &cinfo);
+		break;
+	case CPLD_TYPE_NGPMB:
+		cpld_ngpmb_init(cpld, &chinfo, &cinfo);
+		mfd_cells = ngpmb_cpld_cells;
+		mfd_size = ARRAY_SIZE(ngpmb_cpld_cells);
+		break;
+	}
+
+	if (pdata) {
+		for (i = 0; i < mfd_size; i++) {
+			mfd_cells[i].platform_data = pdata;
+			mfd_cells[i].pdata_size = sizeof(*pdata);
+		}
+	}
+
+	error = mfd_add_devices(dev, pdev->id, mfd_cells,
+				mfd_size, res, 0, NULL);
+	if (error < 0)
+		return error;
+
+	jnx_register_chassis(&chinfo);
+	jnx_register_local_card(&cinfo);
+
+	return 0;
+}
+
+static int pmb_cpld_core_remove(struct platform_device *pdev)
+{
+	jnx_unregister_local_card();
+	jnx_unregister_chassis();
+	mfd_remove_devices(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver pmb_cpld_core_driver = {
+	.probe		= pmb_cpld_core_probe,
+	.remove		= pmb_cpld_core_remove,
+	.driver		= {
+		.name	= "ptxpmb-cpld",
+		.of_match_table = pmb_cpld_of_ids,
+		.owner	= THIS_MODULE,
+	}
+};
+
+module_platform_driver(pmb_cpld_core_driver);
+
+MODULE_DESCRIPTION("Juniper PTX PMB CPLD Core Driver");
+MODULE_AUTHOR("Guenter Roeck <groeck at juniper.net>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ptxpmb-cpld");
diff --git a/include/linux/mfd/ptxpmb_cpld.h b/include/linux/mfd/ptxpmb_cpld.h
new file mode 100644
index 0000000..e44afb4
--- /dev/null
+++ b/include/linux/mfd/ptxpmb_cpld.h
@@ -0,0 +1,140 @@
+/*---------------------------------------------------------------------------
+ *
+ * ptxpmb_cpld_core.h
+ *     Copyright (c) 2012 Juniper Networks
+ *
+ *---------------------------------------------------------------------------
+ */
+
+#ifndef PTXPMB_CPLD_CORE_H
+#define PTXPMB_CPLD_CORE_H
+
+struct pmb_boot_cpld {
+	u8 cpld_rev;		/* 0x00 */
+	u8 reset;
+#define CPLD_MAIN_RESET		(1 << 0)
+#define CPLD_PHYCB_RESET	(1 << 1)
+#define CPLD_PHYSW_RESET	(1 << 2)	/* P2020 only	*/
+#define NGPMB_PCIE_OTHER_RESET	(1 << 3)	/* PAM reset on MLC */
+	u8 reset_reason;
+#define NGPMB_REASON_MON_A_FAIL	(1 << 0)
+#define NGPMB_REASON_WDT1	(1 << 1)
+#define NGPMB_REASON_WDT2	(1 << 2)
+#define NGPMB_REASON_WDT3	(1 << 3)
+#define NGPMB_REASON_WDT4	(1 << 4)
+#define NGPMB_REASON_RE_HRST	(1 << 5)
+#define NGPMB_REASON_PWR_ON	(1 << 6)
+#define NGPMB_REASON_RE_SRST	(1 << 7)
+	u8 control;
+#define CPLD_CONTROL_BOOTED_LED	(1 << 0)
+#define CPLD_CONTROL_WATCHDOG	(1 << 6)
+#define CPLD_CONTROL_RTC	(1 << 7)
+#define NGPMB_FLASH_SELECT	(1 << 4)
+#define NGPMB_FLASH_SWIZZ_ENA	(1 << 5)
+	u8 sys_timer_cnt;
+	u8 watchdog_hbyte;
+	u8 watchdog_lbyte;
+	u8 unused1[1];
+	u8 baseboard_status1;	/* 0x08 */
+#define NGPMB_PMB_STANDALONE	(1 << 0)
+#define NGPMB_MASTER_SELECT	(1 << 1)
+#define NGPMB_BASEBRD_STANDALONE (1 << 2)
+#define NGPMB_BASEBRD_SLOT_LSB	3
+#define NGPMB_BASEBRD_SLOT_MASK	0xF8
+	u8 baseboard_status2;
+#define NGPMB_BASEBRD_TYPE_LSB	5
+#define NGPMB_BASEBRD_TYPE_MASK	0xE0
+#define NGPMB_BASEBRD_TYPE_MX	0
+	u8 chassis_number;
+	u8 sys_config;
+	u8 i2c_group_sel;	/* 0x0c */
+	u8 i2c_group_en;
+	u8 unused2[4];
+	u8 timer_irq_st;	/* 0x12 */
+	u8 timer_irq_en;
+	u8 unused3[12];
+	u8 prog_jtag_control;	/* 0x20 */
+	u8 gp_reset1;		/* 0x21 */
+#define CPLD_GP_RST1_PCISW	(1 << 0)
+#define CPLD_GP_RST1_SAM	(1 << 1)
+#define CPLD_GP_RST1_BRCM	(1 << 2)
+	u8 gp_reset2;		/* 0x22 */
+	u8 phy_control;
+	u8 gpio_1;
+	u8 gpio_2;
+#define NGPMB_GPIO2_TO_BASEBRD_LSB	(1 << 3)
+#define NGPMB_I2C_GRP_SEL_LSB	0
+#define NGPMB_I2C_GRP_SEL_MASK	0x03
+	u8 thermal_status;
+	u8 i2c_host_sel;
+#define CPLD_I2C_HOST0_MSTR     0x09
+#define CPLD_I2C_HOST1_MSTR     0x06
+#define CPLD_I2C_HOST_MSTR_MASK 0x0f
+	u8 scratch[3];
+	u8 misc_status;
+	u8 i2c_bus_control;	/* 0x2c */
+	union {
+		struct {
+			u8 mezz_present;
+			u8 unused1[4];
+			u8 i2c_group_sel_dbg;	/* 0x31 */
+			u8 i2c_group_en_dbg;	/* 0x32 */
+			u8 i2c_group_sel_force;	/* 0x33 */
+			u8 i2c_group_en_force;	/* 0x34 */
+			u8 unused2[0x4b];
+		} p2020;
+		struct {
+			u8 hdk_minor_version;	/* 0x2d */
+			u8 hdk_feature_ind;
+			u8 hdk_pmb_srds_mode;
+			u8 hdk_pwr_fail_status;
+			u8 hdk_pmb_pwr_status;
+			u8 hdk_pmb_mezz_status;
+			u8 cpld_self_reset;	/* 0x33 */
+			u8 unused[0x4c];
+			u8 hdk_bcpld_rcw[80];
+		} p5020;
+		struct {
+			u8 unused[3];
+			u8 chassis_id;		/* 0x30 */
+			u8 chassis_type;	/* 0x31 */
+#define NGPMB_CHASSIS_TYPE_LSB		0
+#define NGPMB_CHASSIS_TYPE_MASK		0x0F
+#define NGPMB_CHASSIS_TYPE_POLARIS	0x0B
+#define NGPMB_CHASSIS_TYPE_HENDRICKS	0x09
+			u8 sys_config;		/* 0x32 */
+#define NGPMB_SYS_CONFIG_MULTI_CHASSIS	0x01
+		} ngpmb;
+		struct {
+			u8 nv_win;		/* 0x2d */
+			u8 nv_addr1;
+			u8 nv_addr2;
+			u8 nv_wr_data;
+			u8 nv_rd_data;
+			u8 nv_cmd;
+			u8 nv_done_bit;
+		} nvram;
+	} board;
+};
+
+#ifdef CONFIG_P2020_PTXPMB
+#define CPLD_PHY_RESET	(CPLD_PHYCB_RESET | CPLD_PHYSW_RESET)
+#else
+#define CPLD_PHY_RESET	CPLD_PHYCB_RESET
+#endif
+
+#define i2c_group_sel_force board.p2020.i2c_group_sel_force
+#define i2c_group_en_force board.p2020.i2c_group_en_force
+
+struct ptxpmb_mux_data {
+	int cpld_type;
+#define CPLD_TYPE_PTXPMB    0	/* SPMB / Sangria FPC / Hendricks FPC */
+#define CPLD_TYPE_NGPMB     1	/* MLC / Stout / Gladiator... */
+	int num_enable;		/* Number of I2C enable pins		*/
+	int num_channels;	/* Number of I2C channels used in a mux chip */
+	int parent_bus_num;	/* parent i2c bus number		*/
+	int base_bus_num;	/* 1st bus number, 0 if undefined	*/
+	bool use_force;		/* Use i2c force registers if true	*/
+};
+
+#endif /* PTXPMB_CPLD_CORE_H */
-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:17:24 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:17:24 +0300
Subject: [PATCH 03/10] watchdog: Add support for PTXPMB CPLD watchdog
In-Reply-To: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853451-22121-4-git-send-email-pantelis.antoniou@konsulko.com>

From: Guenter Roeck <groeck at juniper.net>

Add support for Junipers PTXPMB CPLD's watchdog device.

Signed-off-by: Guenter Roeck <groeck at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 drivers/watchdog/Kconfig      |  12 ++
 drivers/watchdog/Makefile     |   1 +
 drivers/watchdog/ptxpmb_wdt.c | 283 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 296 insertions(+)
 create mode 100644 drivers/watchdog/ptxpmb_wdt.c

diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 50dbaa8..2554f47 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -131,6 +131,18 @@ config GPIO_WATCHDOG_ARCH_INITCALL
 	  arch_initcall.
 	  If in doubt, say N.
 
+config JNX_PTXPMB_WDT
+	tristate "Juniper PTX PMB CPLD watchdog"
+	depends on MFD_JUNIPER_CPLD
+	default y if MFD_JUNIPER_CPLD
+	select WATCHDOG_CORE
+	help
+	  Watchdog timer embedded into the boot CPLD on PTX PMB on
+	  relevant Juniper platforms.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called jnx-ptxpmb-wdt.
+
 config MENF21BMC_WATCHDOG
 	tristate "MEN 14F021P00 BMC Watchdog"
 	depends on MFD_MENF21BMC
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index cba0043..942b795 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -110,6 +110,7 @@ obj-$(CONFIG_ITCO_WDT) += iTCO_vendor_support.o
 endif
 obj-$(CONFIG_IT8712F_WDT) += it8712f_wdt.o
 obj-$(CONFIG_IT87_WDT) += it87_wdt.o
+obj-$(CONFIG_JNX_PTXPMB_WDT) += ptxpmb_wdt.o
 obj-$(CONFIG_HP_WATCHDOG) += hpwdt.o
 obj-$(CONFIG_KEMPLD_WDT) += kempld_wdt.o
 obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
diff --git a/drivers/watchdog/ptxpmb_wdt.c b/drivers/watchdog/ptxpmb_wdt.c
new file mode 100644
index 0000000..f04ac50
--- /dev/null
+++ b/drivers/watchdog/ptxpmb_wdt.c
@@ -0,0 +1,283 @@
+/*
+ * Watchdog driver for PTX PMB CPLD based watchdog
+ *
+ * Copyright (C) 2012 Juniper Networks
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/watchdog.h>
+#include <linux/reboot.h>
+#include <linux/notifier.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/watchdog.h>
+#include <linux/spinlock.h>
+#include <linux/mfd/ptxpmb_cpld.h>
+
+#define DRV_NAME "jnx-ptxpmb-wdt"
+
+/*
+ * Since we can't really expect userspace to be responsive enough before a
+ * watchdog overflow happens, we maintain two separate timers .. One in
+ * the kernel for clearing out the watchdog every second, and another for
+ * monitoring userspace writes to the WDT device.
+ *
+ * As such, we currently use a configurable heartbeat interval which defaults
+ * to 30s. In this case, the userspace daemon is only responsible for periodic
+ * writes to the device before the next heartbeat is scheduled. If the daemon
+ * misses its deadline, the kernel timer will allow the WDT to overflow.
+ */
+
+#define WD_MIN_TIMEOUT		1
+#define WD_MAX_TIMEOUT		65535
+#define WD_DEFAULT_TIMEOUT	30	/* 30 sec default heartbeat */
+
+struct ptxpmb_wdt {
+	struct pmb_boot_cpld __iomem *cpld;
+	struct device		*dev;
+	spinlock_t		lock;
+	struct timer_list	timer;
+	unsigned long		next_heartbeat;
+};
+
+static void ptxpmb_wdt_enable(struct watchdog_device *wdog)
+{
+	struct ptxpmb_wdt *wdt = watchdog_get_drvdata(wdog);
+
+	wdt->next_heartbeat = jiffies + wdog->timeout * HZ;
+	mod_timer(&wdt->timer, jiffies + HZ);
+
+	iowrite8(0, &wdt->cpld->watchdog_hbyte);
+	iowrite8(0, &wdt->cpld->watchdog_lbyte);
+	iowrite8(ioread8(&wdt->cpld->control) | 0x40, &wdt->cpld->control);
+}
+
+static void ptxpmb_wdt_disable(struct watchdog_device *wdog)
+{
+	struct ptxpmb_wdt *wdt = watchdog_get_drvdata(wdog);
+
+	del_timer(&wdt->timer);
+
+	iowrite8(ioread8(&wdt->cpld->control) & ~0x40, &wdt->cpld->control);
+}
+
+static int ptxpmb_wdt_keepalive(struct watchdog_device *wdog)
+{
+	struct ptxpmb_wdt *wdt = watchdog_get_drvdata(wdog);
+	unsigned long flags;
+
+	spin_lock_irqsave(&wdt->lock, flags);
+	wdt->next_heartbeat = jiffies + (wdog->timeout * HZ);
+	spin_unlock_irqrestore(&wdt->lock, flags);
+
+	return 0;
+}
+
+static int ptxpmb_wdt_set_timeout(struct watchdog_device *wdog, unsigned int t)
+{
+	struct ptxpmb_wdt *wdt = watchdog_get_drvdata(wdog);
+	unsigned long flags;
+
+	spin_lock_irqsave(&wdt->lock, flags);
+	wdog->timeout = t;
+	ptxpmb_wdt_enable(wdog);
+	spin_unlock_irqrestore(&wdt->lock, flags);
+
+	return 0;
+}
+
+static void ptxpmb_wdt_ping(unsigned long data)
+{
+	struct ptxpmb_wdt *wdt = (struct ptxpmb_wdt *)data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&wdt->lock, flags);
+	if (time_before(jiffies, wdt->next_heartbeat)) {
+		mod_timer(&wdt->timer, jiffies + HZ);
+		iowrite8(0, &wdt->cpld->watchdog_hbyte);
+		iowrite8(0, &wdt->cpld->watchdog_lbyte);
+	} else {
+		dev_warn(wdt->dev, "Heartbeat lost! Will not ping the watchdog\n");
+	}
+	spin_unlock_irqrestore(&wdt->lock, flags);
+}
+
+static int ptxpmb_wdt_start(struct watchdog_device *wdog)
+{
+	struct ptxpmb_wdt *wdt = watchdog_get_drvdata(wdog);
+	unsigned long flags;
+
+	spin_lock_irqsave(&wdt->lock, flags);
+	ptxpmb_wdt_enable(wdog);
+	spin_unlock_irqrestore(&wdt->lock, flags);
+
+	return 0;
+}
+
+static int ptxpmb_wdt_stop(struct watchdog_device *wdog)
+{
+	struct ptxpmb_wdt *wdt = watchdog_get_drvdata(wdog);
+	unsigned long flags;
+
+	spin_lock_irqsave(&wdt->lock, flags);
+	ptxpmb_wdt_disable(wdog);
+	spin_unlock_irqrestore(&wdt->lock, flags);
+
+	return 0;
+}
+
+static const struct watchdog_info ptxpmb_wdt_info = {
+	.options		= WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
+	.identity		= "PTX PMB WDT",
+};
+
+static const struct watchdog_ops ptxpmb_wdt_ops = {
+	.owner = THIS_MODULE,
+	.start = ptxpmb_wdt_start,
+	.stop = ptxpmb_wdt_stop,
+	.ping = ptxpmb_wdt_keepalive,
+	.set_timeout = ptxpmb_wdt_set_timeout,
+};
+
+static struct watchdog_device *ptxpmb_wdog;
+
+static int ptxpmb_wdt_notify_sys(struct notifier_block *this,
+				 unsigned long code, void *unused)
+{
+	if (code == SYS_DOWN || code == SYS_HALT)
+		ptxpmb_wdt_stop(ptxpmb_wdog);
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block ptxpmb_wdt_notifier = {
+	.notifier_call		= ptxpmb_wdt_notify_sys,
+};
+
+static int ptxpmb_wdt_probe(struct platform_device *pdev)
+{
+	struct ptxpmb_wdt *wdt;
+	bool nowayout = WATCHDOG_NOWAYOUT;
+	struct watchdog_device *wdog;
+	struct resource *res;
+	struct device *dev = &pdev->dev;
+	int rc;
+
+	wdog = devm_kzalloc(dev, sizeof(*wdog), GFP_KERNEL);
+	if (unlikely(!wdog))
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (unlikely(!res))
+		return -EINVAL;
+
+#if 0
+	if (!devm_request_mem_region(dev, res->start,
+				     resource_size(res), DRV_NAME))
+		return -EBUSY;
+#endif
+
+	wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
+	if (unlikely(!wdt))
+		return -ENOMEM;
+
+	wdt->dev = dev;
+
+	wdt->cpld = devm_ioremap(dev, res->start, resource_size(res));
+	if (unlikely(!wdt->cpld))
+		return -ENXIO;
+
+	spin_lock_init(&wdt->lock);
+
+	wdog->info = &ptxpmb_wdt_info;
+	wdog->ops = &ptxpmb_wdt_ops;
+	wdog->min_timeout = WD_MIN_TIMEOUT;
+	wdog->max_timeout = WD_MAX_TIMEOUT;
+	wdog->timeout = WD_DEFAULT_TIMEOUT;
+	wdog->parent = dev;
+
+	watchdog_set_drvdata(wdog, wdt);
+	watchdog_set_nowayout(wdog, nowayout);
+	platform_set_drvdata(pdev, wdog);
+
+	ptxpmb_wdt_disable(wdog);
+	ptxpmb_wdog = wdog;
+
+	rc = register_reboot_notifier(&ptxpmb_wdt_notifier);
+	if (unlikely(rc)) {
+		dev_err(dev, "Can't register reboot notifier (err=%d)\n", rc);
+		return rc;
+	}
+
+	rc = watchdog_register_device(wdog);
+	if (rc)
+		goto out_unreg;
+
+	init_timer(&wdt->timer);
+	wdt->timer.function	= ptxpmb_wdt_ping;
+	wdt->timer.data		= (unsigned long)wdt;
+	wdt->timer.expires	= jiffies + HZ;
+
+	dev_info(dev, "initialized\n");
+
+	return 0;
+
+out_unreg:
+	unregister_reboot_notifier(&ptxpmb_wdt_notifier);
+	return rc;
+}
+
+static int ptxpmb_wdt_remove(struct platform_device *pdev)
+{
+	struct watchdog_device *wdog = platform_get_drvdata(pdev);
+
+	unregister_reboot_notifier(&ptxpmb_wdt_notifier);
+	watchdog_unregister_device(wdog);
+
+	return 0;
+}
+
+static const struct of_device_id ptxpmb_wdt_of_ids[] = {
+	{ .compatible = "jnx,ptxpmb-wdt", NULL },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ptxpmb_wdt_of_ids);
+
+static struct platform_driver ptxpmb_wdt_driver = {
+	.driver		= {
+		.name	= DRV_NAME,
+		.owner	= THIS_MODULE,
+		.of_match_table = ptxpmb_wdt_of_ids,
+	},
+
+	.probe	= ptxpmb_wdt_probe,
+	.remove	= ptxpmb_wdt_remove,
+};
+
+static int __init ptxpmb_wdt_init(void)
+{
+	return platform_driver_register(&ptxpmb_wdt_driver);
+}
+
+static void __exit ptxpmb_wdt_exit(void)
+{
+	platform_driver_unregister(&ptxpmb_wdt_driver);
+}
+module_init(ptxpmb_wdt_init);
+module_exit(ptxpmb_wdt_exit);
+
+MODULE_AUTHOR("Guenter Roeck <groeck at juniper.net>");
+MODULE_DESCRIPTION("Juniper PTX PMB CPLD watchdog driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:17:25 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:17:25 +0300
Subject: [PATCH 04/10] watchdog: ptxpmb-wdt: Add ptxpmb-wdt device tree
 bindings
In-Reply-To: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853451-22121-5-git-send-email-pantelis.antoniou@konsulko.com>

From: Georgi Vlaev <gvlaev at juniper.net>

Add binding document for the watchdog driver of PTXPMB CPLD.

Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 .../devicetree/bindings/watchdog/jnx-ptxpmb-wdt.txt     | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/watchdog/jnx-ptxpmb-wdt.txt

diff --git a/Documentation/devicetree/bindings/watchdog/jnx-ptxpmb-wdt.txt b/Documentation/devicetree/bindings/watchdog/jnx-ptxpmb-wdt.txt
new file mode 100644
index 0000000..34b64f6
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/jnx-ptxpmb-wdt.txt
@@ -0,0 +1,17 @@
+Juniper's PTXPMB FPGA watchdog driver
+
+Required properties:
+
+- compatible:	Should be "jnx,ptxpmb-wdt"
+
+Optional properties:
+
+- reg : Specifies base physical address and size of the registers. It is
+  optional since the MFD parent driver supplies it, but can be overridden.
+
+Example:
+
+wdt {
+	compatible = "jnx,ptxpmb-wdt";
+	/* no properties defined */
+};
-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:17:26 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:17:26 +0300
Subject: [PATCH 05/10] i2c/muxes: Juniper's PTXPMB CPLD I2C multiplexer
In-Reply-To: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853451-22121-6-git-send-email-pantelis.antoniou@konsulko.com>

From: Guenter Roeck <groeck at juniper.net>

Introduce Juniper's PTX PMB CPLD I2C multiplexer driver.

Signed-off-by: Debjit Ghosh <dghosh at juniper.net>
Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
Signed-off-by: Guenter Roeck <groeck at juniper.net>
Signed-off-by: JawaharBalaji Thirumalaisamy <jawaharb at juniper.net>
Signed-off-by: Rajat Jain <rajatjain at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 drivers/i2c/muxes/Kconfig          |  11 ++
 drivers/i2c/muxes/Makefile         |   1 +
 drivers/i2c/muxes/i2c-mux-ptxpmb.c | 299 +++++++++++++++++++++++++++++++++++++
 3 files changed, 311 insertions(+)
 create mode 100644 drivers/i2c/muxes/i2c-mux-ptxpmb.c

diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
index e280c8e..f45a9cb 100644
--- a/drivers/i2c/muxes/Kconfig
+++ b/drivers/i2c/muxes/Kconfig
@@ -61,6 +61,17 @@ config I2C_MUX_PINCTRL
 	  This driver can also be built as a module. If so, the module will be
 	  called pinctrl-i2cmux.
 
+config I2C_MUX_PTXPMB
+	tristate "Juniper PTX PMB CPLD I2C multiplexer"
+	depends on MFD_JUNIPER_CPLD
+	default y if MFD_JUNIPER_CPLD
+	help
+	  Select this to enable the Juniper PTX PMB CPLD I2C multiplexer driver
+	  on the relevant Juniper platforms.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-mux-ptxpmb-cpld.
+
 config I2C_MUX_REG
 	tristate "Register-based I2C multiplexer"
 	help
diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile
index 7c267c2..78d8cba 100644
--- a/drivers/i2c/muxes/Makefile
+++ b/drivers/i2c/muxes/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_I2C_MUX_GPIO)	+= i2c-mux-gpio.o
 obj-$(CONFIG_I2C_MUX_PCA9541)	+= i2c-mux-pca9541.o
 obj-$(CONFIG_I2C_MUX_PCA954x)	+= i2c-mux-pca954x.o
 obj-$(CONFIG_I2C_MUX_PINCTRL)	+= i2c-mux-pinctrl.o
+obj-$(CONFIG_I2C_MUX_PTXPMB)	+= i2c-mux-ptxpmb.o
 obj-$(CONFIG_I2C_MUX_REG)	+= i2c-mux-reg.o
 
 ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
diff --git a/drivers/i2c/muxes/i2c-mux-ptxpmb.c b/drivers/i2c/muxes/i2c-mux-ptxpmb.c
new file mode 100644
index 0000000..e8c7aee
--- /dev/null
+++ b/drivers/i2c/muxes/i2c-mux-ptxpmb.c
@@ -0,0 +1,299 @@
+/*
+ * PTX PMB CPLD I2C multiplexer
+ *
+ * Copyright (c) 2012, Juniper Networks.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/i2c-mux.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mfd/ptxpmb_cpld.h>
+#include <linux/io.h>
+#include <linux/of_device.h>
+
+struct i2c_mux_ptxpmb {
+	struct device *dev;
+	struct ptxpmb_mux_data *pdata;
+	struct pmb_boot_cpld __iomem *cpld;
+	struct i2c_adapter *parent;
+	int bus_count;
+	struct i2c_mux_core *muxc;
+};
+
+static const struct of_device_id i2c_mux_ptxpmb_of_match[] = {
+	{ .compatible = "jnx,i2c-mux-ptxpmb-cpld",
+	  .data = (void *)CPLD_TYPE_PTXPMB },
+	{ .compatible = "jnx,i2c-mux-ngpmb-bcpld",
+	  .data = (void *)CPLD_TYPE_NGPMB },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, i2c_mux_ptxpmb_of_match);
+
+#define I2C_GRP_FORCE_EN	0x80
+
+static int i2c_mux_ptxpmb_select(struct i2c_mux_core *muxc, u32 chan)
+{
+	struct i2c_mux_ptxpmb *mux = i2c_mux_priv(muxc);
+	struct ptxpmb_mux_data *pdata = mux->pdata;
+	u8 group, enable, val;
+
+	switch (pdata->cpld_type) {
+	case CPLD_TYPE_PTXPMB:
+		group = chan % pdata->num_channels;
+		enable = 1 << (chan / pdata->num_channels);
+		/*
+		 * Writing into the enable register does not have an effect on
+		 * FPC with P2020. It is necessary for FPC with P5020/P5040.
+		 * The uKernel for SPMB uses undocumented CPLD registers to set
+		 * group enable values (i2c_group_sel_force and
+		 * i2c_group_en_force at offset 0x33 and 0x34). Bit 7 in
+		 * i2c_group_sel_force must be set for this to work.
+		 * i2c_group_en_force is active-low. This applies to SPMB with
+		 * P2020; behavior with P5020/P5040 is unknown at this time.
+		 */
+		if (pdata->use_force) {
+			iowrite8(group | I2C_GRP_FORCE_EN,
+				 &mux->cpld->i2c_group_sel_force);
+			iowrite8(~enable, &mux->cpld->i2c_group_en_force);
+		} else {
+			iowrite8(group, &mux->cpld->i2c_group_sel);
+			ioread8(&mux->cpld->i2c_group_sel);
+			iowrite8(enable, &mux->cpld->i2c_group_en);
+			ioread8(&mux->cpld->i2c_group_en);
+		}
+		break;
+	case CPLD_TYPE_NGPMB:
+		val = ioread8(&mux->cpld->gpio_2);
+		val &= ~NGPMB_I2C_GRP_SEL_MASK;
+		val |= (chan << NGPMB_I2C_GRP_SEL_LSB) & NGPMB_I2C_GRP_SEL_MASK;
+		iowrite8(val, &mux->cpld->gpio_2);
+		break;
+	}
+	udelay(50);
+
+	return 0;
+}
+
+static int i2c_mux_ptxpmb_deselect(struct i2c_mux_core *muxc, u32 chan)
+{
+	struct i2c_mux_ptxpmb *mux = i2c_mux_priv(muxc);
+	u8 val;
+
+	switch (mux->pdata->cpld_type) {
+	case CPLD_TYPE_PTXPMB:
+		/*
+		 * Restore defaults. Note that setting i2c_group_en does not
+		 * have an effect on FPC with P2020, but is necessary for FPC
+		 * with P5020/P5040.
+		 */
+		if (mux->pdata->use_force) {
+			iowrite8(0 | I2C_GRP_FORCE_EN,
+				 &mux->cpld->i2c_group_sel_force);
+			iowrite8(0xff, &mux->cpld->i2c_group_en_force);
+		} else {
+			iowrite8(0, &mux->cpld->i2c_group_sel);
+			ioread8(&mux->cpld->i2c_group_sel);
+			iowrite8(0, &mux->cpld->i2c_group_en);
+			ioread8(&mux->cpld->i2c_group_en);
+		}
+		break;
+	case CPLD_TYPE_NGPMB:
+		/* Use the (unconnected) channel 3 to deselct */
+		val = ioread8(&mux->cpld->gpio_2);
+		val &= ~NGPMB_I2C_GRP_SEL_MASK;
+		val |= (3 << NGPMB_I2C_GRP_SEL_LSB) & NGPMB_I2C_GRP_SEL_MASK;
+		iowrite8(val, &mux->cpld->gpio_2);
+		break;
+	}
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static int i2c_mux_ptxpmb_parse_dt(struct i2c_mux_ptxpmb *mux,
+				   struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+	int ret;
+	struct device_node *adapter_np;
+	struct i2c_adapter *adapter;
+	const struct of_device_id *match;
+
+	if (!np)
+		return 0;
+
+	mux->pdata = devm_kzalloc(dev, sizeof(*mux->pdata), GFP_KERNEL);
+	if (!mux->pdata)
+		return -ENOMEM;
+
+	match = of_match_device(i2c_mux_ptxpmb_of_match, dev);
+	if (match)
+		mux->pdata->cpld_type = (int)(unsigned long)match->data;
+
+	ret = of_property_read_u32(np, "num-enable", &mux->pdata->num_enable);
+	if (ret) {
+		dev_err(dev, "num-enable missing\n");
+		return -ENODEV;
+	}
+
+	ret = of_property_read_u32(np, "num-channels",
+				   &mux->pdata->num_channels);
+	if (ret)
+		mux->pdata->num_channels = 8;
+
+	ret = of_property_read_u32(np, "base-bus-num",
+				   &mux->pdata->base_bus_num);
+	if (ret)
+		mux->pdata->base_bus_num = 0;
+
+	if (of_find_property(np, "use-force", NULL))
+		mux->pdata->use_force = true;
+
+	adapter_np = of_parse_phandle(np, "i2c-parent", 0);
+	if (!adapter_np) {
+		dev_err(dev, "Cannot parse i2c-parent\n");
+		return -ENODEV;
+	}
+	adapter = of_find_i2c_adapter_by_node(adapter_np);
+	if (!adapter) {
+		dev_err(dev, "Cannot find parent bus\n");
+		return -ENODEV;
+	}
+	mux->pdata->parent_bus_num = i2c_adapter_id(adapter);
+	put_device(&adapter->dev);
+
+	return 0;
+}
+#else
+static inline int i2c_mux_ptxpmb_parse_dt(struct i2c_mux_ptxpmb *mux,
+					  struct device *dev)
+{
+	return 0;
+}
+#endif
+
+static int i2c_mux_ptxpmb_probe(struct platform_device *pdev)
+{
+	struct i2c_mux_ptxpmb *mux;
+	struct i2c_mux_core *muxc;
+	int i, ret;
+	struct resource *res;
+	struct device *dev = &pdev->dev;
+
+	mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
+	if (!mux)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, mux);
+
+	mux->dev = dev;
+
+	mux->pdata = dev->platform_data;
+	if (!mux->pdata) {
+		ret = i2c_mux_ptxpmb_parse_dt(mux, dev);
+		if (ret < 0)
+			return ret;
+	}
+	if (!mux->pdata) {
+		dev_err(dev, "No platform / devicetree data\n");
+		return -ENODEV;
+	}
+
+	if (mux->pdata->num_enable <= 0 || mux->pdata->num_enable > 8 ||
+	    mux->pdata->num_channels <= 0 || mux->pdata->num_channels > 8) {
+		dev_err(dev, "Invalid platform data\n");
+		return -EINVAL;
+	}
+
+	mux->bus_count = mux->pdata->num_enable * mux->pdata->num_channels;
+
+	mux->parent = i2c_get_adapter(mux->pdata->parent_bus_num);
+	if (!mux->parent) {
+		dev_err(dev, "Parent adapter (%d) not found\n",
+			mux->pdata->parent_bus_num);
+		return -ENODEV;
+	}
+
+	muxc = i2c_mux_alloc(mux->parent, dev, mux->bus_count, 0, 0,
+			     i2c_mux_ptxpmb_select, i2c_mux_ptxpmb_deselect);
+	if (!muxc) {
+		ret =  -ENOMEM;
+		goto err;
+	}
+	muxc->priv = mux;
+	mux->muxc = muxc;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "No memory resource\n");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	mux->cpld = devm_ioremap_nocache(dev, res->start, resource_size(res));
+	if (!mux->cpld) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	for (i = 0; i < mux->bus_count; i++) {
+		u32 bus = mux->pdata->base_bus_num ?
+			mux->pdata->base_bus_num + i : 0;
+
+		ret = i2c_mux_add_adapter(muxc, bus, i, 0);
+		if (ret) {
+			dev_err(dev, "Failed to add adapter %d\n", i);
+			goto err_del_adapter;
+		}
+	}
+
+	return 0;
+
+err_del_adapter:
+	i2c_mux_del_adapters(mux->muxc);
+err:
+	i2c_put_adapter(mux->parent);
+	return ret;
+}
+
+static int i2c_mux_ptxpmb_remove(struct platform_device *pdev)
+{
+	struct i2c_mux_ptxpmb *mux = platform_get_drvdata(pdev);
+
+	i2c_mux_del_adapters(mux->muxc);
+	i2c_put_adapter(mux->parent);
+
+	return 0;
+}
+
+static struct platform_driver i2c_mux_ptxpmb_driver = {
+	.driver	= {
+		.name	= "i2c-mux-ptxpmb-cpld",
+		.owner	= THIS_MODULE,
+		.of_match_table = i2c_mux_ptxpmb_of_match,
+	},
+	.probe	= i2c_mux_ptxpmb_probe,
+	.remove	= i2c_mux_ptxpmb_remove,
+};
+
+module_platform_driver(i2c_mux_ptxpmb_driver);
+
+MODULE_DESCRIPTION("ptxpmb CPLD I2C multiplexer driver");
+MODULE_AUTHOR("Guenter Roeck <groeck at juniper.net>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:i2c-mux-ptxpmb-cpld");
-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:17:27 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:17:27 +0300
Subject: [PATCH 06/10] i2c: i2c-mux-ptxpmb-cpld: Add device tree bindings
In-Reply-To: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853451-22121-7-git-send-email-pantelis.antoniou@konsulko.com>

From: Georgi Vlaev <gvlaev at juniper.net>

Add binding document for the i2c driver of PTXPMB CPLD.

Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 .../bindings/i2c/jnx,i2c-mux-ptxpmb-cpld.txt       | 50 ++++++++++++++++++++++
 1 file changed, 50 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/i2c/jnx,i2c-mux-ptxpmb-cpld.txt

diff --git a/Documentation/devicetree/bindings/i2c/jnx,i2c-mux-ptxpmb-cpld.txt b/Documentation/devicetree/bindings/i2c/jnx,i2c-mux-ptxpmb-cpld.txt
new file mode 100644
index 0000000..3b201f7
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/jnx,i2c-mux-ptxpmb-cpld.txt
@@ -0,0 +1,50 @@
+* Juniper PTXPMB CPLD I2C Mux
+
+I2C mux on the PTXPMB CPLD on Juniper series of routers.
+
+Required properties:
+
+  - compatible: Must contain one of the following.
+    "jnx,i2c-mux-ptxpmb-cpld", "jnx,i2c-mux-ngpmb-bcpld"
+  - num-enable: Number of muxes to enable.
+
+  The following required properties are defined externally:
+
+  - Standard I2C mux properties. See i2c-mux.txt in this directory.
+  - I2C child bus nodes. See i2c-mux.txt in this directory.
+
+Optional Properties:
+
+  - num-channels: Number of channels. If not present the default is 8.
+  - base-bus-num: Base bus number. If not present it is 0.
+  - use-force: Use the force method of the controller.
+
+
+Example:
+
+cpld-i2c-mux {
+	compatible = "jnx,i2c-mux-ptxpmb-cpld";
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	i2c-parent = <&i2c1>;
+
+	num-enable = <1>;
+
+	i2c at 0 {
+		reg = <0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		/* PMB devices are accessed through FPC */
+
+		temp-sensor at 1a { /* FPC */
+			compatible = "maxim,max6697";
+			reg = <0x1a>;
+			smbus-timeout-disable;
+			resistance-cancellation;
+			alert-mask = <0xff>;
+			over-temperature-mask = <0xff>;
+		};
+	};
+};
-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:17:28 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:17:28 +0300
Subject: [PATCH 07/10] gpio: ptxpmb-cpld: Add support for PTXPMB CPLD's GPIO
In-Reply-To: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853451-22121-8-git-send-email-pantelis.antoniou@konsulko.com>

From: Guenter Roeck <groeck at juniper.net>

Support the GPIO block which is located in PTXPMB CPLDs
on relevant Juniper platforms.

Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
Signed-off-by: Guenter Roeck <groeck at juniper.net>
Signed-off-by: Rajat Jain <rajatjain at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 drivers/gpio/Kconfig            |  11 +++
 drivers/gpio/Makefile           |   1 +
 drivers/gpio/gpio-ptxpmb-cpld.c | 177 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 189 insertions(+)
 create mode 100644 drivers/gpio/gpio-ptxpmb-cpld.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 26ee00f..9c91de6 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -360,6 +360,17 @@ config GPIO_PL061
 	help
 	  Say yes here to support the PrimeCell PL061 GPIO device
 
+config GPIO_PTXPMB_CPLD
+	tristate "PTXPMB CPLD GPIO"
+	depends on MFD_JUNIPER_CPLD
+	default y if MFD_JUNIPER_CPLD
+	help
+	  This driver supports the GPIO interfaces on the PTXPMB CPLD which is
+	  present on the relevant Juniper platforms.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called gpio-ptxpmb-cpld.
+
 config GPIO_PXA
 	bool "PXA GPIO support"
 	depends on ARCH_PXA || ARCH_MMP
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index ab28a2d..d397ea5 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -90,6 +90,7 @@ obj-$(CONFIG_GPIO_PCF857X)	+= gpio-pcf857x.o
 obj-$(CONFIG_GPIO_PCH)		+= gpio-pch.o
 obj-$(CONFIG_GPIO_PISOSR)	+= gpio-pisosr.o
 obj-$(CONFIG_GPIO_PL061)	+= gpio-pl061.o
+obj-$(CONFIG_GPIO_PTXPMB_CPLD)	+= gpio-ptxpmb-cpld.o
 obj-$(CONFIG_GPIO_PXA)		+= gpio-pxa.o
 obj-$(CONFIG_GPIO_RC5T583)	+= gpio-rc5t583.o
 obj-$(CONFIG_GPIO_RDC321X)	+= gpio-rdc321x.o
diff --git a/drivers/gpio/gpio-ptxpmb-cpld.c b/drivers/gpio/gpio-ptxpmb-cpld.c
new file mode 100644
index 0000000..e6fab7c
--- /dev/null
+++ b/drivers/gpio/gpio-ptxpmb-cpld.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2012 Juniper networks
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/gpio.h>
+#include <linux/errno.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
+#include <linux/io.h>
+#include <linux/module.h>
+
+#include <linux/mfd/ptxpmb_cpld.h>
+
+/**
+ * struct ptxpmb_cpld_gpio - GPIO private data structure.
+ * @base:			PCI base address of Memory mapped I/O register.
+ * @dev:			Pointer to device structure.
+ * @gpio:			Data for GPIO infrastructure.
+ */
+struct ptxpmb_cpld_gpio {
+	void __iomem *base;
+	struct device *dev;
+	struct gpio_chip gpio;
+	struct mutex lock;
+};
+
+static u8 *ptxpmb_cpld_gpio_get_addr(struct pmb_boot_cpld *cpld,
+				     unsigned int nr)
+{
+	if (nr < 8)			/* 0..7: reset			*/
+		return &cpld->reset;
+	else if (nr < 16)		/* 8..15: control		*/
+		return &cpld->control;
+	else if (nr < 24)		/* 16..23: gpio1		*/
+		return &cpld->gpio_1;
+	else if (nr < 32)		/* 24..31: gpio2		*/
+		return &cpld->gpio_2;
+	else if (nr < 40)		/* 32..39: gp_reset1		*/
+		return &cpld->gp_reset1;
+	return &cpld->thermal_status;	/* 40..41: thermal status	*/
+}
+
+static void ptxpmb_cpld_gpio_set(struct gpio_chip *gpio, unsigned int nr,
+				 int val)
+{
+	u32 reg;
+	u8 bit = 1 << (nr & 7);
+	struct ptxpmb_cpld_gpio *chip =
+	  container_of(gpio, struct ptxpmb_cpld_gpio, gpio);
+	u8 *addr = ptxpmb_cpld_gpio_get_addr(chip->base, nr);
+
+	mutex_lock(&chip->lock);
+	reg = ioread8(addr);
+	if (val)
+		reg |= bit;
+	else
+		reg &= ~bit;
+
+	iowrite8(reg, addr);
+	mutex_unlock(&chip->lock);
+}
+
+static int ptxpmb_cpld_gpio_get(struct gpio_chip *gpio, unsigned int nr)
+{
+	struct ptxpmb_cpld_gpio *chip = container_of(gpio,
+						     struct ptxpmb_cpld_gpio,
+						     gpio);
+	u8 *addr = ptxpmb_cpld_gpio_get_addr(chip->base, nr);
+	u8 bit = 1 << (nr & 7);
+
+	return !!(ioread8(addr) & bit);
+}
+
+static int ptxpmb_cpld_gpio_direction_output(struct gpio_chip *gpio,
+					     unsigned int nr, int val)
+{
+	return 0;
+}
+
+static int ptxpmb_cpld_gpio_direction_input(struct gpio_chip *gpio,
+					    unsigned int nr)
+{
+	return 0;
+}
+
+static void ptxpmb_cpld_gpio_setup(struct ptxpmb_cpld_gpio *chip)
+{
+	struct gpio_chip *gpio = &chip->gpio;
+
+	gpio->label = dev_name(chip->dev);
+	gpio->owner = THIS_MODULE;
+	gpio->direction_input = ptxpmb_cpld_gpio_direction_input;
+	gpio->get = ptxpmb_cpld_gpio_get;
+	gpio->direction_output = ptxpmb_cpld_gpio_direction_output;
+	gpio->set = ptxpmb_cpld_gpio_set;
+	gpio->dbg_show = NULL;
+	gpio->base = -1;
+	gpio->ngpio = 48;
+	gpio->can_sleep = 0;
+#ifdef CONFIG_OF_GPIO
+	gpio->of_node = chip->dev->of_node;
+#endif
+}
+
+static int ptxpmb_cpld_gpio_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct ptxpmb_cpld_gpio *chip;
+	struct resource *res;
+	struct device *dev = &pdev->dev;
+
+	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+	if (chip == NULL)
+		return -ENOMEM;
+
+	chip->dev = dev;
+	platform_set_drvdata(pdev, chip);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	chip->base = devm_ioremap_nocache(dev, res->start, resource_size(res));
+	if (!chip->base)
+		return -ENOMEM;
+
+	mutex_init(&chip->lock);
+	ptxpmb_cpld_gpio_setup(chip);
+	ret = gpiochip_add(&chip->gpio);
+	if (ret) {
+		dev_err(dev, "CPLD gpio: Failed to register GPIO\n");
+		return ret;
+	}
+	return 0;
+}
+
+static int ptxpmb_cpld_gpio_remove(struct platform_device *pdev)
+{
+	struct ptxpmb_cpld_gpio *chip = platform_get_drvdata(pdev);
+
+	gpiochip_remove(&chip->gpio);
+
+	return 0;
+}
+
+static const struct of_device_id ptxpmb_cpld_gpio_ids[] = {
+	{ .compatible = "jnx,gpio-ptxpmb-cpld", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, ptxpmb_cpld_gpio_ids);
+
+static struct platform_driver ptxpmb_cpld_gpio_driver = {
+	.driver = {
+		.name = "gpio-ptxpmb-cpld",
+		.owner  = THIS_MODULE,
+		.of_match_table = ptxpmb_cpld_gpio_ids,
+	},
+	.probe = ptxpmb_cpld_gpio_probe,
+	.remove = ptxpmb_cpld_gpio_remove,
+};
+
+module_platform_driver(ptxpmb_cpld_gpio_driver);
+
+MODULE_DESCRIPTION("CPLD FPGA GPIO Driver");
+MODULE_LICENSE("GPL");
-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:17:29 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:17:29 +0300
Subject: [PATCH 08/10] gpio: ptxpmb-cpld: Document bindings of PTXPMB's CPLD
 GPIO
In-Reply-To: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853451-22121-9-git-send-email-pantelis.antoniou@konsulko.com>

From: Georgi Vlaev <gvlaev at juniper.net>

Add device tree bindings document for the GPIO driver of
Juniper's PTXPMB/NGPMB CPLD.

Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 .../bindings/gpio/jnx,gpio-ptxpmb-cpld.txt         | 30 ++++++++++++++++++++++
 1 file changed, 30 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/gpio/jnx,gpio-ptxpmb-cpld.txt

diff --git a/Documentation/devicetree/bindings/gpio/jnx,gpio-ptxpmb-cpld.txt b/Documentation/devicetree/bindings/gpio/jnx,gpio-ptxpmb-cpld.txt
new file mode 100644
index 0000000..1122021
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/jnx,gpio-ptxpmb-cpld.txt
@@ -0,0 +1,30 @@
+Juniper PTXPMB CPLD GPIO block
+
+Required properties:
+
+- compatible:
+    Must be "jnx,gpio-ptxpmb-cpld"
+
+- #gpio-cells:
+    Should be <2>.  The first cell is the pin number (within the controller's
+    pin space), and the second is used for the following flags:
+	bit[0]: direction (0 = out, 1 = in)
+	bit[1]: init high
+	bit[2]: active low
+
+- gpio-controller:
+    Specifies that the node is a GPIO controller.
+
+Optional properties:
+
+- reg:
+    Address and length of the register set for the device. Usually supplied by
+    the parent MFD driver
+
+Example:
+
+gpio_cpld: cpld_gpio {
+	compatible = "jnx,gpio-ptxpmb-cpld";
+	#gpio-cells = <2>;
+	gpio-controller;
+};
-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:17:30 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:17:30 +0300
Subject: [PATCH 09/10] mtd: devices: Add driver for memory mapped NVRAM on FPC
In-Reply-To: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853451-22121-10-git-send-email-pantelis.antoniou@konsulko.com>

From: JawaharBalaji Thirumalaisamy <jawaharb at juniper.net>

Add MTD driver for NVRAM on Juniper Gladiator FPC PMB. This driver uses
indirect memory-mapped access facilitated by bootcpld. Requires
cpld_ver >= 0XC6 and DT support.

Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
Signed-off-by: JawaharBalaji Thirumalaisamy <jawaharb at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 drivers/mtd/devices/Kconfig         |  11 +++
 drivers/mtd/devices/Makefile        |   1 +
 drivers/mtd/devices/jnx_pmb_nvram.c | 191 ++++++++++++++++++++++++++++++++++++
 3 files changed, 203 insertions(+)
 create mode 100644 drivers/mtd/devices/jnx_pmb_nvram.c

diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index 58329d2..d4255fb 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -144,6 +144,17 @@ config MTD_LART
 	  not need any mapping/chip driver for LART. This one does it all
 	  for you, so go disable all of those if you enabled some of them (:
 
+config JNX_PMB_NVRAM
+	tristate "Juniper FPC PMB NVRAM Driver"
+	depends on (PTXPMB_COMMON || JNX_PTX_NGPMB)
+	default y if (PTXPMB_COMMON || JNX_PTX_NGPMB)
+	help
+	  This driver adds support for NVRAM on Gladiator 3T FPC which is connected
+	  to the BOOTCPLD (cpld_version >= C6).
+
+	  This driver can also be built as a module. When it is so the name of
+	  the module is ngpmb-nvram.
+
 config MTD_MTDRAM
 	tristate "Test driver using RAM"
 	help
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
index 7912d3a..b407c5fc 100644
--- a/drivers/mtd/devices/Makefile
+++ b/drivers/mtd/devices/Makefile
@@ -18,5 +18,6 @@ obj-$(CONFIG_MTD_BCM47XXSFLASH)	+= bcm47xxsflash.o
 obj-$(CONFIG_MTD_ST_SPI_FSM)    += st_spi_fsm.o
 obj-$(CONFIG_MTD_POWERNV_FLASH)	+= powernv_flash.o
 
+obj-$(CONFIG_JNX_PMB_NVRAM)     += jnx_pmb_nvram.o
 
 CFLAGS_docg3.o			+= -I$(src)
diff --git a/drivers/mtd/devices/jnx_pmb_nvram.c b/drivers/mtd/devices/jnx_pmb_nvram.c
new file mode 100644
index 0000000..8a1e812
--- /dev/null
+++ b/drivers/mtd/devices/jnx_pmb_nvram.c
@@ -0,0 +1,191 @@
+/*
+ * Juniper Networks PTX1K RCB I2CS Boot FPGA MTD driver
+ * FPGA upgrades of the Spartan3AN/XC3S700 based I2CS.
+ *
+ * Copyright (C) 2015 Juniper Networks. All rights reserved.
+ * Author:	JawaharBalaji Thirumalaisamy <jawaharb at juniper.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/delay.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mfd/ptxpmb_cpld.h>
+
+struct nvram_mtd {
+	void __iomem *base;
+	struct device *dev;
+	struct mtd_info mtd;
+	struct mutex lock;
+};
+
+
+static int ram_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+	struct nvram_mtd *nvram = container_of(mtd, struct nvram_mtd, mtd);
+
+	memset((char *)nvram->base + instr->addr, 0xff, instr->len);
+	instr->state = MTD_ERASE_DONE;
+	mtd_erase_callback(instr);
+	return 0;
+}
+
+static int ram_point(struct mtd_info *mtd, loff_t from, size_t len,
+		     size_t *retlen, void **virt, resource_size_t *phys)
+{
+	struct nvram_mtd *nvram = container_of(mtd, struct nvram_mtd, mtd);
+
+	virt = nvram->base + from;
+	*retlen = len;
+	return 0;
+}
+
+static int ram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
+{
+	return 0;
+}
+
+static int ram_read(struct mtd_info *mtd, loff_t from, size_t len,
+		    size_t *retlen, u_char *buf)
+{
+	struct nvram_mtd *nvram = container_of(mtd, struct nvram_mtd, mtd);
+
+	memcpy(buf, nvram->base + from, len);
+	*retlen = len;
+	return 0;
+}
+
+static int ram_write(struct mtd_info *mtd, loff_t to, size_t len,
+		     size_t *retlen, const u_char *buf)
+{
+	struct nvram_mtd *nvram = container_of(mtd, struct nvram_mtd, mtd);
+
+	memcpy((char *)nvram->base + to, buf, len);
+	*retlen = len;
+	return 0;
+}
+
+int nvram_init_mtd_parse(struct platform_device *pdev, struct mtd_info *mtd)
+{
+	struct mtd_part_parser_data ppdata = {};
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	mtd->name = dev_name(dev);
+	mtd->type = MTD_RAM;
+	mtd->flags = MTD_CAP_RAM;
+	mtd->size = 0xFF00;
+	mtd->writesize = 1;
+	mtd->writebufsize = 64; /* Mimic CFI NOR flashes */
+	mtd->erasesize = 0x1000;
+	mtd->owner = THIS_MODULE;
+	mtd->_erase = ram_erase;
+	mtd->_point = ram_point;
+	mtd->_unpoint = ram_unpoint;
+	mtd->_read = ram_read;
+	mtd->_write = ram_write;
+	mtd->_panic_write = ram_write;
+
+	ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
+	if (ret) {
+		dev_err(dev, "mtd_device_parse_register returned %d\n", ret);
+		return ret;
+	}
+	return ret;
+}
+
+static int nvram_probe(struct platform_device *pdev)
+{
+	struct pmb_boot_cpld __iomem *cpld;
+	struct nvram_mtd *nvram;
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	int ret;
+
+	nvram = devm_kzalloc(dev, sizeof(*nvram), GFP_KERNEL);
+	if (!nvram)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "Failed to get nvram mmio resource\n");
+		return -ENOENT;
+	}
+	nvram->base = devm_ioremap_nocache(dev, res->start, resource_size(res));
+	if (!nvram->base) {
+		dev_err(dev, "Cannot map nvram\n");
+		return -EADDRNOTAVAIL;
+	}
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res) {
+		/* Always assume that we need cpld control */
+		dev_err(dev, "Failed to get cpld mmio resource\n");
+		return -ENOENT;
+	}
+	cpld = devm_ioremap_nocache(dev, res->start, resource_size(res));
+	if (!cpld) {
+		dev_err(dev, "Cannot map cpld\n");
+		return -EADDRNOTAVAIL;
+	}
+	nvram->dev = dev;
+	platform_set_drvdata(pdev, nvram);
+	ret = nvram_init_mtd_parse(pdev, &nvram->mtd);
+	if (ret)
+		return ret;
+
+	if (READ_ONCE(cpld->cpld_rev) < 0xC6)
+		dev_info(dev, "NVRAM requires atleast cpld_rev 0XC6\n");
+
+	/* Initialize the window register in the cpld*/
+	WRITE_ONCE(cpld->board.nvram.nv_win, 0x0);
+	dev_info(dev, "Initialized window:0x%x\n",
+			READ_ONCE(cpld->board.nvram.nv_win));
+	return ret;
+}
+
+static int nvram_remove(struct platform_device *pdev)
+{
+	struct nvram_mtd *nvram;
+
+	nvram = platform_get_drvdata(pdev);
+	mtd_device_unregister(&nvram->mtd);
+	return 0;
+}
+
+static const struct of_device_id ngpmb_mtd_ids[] = {
+	{ .compatible = "jnx,ngpmb-nvram", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, ngpmb_mtd_ids);
+
+static struct platform_driver nvram_driver = {
+	.probe  = nvram_probe,
+	.remove = nvram_remove,
+	.driver = {
+		.name = "ngpmb-nvram",
+		.owner = THIS_MODULE,
+		.of_match_table = ngpmb_mtd_ids,
+	},
+};
+
+module_platform_driver(nvram_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("JawaharBalaji Thirumalaisamy <jawaharb at juniper.net>");
+MODULE_DESCRIPTION("EVO PTXPMB CPLD NVRAM Driver");
+MODULE_ALIAS("platform:ngpmb-nvram");
-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:18:28 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:18:28 +0300
Subject: [PATCH 00/10] Introduce Juniper SAM FPGA driver
Message-ID: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>

Add Juniper's SAM FPGA driver. Those FPGAs
are present in Juniper's PTX series of routers.

The MFD driver provices i2c/gpio/mtd/mdio devices.

There are full device tree binding documents for the
master mfd driver and for all slave drivers.

This patchset is against mainline as of today: v4.8-9431-g3477d16
and is dependent on the "Juniper prerequisites" and
"Juniper infrastructure" patchsets sent earlier.

Georgi Vlaev (6):
  mfd: sam: Add documentation for the SAM FPGA
  i2c: i2c-sam: Add device tree bindings
  gpio: sam: Document bindings of SAM FPGA GPIO block
  mtd: flash-sam: Bindings for Juniper's SAM FPGA flash
  net: phy: Add MDIO driver for Juniper's SAM FPGA
  net: mdio-sam: Add device tree documentation for SAM MDIO

Guenter Roeck (2):
  gpio: Introduce SAM gpio driver
  mtd: Add SAM Flash driver

Maryam Seraj (2):
  mfd: Add Juniper SAM FPGA MFD driver
  i2c: Juniper SAM I2C driver

 .../devicetree/bindings/gpio/jnx,gpio-sam.txt      | 110 +++
 .../devicetree/bindings/i2c/i2c-sam-mux.txt        |  20 +
 Documentation/devicetree/bindings/i2c/i2c-sam.txt  |  44 +
 Documentation/devicetree/bindings/mfd/jnx-sam.txt  |  94 ++
 .../devicetree/bindings/mtd/flash-sam.txt          |  31 +
 Documentation/devicetree/bindings/net/mdio-sam.txt |  48 +
 drivers/gpio/Kconfig                               |  11 +
 drivers/gpio/Makefile                              |   1 +
 drivers/gpio/gpio-sam.c                            | 707 +++++++++++++++
 drivers/i2c/busses/Kconfig                         |  11 +
 drivers/i2c/busses/Makefile                        |   1 +
 drivers/i2c/busses/i2c-sam.c                       | 942 +++++++++++++++++++
 drivers/mfd/Kconfig                                |  16 +
 drivers/mfd/Makefile                               |   1 +
 drivers/mfd/sam-core.c                             | 997 +++++++++++++++++++++
 drivers/mtd/devices/Kconfig                        |  11 +
 drivers/mtd/devices/Makefile                       |   1 +
 drivers/mtd/devices/sam-flash.c                    | 642 +++++++++++++
 drivers/net/phy/Kconfig                            |   8 +
 drivers/net/phy/Makefile                           |   1 +
 drivers/net/phy/mdio-sam.c                         | 564 ++++++++++++
 include/linux/mfd/sam.h                            |  30 +
 22 files changed, 4291 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/gpio/jnx,gpio-sam.txt
 create mode 100644 Documentation/devicetree/bindings/i2c/i2c-sam-mux.txt
 create mode 100644 Documentation/devicetree/bindings/i2c/i2c-sam.txt
 create mode 100644 Documentation/devicetree/bindings/mfd/jnx-sam.txt
 create mode 100644 Documentation/devicetree/bindings/mtd/flash-sam.txt
 create mode 100644 Documentation/devicetree/bindings/net/mdio-sam.txt
 create mode 100644 drivers/gpio/gpio-sam.c
 create mode 100644 drivers/i2c/busses/i2c-sam.c
 create mode 100644 drivers/mfd/sam-core.c
 create mode 100644 drivers/mtd/devices/sam-flash.c
 create mode 100644 drivers/net/phy/mdio-sam.c
 create mode 100644 include/linux/mfd/sam.h

-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:18:30 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:18:30 +0300
Subject: [PATCH 02/10] mfd: sam: Add documentation for the SAM FPGA
In-Reply-To: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853518-22264-3-git-send-email-pantelis.antoniou@konsulko.com>

From: Georgi Vlaev <gvlaev at juniper.net>

Add DT bindings document for the SAM MFD device.

Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 Documentation/devicetree/bindings/mfd/jnx-sam.txt | 94 +++++++++++++++++++++++
 1 file changed, 94 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/jnx-sam.txt

diff --git a/Documentation/devicetree/bindings/mfd/jnx-sam.txt b/Documentation/devicetree/bindings/mfd/jnx-sam.txt
new file mode 100644
index 0000000..b4af7ea
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/jnx-sam.txt
@@ -0,0 +1,94 @@
+Device-Tree bindings for Juniper Networks SAM MFD
+
+Required properties:
+
+- compatible - Must be: "jnx,sam"
+
+Optional properties:
+
+- pma-coefficients: A set of tupples containing the configuration of the PMA.
+
+Device                   Description
+------                   -----------
+jnx,i2c-sam		: I2C mux driver
+jnx,gpio-sam		: GPIO block
+jnx,flash-sam		: MTD Flash
+jnx,mdio-sam		: MDIO interfaces
+
+All these optional nodes are described in their respective binding
+documents.
+
+Example node:
+
+pci-0000-10-00.0 {
+	compatible = "jnx,sam";
+	#address-cells = <1>;
+	#size-cells = <0>;
+	pma-coefficients = <4 0x0>;
+
+	i2c-sam at 10 {
+		compatible = "jnx,i2c-sam";
+		mux-channels = <2>;
+		master-offset = <0x10000>;
+	};
+
+	gpiogpqam0: gpio-sam at 10 {
+		compatible = "jnx,gpio-sam";
+		gpio-controller;
+		#gpio-cells = <2>;
+		gpio-count = <297>;
+		interrupt-controller;
+		/*
+		* 1st cell: gpio interrupt status bit
+		* 2nd cell: 1st pin
+		* 3rd cell: # of pins
+		*/
+		gpio-interrupts =
+			<0 0 12>,   /* phy_int_monitor_en [16] */
+			<1 235 24>, /* qsfpp_fpga_int_monitor [17] */
+			<2 259 24>, /* qsfpp_fpga_modprs_monitor [18] */
+			<3 295 1>,  /* si5345_fpga_monitor [19] */
+			<4 294 1>;  /* fpc_pic_int_monitor [20] */
+	};
+
+	flash-sam at 10 {
+		compatible = "jnx,flash-sam";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		partition at 0 {
+		reg = <0x0 0x400000>;
+			label = "pic0-golden";
+			read-only;
+		};
+		partition at 400000 {
+			reg = <0x400000 0x400000>;
+			label = "pic0-user";
+		};
+	};
+
+	mdio-sam at 10 {
+		compatible = "jnx,mdio-sam";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0x40000>;
+
+		/* mii_bus types */
+		mdio0: mdio-sam at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0x0>;
+		};
+
+		mdio1: mdio-sam at 4000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0x4000>;
+		};
+
+		mdio2: mdio-sam at 8000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0x8000>;
+		};
+	};
+};
-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:18:32 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:18:32 +0300
Subject: [PATCH 04/10] i2c: i2c-sam: Add device tree bindings
In-Reply-To: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853518-22264-5-git-send-email-pantelis.antoniou@konsulko.com>

From: Georgi Vlaev <gvlaev at juniper.net>

Add binding document for the i2c driver of SAM FPGA.

Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 .../devicetree/bindings/i2c/i2c-sam-mux.txt        | 20 ++++++++++
 Documentation/devicetree/bindings/i2c/i2c-sam.txt  | 44 ++++++++++++++++++++++
 2 files changed, 64 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/i2c/i2c-sam-mux.txt
 create mode 100644 Documentation/devicetree/bindings/i2c/i2c-sam.txt

diff --git a/Documentation/devicetree/bindings/i2c/i2c-sam-mux.txt b/Documentation/devicetree/bindings/i2c/i2c-sam-mux.txt
new file mode 100644
index 0000000..10ddffa
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-sam-mux.txt
@@ -0,0 +1,20 @@
+Juniper's SAM FPGA I2C accelerator mux
+
+The SAM FPGA I2C mux is present only on Juniper SAM FPGA PTX series
+of routers.
+
+The definition of the i2c sam bus is located in the i2c-sam.txt document.
+
+Required properties:
+- compatible: should be "jnx,i2c-sam-mux".
+- reg: master number and mux number.
+
+Optional properties:
+- speed: If present must be either 100000 or 400000. No other values supported.
+
+Examples:
+
+pe1i2c: i2c-sam-mux at 1,0 {
+	compatible = "jnx,i2c-sam-mux";
+	reg = <1 0>;
+};
diff --git a/Documentation/devicetree/bindings/i2c/i2c-sam.txt b/Documentation/devicetree/bindings/i2c/i2c-sam.txt
new file mode 100644
index 0000000..4830b48
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-sam.txt
@@ -0,0 +1,44 @@
+Juniper's SAM FPGA I2C accelerator
+
+The SAM FPGA accelerator is used to connect the large number of
+I2C muxes that are present on Juniper PTX series of routers.
+While it's an i2c bus, no other devices are located besides
+i2c-sam-mux devices.
+
+The definition of the i2c sam mux is located in the i2c-sam-mux.txt document.
+
+Required properties:
+- compatible: should be "jnx,i2c-sam".
+- #address-cells: should be 2.
+- #size-cells: should be 0.
+- mux-channels: number of mux channels present
+
+Optional properties:
+- reg: offset and length of the register set for the device are optional since
+  typically the register range is provided by the parent SAM MFD device.
+- master-offset: Offset of where the master register memory starts.
+  Default value is 0x8000.
+- reverse-fill: Fill the start entries of transactions in reverse order
+- priority-tables: Use the pre-programmed priority tables in the FPGA
+- i2c-options: list of options to be written to the option field in the
+  FPGA controlling things like SCL push-pull drives, hold-times, etc.
+- bus-range: start of bus master range and number of masters.
+
+Examples:
+
+i2c-sam {
+	compatible = "jnx,i2c-sam";
+	mux-channels = <2>;
+	#size-cells = <0>;
+	#address-cells = <2>;
+
+	/* PE0 */ pe0i2c: i2c-sam-mux at 0,0 {
+		compatible = "jnx,i2c-sam-mux";
+		reg = <0 0>;
+	};
+
+	/* PE1 */ pe1i2c: i2c-sam-mux at 1,0 {
+		compatible = "jnx,i2c-sam-mux";
+		reg = <1 0>;
+	};
+};
-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:18:29 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:18:29 +0300
Subject: [PATCH 01/10] mfd: Add Juniper SAM FPGA MFD driver
In-Reply-To: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853518-22264-2-git-send-email-pantelis.antoniou@konsulko.com>

From: Maryam Seraj <mseraj at juniper.net>

Add Juniper's SAM FPGA multi-function driver.

The SAM FPGAs are present on different FPC/SIB cards from the Juniper's
PTX series of routers. Depending on the card type and FPGA revision,
they include the following functional blocks:

* I2C SAM accelerator - multiple I2C masters and multiplexers
* GPIO
* Flash - hardware wrapper interface for the Altera's EPCS flashes
	(used for configuration flash updates)
* MDIO - multiple MDIO masters

Signed-off-by: Maryam Seraj <mseraj at juniper.net>
Signed-off-by: Debjit Ghosh <dghosh at juniper.net>
Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
Signed-off-by: Guenter Roeck <groeck at juniper.net>
Signed-off-by: Rajat Jain <rajatjain at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 drivers/mfd/Kconfig     |  16 +
 drivers/mfd/Makefile    |   1 +
 drivers/mfd/sam-core.c  | 997 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/mfd/sam.h |  30 ++
 4 files changed, 1044 insertions(+)
 create mode 100644 drivers/mfd/sam-core.c
 create mode 100644 include/linux/mfd/sam.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 438666a..75b46a1 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1355,6 +1355,22 @@ config MFD_JUNIPER_CPLD
 	  This driver can be built as a module. If built as a module it will be
 	  called "ptxpmb-cpld"
 
+config MFD_JUNIPER_SAM
+	tristate "Juniper SAM FPGA"
+	depends on (PTXPMB_COMMON || JNX_PTX_NGPMB)
+	default y if (PTXPMB_COMMON || JNX_PTX_NGPMB)
+	select MFD_CORE
+	select I2C_SAM
+	select GPIO_SAM
+	select MTD_SAM_FLASH
+	select MDIO_SAM
+	help
+	  Select this to enable the SAM FPGA multi-function kernel driver.
+	  This FPGA is used on the PTX FPC board.
+
+	  This driver can be built as a module. If built as a module it will be
+	  called "sam-core"
+
 config MFD_TWL4030_AUDIO
 	bool "TI TWL4030 Audio"
 	depends on TWL4030_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 62decc9..71a8ba6 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -149,6 +149,7 @@ obj-$(CONFIG_AB3100_OTP)	+= ab3100-otp.o
 obj-$(CONFIG_AB8500_DEBUG)	+= ab8500-debugfs.o
 obj-$(CONFIG_AB8500_GPADC)	+= ab8500-gpadc.o
 obj-$(CONFIG_MFD_JUNIPER_CPLD)	+= ptxpmb-cpld-core.o
+obj-$(CONFIG_MFD_JUNIPER_SAM)	+= sam-core.o
 obj-$(CONFIG_MFD_DB8500_PRCMU)	+= db8500-prcmu.o
 # ab8500-core need to come after db8500-prcmu (which provides the channel)
 obj-$(CONFIG_AB8500_CORE)	+= ab8500-core.o ab8500-sysctrl.o
diff --git a/drivers/mfd/sam-core.c b/drivers/mfd/sam-core.c
new file mode 100644
index 0000000..2ea2b1b
--- /dev/null
+++ b/drivers/mfd/sam-core.c
@@ -0,0 +1,997 @@
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/sam.h>
+#include <linux/jnx/pci_ids.h>
+#include <linux/of.h>
+
+#define DRIVER_DESC			"SAM FPGA MFD core driver"
+#define DRIVER_VERSION			"0.02.2"
+#define DRIVER_AUTHOR			"Maryam Seraj <mseraj at juniper.net>"
+
+#define SAM_FPGA_MODULE_NAME		"sam-mfd-core"
+#define FPGA_MEM_SIZE			0x20000
+
+#define SAM_NUM_IRQ			2
+#define SAM_NUM_MFD_CELLS		3
+#define SAM_NUM_RESOURCES		2
+#define SAM_NUM_RESOURCES_NOIRQ		1
+
+/* Minimum SAM revisions needed for i2c irq and PMA support */
+#define SAM_REVISION_I2C_IRQ_MIN	0x0065
+#define SAM_REVISION_PMA_MIN		0x004d
+#define SAM_REVISION_MASK		0x0000ffff
+#define SAM_REVISION(s)			((s)->fpga_rev & SAM_REVISION_MASK)
+
+#define SAM_BOARD_ID_MASK		0x000000ff
+#define SAM_BOARD_ID(s)			((s)->board_id & SAM_BOARD_ID_MASK)
+#define SAM_BOARD_ID_HENDRICKS_FPC	0x00
+#define SAM_BOARD_ID_CFP4		0x00
+#define SAM_BOARD_ID_QSFPP		0x00
+#define SAM_BOARD_ID_GPCAM		0x01
+#define SAM_BOARD_ID_SANGRIA_FPC	0x03
+#define SAM_BOARD_ID_QSFPP_OLD		0x03
+#define SAM_BOARD_ID_24x10GE_PIC	0x0B
+#define SAM_BOARD_ID_GLADIATOR_3T	0x11
+#define SAM_BOARD_ID_MLC		0x21
+
+#define SAM_IMG_ID_MASK			0x000000ff
+#define SAM_IMG_ID_SHIFT		16
+#define SAM_IMG_ID(s)			(((s)->board_id >> SAM_IMG_ID_SHIFT) & \
+					 SAM_IMG_ID_MASK)
+
+#define SAM_IMG_ID_QSFPP		0x00
+#define SAM_IMG_ID_GPCAM		0x01
+#define SAM_IMG_ID_SANGRIA_FPC		0x03
+#define SAM_IMG_ID_QSFPP_OLD		0x03
+#define SAM_IMG_ID_GLADIATOR_3T		0x03
+#define SAM_IMG_ID_HENDRICKS_FPC	0x05
+#define SAM_IMG_ID_24x10GE_PIC		0x0B
+#define SAM_IMG_ID_MLC			0x21
+#define SAM_IMG_ID_CFP4			0x22
+
+#define SANGRIA_FPC_PCIE_BUS		0x20
+
+struct sam_fpga_data {
+	void __iomem *membase;
+	struct pci_dev *pdev;
+	u32 fpga_rev;
+	u32 board_id;
+	u32 pma_lanes;
+	u32 pma_coefficients;
+	int irq_base;
+	u32 i2c_irq_mask;
+	u32 gpio_irq_mask;
+	int gpio_irq_shift;
+	spinlock_t irq_lock;
+	struct mfd_cell mfd_cells[SAM_NUM_MFD_CELLS];
+	struct resource mfd_i2c_resources[SAM_NUM_RESOURCES];
+	struct resource mfd_gpio_resources[SAM_NUM_RESOURCES];
+	struct resource mfd_mtd_resources[SAM_NUM_RESOURCES_NOIRQ];
+};
+
+#define VERSION_ADDR(s)		((s)->membase + 0x000)
+#define BOARD_ID_ADDR(s)	((s)->membase + 0x004)
+#define ICTRL_ADDR(s)		((s)->membase + 0x104)
+#define ISTAT_ADDR(s)		((s)->membase + 0x108)
+
+/* PMA */
+#define SAM_PMA_CONTROL_REG(s)	((s)->membase + 0x40)
+#define SAM_PMA_STATUS_REG(s)	((s)->membase + 0x44)
+
+#define SAM_PMA_CONTROL_WRITE	(1 << 31)
+#define SAM_PMA_CONTROL_READ	(1 << 30)
+#define SAM_PMA_LANE(lane)	(((lane) & 0x07) << 25)
+#define SAM_PMA_COEFF_MASK	((1 << 25) - 1)
+
+#define SAM_PMA_STATUS_BUSY	(1 << 31)
+#define SAM_PMA_STATUS_VALID	(1 << 30)
+
+#define SAM_PMA_RETRIES		40	/* observed to take 20 - 40 uS typ. */
+#define SAM_PMA_WAIT_TIME	10	/* uS */
+
+/* Constants used for FPGA upgrades */
+
+#define SAM_FPGA_FLASH_VALID_BIT		0xA5A5A5A5
+#define SAM_FPGA_FLASH_VALID_BIT_ADDR		0x7F0000
+
+/* FPGA remote upgrade registers */
+#define SAM_FPGA_REMOTE_UPGRADE_TRIG_BIT	0x08000000
+#define SAM_FPGA_REMOTE_UPGRADE_STATUS_BUSY	0x01000000
+#define SAM_FPGA_REMOTE_UPGRADE_READ_PARAM	0x80000000
+#define SAM_FPGA_REMOTE_UPGRADE_WRITE_PARAM	0x40000000
+#define SAM_FPGA_REMOTE_UPGRADE_CONTROL_RESET	0x10000000
+
+#define SAM_FPGA_REMOTE_UPGRADE_PAGE_SEL	(0x04 << 24)
+#define SAM_FPGA_REMOTE_UPGRADE_ANF		(0x05 << 24)
+#define SAM_FPGA_USER_IMAGE_BASE		0x400000
+
+#define SAM_FLASH_BASE				0x0300
+
+#define FLASH_ADDR_REG(x)	((x)->membase + SAM_FLASH_BASE + 0x000)
+#define FLASH_COUNTER_REG(x)	((x)->membase + SAM_FLASH_BASE + 0x004)
+#define FLASH_CONTROL_REG(x)	((x)->membase + SAM_FLASH_BASE + 0x008)
+#define FLASH_STATUS_REG(x)	((x)->membase + SAM_FLASH_BASE + 0x00c)
+#define FLASH_WRITE_DATA_REG(x)	((x)->membase + SAM_FLASH_BASE + 0x100)
+#define FLASH_READ_DATA_REG(x)	((x)->membase + SAM_FLASH_BASE + 0x200)
+
+#define FLASH_STATUS_BUSY	0x01
+
+#define SAM_FLASH_IF_CONTROL_READ	0x00000001
+
+/* Upgrade control and management */
+#define SAM_UPGRADE_BASE	0x0200
+#define UPGRADE_CONTROL_REG(x)	((x)->membase + SAM_UPGRADE_BASE)
+#define UPGRADE_STATUS_REG(x)	((x)->membase + SAM_UPGRADE_BASE + 0x0004)
+
+/* List of discovered SAM devices */
+struct sam_core_list {
+	struct list_head node;
+	unsigned long insertion_time;
+	int bus;
+	int devfn;
+	u32 rev;
+	u32 id;
+};
+
+LIST_HEAD(sam_core_list);
+DEFINE_MUTEX(sam_core_list_mutex);
+
+static int sam_core_update_entry(struct sam_fpga_data *sam)
+{
+	struct sam_core_list *entry = NULL, *e;
+	int ret = 0;
+
+	mutex_lock(&sam_core_list_mutex);
+	list_for_each_entry(e, &sam_core_list, node) {
+		if (e->devfn == sam->pdev->devfn &&
+		    e->bus == sam->pdev->bus->number) {
+			entry = e;
+			break;
+		}
+	}
+
+	if (!entry) {
+		entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+		if (!entry) {
+			ret = -ENOMEM;
+			goto abort;
+		}
+		list_add(&entry->node, &sam_core_list);
+	}
+
+	entry->bus = sam->pdev->bus->number;
+	entry->devfn = sam->pdev->devfn;
+	entry->rev = sam->fpga_rev;
+	entry->id = sam->board_id;
+	entry->insertion_time = jiffies;
+abort:
+	mutex_unlock(&sam_core_list_mutex);
+	return ret;
+}
+
+static bool sam_supports_i2c_irq(struct sam_fpga_data *sam)
+{
+	switch (sam->pdev->device) {
+	case PCI_DEVICE_ID_JNX_SAM_OMEGA:
+		/* Sochu SHAM, Gladiator SIB, Omega SIB */
+		return true;
+	case PCI_DEVICE_ID_JNX_SAM_X:
+		/* Gladiator 3T FPC */
+		return true;
+	case PCI_DEVICE_ID_JNX_PAM:
+		if (SAM_REVISION(sam) >= SAM_REVISION_I2C_IRQ_MIN)
+			return true;
+		return false;
+	case PCI_DEVICE_ID_JNX_SAM:
+	default:
+		/* others depend on image/board ID and FPGA version */
+		break;
+	}
+
+	switch (SAM_IMG_ID(sam)) {
+	case SAM_IMG_ID_QSFPP:
+		/* QSFPP, GPQAM */
+		if (SAM_BOARD_ID(sam) == SAM_BOARD_ID_QSFPP)
+			return true;
+		break;
+	case SAM_IMG_ID_GPCAM:
+		/* GPCAM, GPQ28 */
+		if (SAM_BOARD_ID(sam) == SAM_BOARD_ID_GPCAM)
+			return true;
+		break;
+	case SAM_IMG_ID_HENDRICKS_FPC:
+		/* Hendricks SAM FPGA version 15 still fails */
+		if (SAM_BOARD_ID(sam) == SAM_BOARD_ID_HENDRICKS_FPC)
+			return false;
+		break;
+	case SAM_IMG_ID_24x10GE_PIC:
+		if (SAM_BOARD_ID(sam) == SAM_BOARD_ID_24x10GE_PIC &&
+		    SAM_REVISION(sam) >= SAM_REVISION_I2C_IRQ_MIN)
+			return true;
+		break;
+	case SAM_IMG_ID_SANGRIA_FPC:
+		/*
+		 * Image and board IDs for Sangria FPC and QSFPP are the same.
+		 * Use PCIe bus number for disambiguation.
+		 * Bus number for QSFPP would be 0x10 or 0x30 (PIC bus numbers).
+		 */
+		if (SAM_BOARD_ID(sam) == SAM_BOARD_ID_SANGRIA_FPC &&
+		    SAM_REVISION(sam) >= SAM_REVISION_I2C_IRQ_MIN &&
+		    sam->pdev->bus->number == SANGRIA_FPC_PCIE_BUS)
+			return true;
+		break;
+	default:
+		/*
+		 * For all others, play safe and assume that i2c interrupts
+		 * don't work.
+		 */
+		break;
+	}
+	return false;
+}
+
+static bool sam_supports_msi(struct sam_fpga_data *sam)
+{
+	switch (sam->pdev->device) {
+	case PCI_DEVICE_ID_JNX_SAM_OMEGA:
+		/* Sochu SHAM, Gladiator SIB, Omega SIB */
+		return true;
+	case PCI_DEVICE_ID_JNX_SAM_X:
+		/* Gladiator 3T FPC */
+		return true;
+	case PCI_DEVICE_ID_JNX_PAM:
+		/* unknown */
+		return false;
+	case PCI_DEVICE_ID_JNX_SAM:
+	default:
+		break;
+	}
+
+	switch (SAM_IMG_ID(sam)) {
+	case SAM_IMG_ID_HENDRICKS_FPC:
+		if (SAM_BOARD_ID(sam) == SAM_BOARD_ID_HENDRICKS_FPC)
+			return false;
+		break;
+	case SAM_IMG_ID_24x10GE_PIC:
+		if (SAM_BOARD_ID(sam) == SAM_BOARD_ID_24x10GE_PIC)
+			return false;
+		break;
+	case SAM_IMG_ID_SANGRIA_FPC:
+		/*
+		 * Image and board IDs for Sangria FPC and QSFPP are the same.
+		 * Use PCIe bus number for disambiguation.
+		 */
+		if (SAM_BOARD_ID(sam) == SAM_BOARD_ID_SANGRIA_FPC
+		    && sam->pdev->bus->number == SANGRIA_FPC_PCIE_BUS)
+			return false;
+		break;
+	default:
+		break;
+	}
+	return true;
+}
+
+static bool sam_supports_pma(struct sam_fpga_data *sam)
+{
+	switch (sam->pdev->device) {
+	case PCI_DEVICE_ID_JNX_SAM_OMEGA:
+		/* Sochu SHAM, Gladiator SIB, Omega SIB */
+		/* Note: marked HW use only on SHAM */
+		return true;
+	case PCI_DEVICE_ID_JNX_SAM_X:
+		/* Gladiator 3T FPC */
+		return true;
+	case PCI_DEVICE_ID_JNX_PAM:
+		return false;
+	case PCI_DEVICE_ID_JNX_SAM:
+		break;
+	default:
+		/* play safe */
+		return false;
+	}
+
+	switch (SAM_IMG_ID(sam)) {
+	case SAM_IMG_ID_QSFPP:
+		if (SAM_BOARD_ID(sam) == SAM_BOARD_ID_QSFPP)
+			return true;
+		break;
+	case SAM_IMG_ID_CFP4:
+		if (SAM_BOARD_ID(sam) == SAM_BOARD_ID_CFP4)
+			return true;
+		break;
+	case SAM_IMG_ID_HENDRICKS_FPC:
+		break;
+	case SAM_IMG_ID_24x10GE_PIC:
+		if (SAM_BOARD_ID(sam) == SAM_BOARD_ID_24x10GE_PIC &&
+		    SAM_REVISION(sam) >= SAM_REVISION_PMA_MIN)
+			return true;
+		break;
+	case SAM_IMG_ID_SANGRIA_FPC:
+		/*
+		 * Image and board IDs for Sangria FPC and QSFPP (old)
+		 * are the same. Use PCIe bus number for disambiguation.
+		 */
+		if (SAM_BOARD_ID(sam) == SAM_BOARD_ID_SANGRIA_FPC &&
+		    SAM_REVISION(sam) >= SAM_REVISION_PMA_MIN &&
+		    sam->pdev->bus->number == SANGRIA_FPC_PCIE_BUS)
+			return true;
+		break;
+	default:
+		/* unknown, play safe */
+		break;
+	}
+
+	return false;
+}
+
+/*
+ * Flash access commands (simplified)
+ */
+static bool sam_flash_busy(struct sam_fpga_data *sam)
+{
+	return ioread32(FLASH_STATUS_REG(sam)) & FLASH_STATUS_BUSY;
+}
+
+static int
+sam_flash_read(struct sam_fpga_data *sam, u_int32_t offset, u32 *data)
+{
+	if (sam_flash_busy(sam))
+		return -ETIMEDOUT;
+
+	iowrite32(sizeof(u32) - 1, FLASH_COUNTER_REG(sam));
+	iowrite32(offset, FLASH_ADDR_REG(sam));
+
+	/* trigger the read */
+	iowrite32(SAM_FLASH_IF_CONTROL_READ, FLASH_CONTROL_REG(sam));
+	ioread32(FLASH_CONTROL_REG(sam));
+
+	udelay(50);
+
+	if (sam_flash_busy(sam))
+		return  -ETIMEDOUT;
+
+	*data = ioread32(FLASH_READ_DATA_REG(sam));
+	return 0;
+}
+
+static u32 sam_irq_mask(struct sam_fpga_data *sam, enum sam_irq_type type,
+			u32 mask)
+{
+	switch (type) {
+	case SAM_IRQ_I2C:
+		mask &= sam->i2c_irq_mask;
+		break;
+	case SAM_IRQ_GPIO:
+		mask <<= sam->gpio_irq_shift;
+		mask &= sam->gpio_irq_mask;
+		break;
+	}
+	return mask;
+}
+
+static void sam_enable_irq(struct device *dev, enum sam_irq_type type, int irq,
+			   u32 mask)
+{
+	struct sam_fpga_data *sam = dev_get_drvdata(dev);
+	unsigned long flags;
+	u32 s;
+
+	/* irq is one of the virqs passed to the driver */
+
+	mask = sam_irq_mask(sam, type, mask);
+
+	spin_lock_irqsave(&sam->irq_lock, flags);
+	s = ioread32(ICTRL_ADDR(sam));
+	s |= mask;
+	iowrite32(s, ICTRL_ADDR(sam));
+	ioread32(ICTRL_ADDR(sam));
+	spin_unlock_irqrestore(&sam->irq_lock, flags);
+}
+
+static void sam_disable_irq(struct device *dev, enum sam_irq_type type, int irq,
+			    u32 mask)
+{
+	struct sam_fpga_data *sam = dev_get_drvdata(dev);
+	unsigned long flags;
+	u32 s;
+
+	mask = sam_irq_mask(sam, type, mask);
+
+	spin_lock_irqsave(&sam->irq_lock, flags);
+	s = ioread32(ICTRL_ADDR(sam));
+	s &= ~mask;
+	iowrite32(s, ICTRL_ADDR(sam));
+	ioread32(ICTRL_ADDR(sam));
+	spin_unlock_irqrestore(&sam->irq_lock, flags);
+}
+
+static u32 sam_irq_status(struct device *dev, enum sam_irq_type type, int irq)
+{
+	struct sam_fpga_data *sam = dev_get_drvdata(dev);
+	u32 status;
+
+	status = ioread32(ISTAT_ADDR(sam));
+
+	switch (type) {
+	case SAM_IRQ_I2C:
+		status &= sam->i2c_irq_mask;
+		break;
+	case SAM_IRQ_GPIO:
+		status &= sam->gpio_irq_mask;
+		status >>= sam->gpio_irq_shift;
+		break;
+	}
+	return status;
+}
+
+static void sam_irq_status_clear(struct device *dev, enum sam_irq_type type,
+				 int irq, u32 mask)
+{
+	struct sam_fpga_data *sam = dev_get_drvdata(dev);
+
+	mask = sam_irq_mask(sam, type, mask);
+
+	iowrite32(mask, ISTAT_ADDR(sam));
+	ioread32(ISTAT_ADDR(sam));
+}
+
+static irqreturn_t sam_irq_handler(int irq, void *data)
+{
+	struct sam_fpga_data *sam = data;
+	u32 status, mask;
+	int ret = IRQ_NONE;
+
+	/*
+	 * Shared interrupt handlers are called from the interrupt release
+	 * function, so be careful not to access already released resources.
+	 */
+	if (sam->irq_base) {
+		mask = ioread32(ICTRL_ADDR(sam));
+		status = ioread32(ISTAT_ADDR(sam));
+		status &= mask;
+		if (status & sam->i2c_irq_mask) {	/* i2c interrupt */
+			handle_nested_irq(sam->irq_base);
+			ret = IRQ_HANDLED;
+		}
+		if (status & sam->gpio_irq_mask) {	/* gpio interrupt */
+			handle_nested_irq(sam->irq_base + 1);
+			ret = IRQ_HANDLED;
+		}
+	}
+	return ret;
+}
+
+static int sam_irq_set_affinity(struct irq_data *d,
+				const struct cpumask *affinity, bool force)
+{
+	return 0;
+}
+
+static void noop(struct irq_data *data) { }
+
+static struct irq_chip sam_irq_chip = {
+	.name = "sam-core",
+	.irq_mask = noop,
+	.irq_unmask = noop,
+	.irq_set_affinity = sam_irq_set_affinity,
+};
+
+static int sam_attach_irq(struct sam_fpga_data *sam)
+{
+	int irq_base = irq_alloc_descs(-1, 0, SAM_NUM_IRQ, 0);
+	int irq;
+
+	if (irq_base < 0)
+		return irq_base;
+
+	for (irq = irq_base; irq < irq_base + SAM_NUM_IRQ; irq++) {
+		irq_set_noprobe(irq);
+		irq_set_chip_and_handler(irq, &sam_irq_chip, handle_level_irq);
+		irq_set_chip_data(irq, sam);
+		irq_set_status_flags(irq, IRQ_LEVEL);
+		irq_clear_status_flags(irq, IRQ_NOREQUEST);
+		irq_set_nested_thread(irq, true);
+	}
+	if (sam_supports_i2c_irq(sam)) {
+		sam->mfd_i2c_resources[1].start
+		  = sam->mfd_i2c_resources[1].end = irq_base;
+		sam->mfd_cells[0].num_resources = SAM_NUM_RESOURCES;
+	}
+	sam->mfd_gpio_resources[1].start = sam->mfd_gpio_resources[1].end
+	  = irq_base + 1;
+	sam->mfd_cells[1].num_resources = SAM_NUM_RESOURCES;
+	sam->irq_base = irq_base;
+
+	return 0;
+}
+
+static void sam_detach_irq(struct sam_fpga_data *sam)
+{
+	int irq, irq_base = sam->irq_base;
+
+	if (irq_base) {
+		sam->irq_base = 0;
+		for (irq = irq_base; irq < irq_base + SAM_NUM_IRQ; irq++) {
+			irq_set_handler_data(irq, NULL);
+			irq_set_chip(irq, NULL);
+			irq_set_chip_data(irq, NULL);
+		}
+		irq_free_descs(irq_base, SAM_NUM_IRQ);
+	}
+}
+
+static int sam_fpga_load_wait(struct sam_fpga_data *sam)
+{
+	unsigned long start = jiffies;
+	unsigned long timeout = start + msecs_to_jiffies(2000);
+
+	/* wait for up to two seconds for the command to complete */
+	do {
+		u32 status = ioread32(UPGRADE_STATUS_REG(sam));
+
+		if (!(status & SAM_FPGA_REMOTE_UPGRADE_STATUS_BUSY))
+			return 0;
+
+		usleep_range(500, 1000);
+	} while (time_before(jiffies, timeout));
+
+	return -ETIMEDOUT;
+}
+
+/*
+ * FPGA image download
+ */
+static int sam_fpga_load_image(struct device *dev, struct sam_fpga_data *sam)
+{
+	int ret;
+	u32 valid;
+	struct sam_core_list *entry;
+
+	/*
+	 * If the node exists, we have seen this device before.
+	 * Don't try to re-load it again unless the FPGA version changed,
+	 * a different board was inserted, or the board was inserted
+	 * more than a minute ago.
+	 * This check is necessary to ensure that we don't end up
+	 * in endless attempts to re-load SAM.
+	 */
+	mutex_lock(&sam_core_list_mutex);
+	list_for_each_entry(entry, &sam_core_list, node) {
+		if (entry->devfn == sam->pdev->devfn &&
+		    entry->bus == sam->pdev->bus->number &&
+		    entry->id == sam->board_id &&
+		    entry->rev == sam->fpga_rev &&
+		    time_before(entry->insertion_time, jiffies + HZ * 60)) {
+			mutex_unlock(&sam_core_list_mutex);
+			return 0;
+		}
+	}
+	mutex_unlock(&sam_core_list_mutex);
+
+	ret = sam_flash_read(sam, SAM_FPGA_FLASH_VALID_BIT_ADDR, &valid);
+	if (ret < 0 || valid != SAM_FPGA_FLASH_VALID_BIT)
+		return 0;
+
+	/* reset state machine and request upgrade */
+	iowrite32(SAM_FPGA_REMOTE_UPGRADE_CONTROL_RESET,
+		  UPGRADE_CONTROL_REG(sam));
+	usleep_range(10000, 20000);
+
+	iowrite32(SAM_FPGA_REMOTE_UPGRADE_WRITE_PARAM |
+		  SAM_FPGA_REMOTE_UPGRADE_PAGE_SEL |
+		  SAM_FPGA_USER_IMAGE_BASE,
+		  UPGRADE_CONTROL_REG(sam));
+	ioread32(UPGRADE_CONTROL_REG(sam));
+
+	ret = sam_fpga_load_wait(sam);
+	if (ret)
+		return 0;
+
+#if 0
+	/*
+	 * Request fallback to golden image if upgrade fails
+	 * Commented out in Sangria code, kept for reference
+	 */
+	iowrite32(SAM_FPGA_REMOTE_UPGRADE_WRITE_PARAM |
+		  SAM_FPGA_REMOTE_UPGRADE_ANF | 1,
+		  UPGRADE_CONTROL_REG(sam));
+
+	ret = sam_fpga_load_wait(sam);
+	if (ret)
+		return ret;
+#endif
+
+	/* Trigger reconfiguration */
+	iowrite32(SAM_FPGA_REMOTE_UPGRADE_TRIG_BIT, UPGRADE_CONTROL_REG(sam));
+
+	sam_core_update_entry(sam);
+
+	/*
+	 * With a clean infrastructure, we could return -EPROBEDEFER here and
+	 * leave it up to the PCIe hotplug driver to detect that the device has
+	 * been removed and re-inserted. Without such a driver, user space
+	 * will have to take care of it.
+	 */
+	return -ENODEV;
+}
+
+static ssize_t version_show(struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{
+	struct sam_fpga_data *sam = dev_get_drvdata(dev);
+
+	return sprintf(buf, "0x%x\n", sam->fpga_rev);
+}
+
+static ssize_t board_id_show(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct sam_fpga_data *sam = dev_get_drvdata(dev);
+
+	return sprintf(buf, "0x%x\n", sam->board_id);
+}
+
+static DEVICE_ATTR(version, S_IRUGO, version_show, NULL);
+static DEVICE_ATTR(board_id, S_IRUGO, board_id_show, NULL);
+
+/* Initialize PMA coefficients */
+
+static int sam_pma_wait(struct sam_fpga_data *sam)
+{
+	int i;
+	u32 status;
+
+	for (i = 0; i < SAM_PMA_RETRIES; i++) {
+		udelay(SAM_PMA_WAIT_TIME);
+		status = ioread32(SAM_PMA_STATUS_REG(sam));
+		if (!(status & SAM_PMA_STATUS_BUSY))
+			return (status & SAM_PMA_STATUS_VALID) ? 0 : -EIO;
+	}
+	return -ETIMEDOUT;
+}
+
+static int sam_pma_write(struct sam_fpga_data *sam, u32 data, void *addr)
+{
+	iowrite32(data, addr);
+	ioread32(addr);
+	return sam_pma_wait(sam);
+}
+
+static int sam_pma_init(struct sam_fpga_data *sam)
+{
+	int lane;
+	int err;
+
+	for (lane = 0; lane < sam->pma_lanes; lane++) {
+		err = sam_pma_write(sam,
+				    SAM_PMA_CONTROL_READ | SAM_PMA_LANE(lane),
+				    SAM_PMA_CONTROL_REG(sam));
+		if (err)
+			return err;
+		err = sam_pma_write(sam,
+				    SAM_PMA_CONTROL_WRITE | SAM_PMA_LANE(lane) |
+				    sam->pma_coefficients,
+				    SAM_PMA_CONTROL_REG(sam));
+		if (err)
+			return err;
+	}
+	return 0;
+}
+
+static int sam_fpga_of_init(struct device *dev, struct sam_fpga_data *sam)
+{
+	int len;
+	const __be32 *pma_coefficients;
+
+	if (!dev->of_node) {
+		dev_warn(dev, "No SAM FDT node\n");
+		return of_have_populated_dt() ? -ENODEV : 0;
+	}
+
+	pma_coefficients = of_get_property(of_get_parent(dev->of_node),
+					   "pma-coefficients", &len);
+	if (pma_coefficients) {
+		if (len != 2 * sizeof(u32))
+			return -EINVAL;
+		sam->pma_lanes = be32_to_cpu(pma_coefficients[0]);
+		sam->pma_coefficients = be32_to_cpu(pma_coefficients[1]);
+
+		if (sam->pma_lanes > 7 ||
+		    (sam->pma_coefficients & ~SAM_PMA_COEFF_MASK))
+			return -EINVAL;
+	}
+	return 0;
+}
+
+/* SAM drivers interrupt handling */
+static struct sam_platform_data sam_plat_data = {
+	.enable_irq = sam_enable_irq,
+	.disable_irq = sam_disable_irq,
+	.irq_status = sam_irq_status,
+	.irq_status_clear = sam_irq_status_clear,
+	.i2c_mux_channels = 2,		/* MLC default */
+};
+
+/* Add a single cell from OF */
+static int sam_mfd_of_add_cell(struct device *dev, const char *compatible,
+				int id, struct resource *base)
+{
+	struct device_node *np;
+	struct mfd_cell cell = {0};
+	struct resource res = {0};
+	u32 reg;
+	int ret;
+
+	/* Note:
+	 * Due to limitations in the MFD core, we can't have more
+	 * than one compatible node - we can't match properly and bind
+	 * the of_nodes to mfd cells.
+	 */
+	np = of_find_compatible_node(dev->of_node, NULL, compatible);
+	if (!np)
+		return -ENODEV;
+
+	ret = of_property_read_u32(np, "reg", &reg);
+	if (ret)
+		return ret;
+
+	res.start = reg;
+	res.end = resource_size(base) - 1 - reg;
+	res.flags = IORESOURCE_MEM;
+	cell.name = np->name;
+	cell.of_compatible = compatible;
+	cell.resources = &res;
+	cell.num_resources = 1;
+
+	return mfd_add_devices(dev, id, &cell, 1, base, 0, NULL);
+}
+
+static void sam_init_irq_masks(struct sam_fpga_data *sam)
+{
+	if ((SAM_IMG_ID(sam) == SAM_IMG_ID_HENDRICKS_FPC &&
+	     SAM_BOARD_ID(sam) == SAM_BOARD_ID_HENDRICKS_FPC) ||
+	    (SAM_IMG_ID(sam) == SAM_IMG_ID_24x10GE_PIC &&
+	     SAM_BOARD_ID(sam) == SAM_BOARD_ID_24x10GE_PIC) ||
+	    (SAM_IMG_ID(sam) == SAM_IMG_ID_SANGRIA_FPC &&
+	     SAM_BOARD_ID(sam) == SAM_BOARD_ID_SANGRIA_FPC &&
+	     sam->pdev->bus->number == SANGRIA_FPC_PCIE_BUS)) {
+		sam->i2c_irq_mask = 0x000000ff;
+		sam->gpio_irq_mask = 0x1ffff000;
+		sam->gpio_irq_shift = 12;
+	} else {
+		sam->i2c_irq_mask = 0x0000ffff;
+		sam->gpio_irq_mask = 0xffff0000;
+		sam->gpio_irq_shift = 16;
+	}
+}
+
+static int sam_fpga_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	int err;
+	struct sam_fpga_data *sam;
+	struct device *dev = &pdev->dev;
+
+	sam = devm_kzalloc(dev, sizeof(*sam), GFP_KERNEL);
+	if (sam == NULL)
+		return -ENOMEM;
+
+	err = sam_fpga_of_init(dev, sam);
+	if (err < 0)
+		return err;
+
+	err = pci_enable_device(pdev);
+	if (err < 0) {
+		dev_err(dev, "pci_enable_device() failed: %d\n", err);
+		return err;
+	}
+
+	err = pci_request_regions(pdev, SAM_FPGA_MODULE_NAME);
+	if (err < 0) {
+		dev_err(dev, "pci_request_regions() failed: %d\n",
+			err);
+		goto err_disable;
+	}
+
+	sam->membase = pci_ioremap_bar(pdev, 0);
+	if (!sam->membase) {
+		dev_err(dev, "pci_ioremap_bar() failed\n");
+		err = -ENOMEM;
+		goto err_release;
+	}
+
+	sam->pdev = pdev;
+	pci_set_drvdata(pdev, sam);
+
+	/*
+	 * Try to upgrade FPGA image to user image if revision is too old
+	 * to support I2C interrupts
+	 */
+	sam->fpga_rev = ioread32(VERSION_ADDR(sam));
+	sam->board_id = ioread32(BOARD_ID_ADDR(sam));
+
+	if (!sam_supports_i2c_irq(sam)) {
+		dev_info(dev,
+			 "FPGA revision %u.%u doesn't support I2C interrupts, attempting firmware download\n",
+			 (sam->fpga_rev >> 8) & 0xff, sam->fpga_rev & 0xff);
+		err = sam_fpga_load_image(dev, sam);
+		if (err)
+			goto err_unmap;
+	}
+
+	if (sam_supports_pma(sam) && sam->pma_lanes) {
+		err = sam_pma_init(sam);
+		if (err < 0)
+			goto err_unmap;
+	}
+
+	sam_init_irq_masks(sam);
+
+	spin_lock_init(&sam->irq_lock);
+
+	sam->mfd_cells[0].name = "i2c-sam";
+	sam->mfd_cells[0].num_resources = SAM_NUM_RESOURCES_NOIRQ;
+	sam->mfd_cells[0].resources = sam->mfd_i2c_resources;
+	sam->mfd_cells[0].of_compatible = "jnx,i2c-sam";
+	sam->mfd_cells[0].platform_data = &sam_plat_data;
+	sam->mfd_cells[0].pdata_size = sizeof(sam_plat_data);
+
+	sam->mfd_i2c_resources[0].end = FPGA_MEM_SIZE - 1;
+	sam->mfd_i2c_resources[0].flags = IORESOURCE_MEM;
+	sam->mfd_i2c_resources[1].flags = IORESOURCE_IRQ;
+
+	sam->mfd_cells[1].name = "gpio-sam";
+	sam->mfd_cells[1].num_resources = SAM_NUM_RESOURCES_NOIRQ;
+	sam->mfd_cells[1].resources = sam->mfd_gpio_resources;
+	sam->mfd_cells[1].of_compatible = "jnx,gpio-sam";
+	sam->mfd_cells[1].platform_data = &sam_plat_data;
+	sam->mfd_cells[1].pdata_size = sizeof(sam_plat_data);
+
+	sam->mfd_gpio_resources[0].end = FPGA_MEM_SIZE - 1;
+	sam->mfd_gpio_resources[0].flags = IORESOURCE_MEM;
+	sam->mfd_gpio_resources[1].flags = IORESOURCE_IRQ;
+
+	sam->mfd_cells[2].name = "flash-sam";
+	sam->mfd_cells[2].num_resources = SAM_NUM_RESOURCES_NOIRQ;
+	sam->mfd_cells[2].resources = sam->mfd_mtd_resources;
+	sam->mfd_cells[2].of_compatible = "jnx,flash-sam";
+
+	sam->mfd_mtd_resources[0].end = FPGA_MEM_SIZE - 1;
+	sam->mfd_mtd_resources[0].flags = IORESOURCE_MEM;
+
+	/* Enable MSI, if it is supported by this version of SAM */
+	if (sam_supports_msi(sam) && !pci_enable_msi(pdev))
+		pci_set_master(pdev);
+
+	if (pdev->irq) {
+		err = devm_request_threaded_irq(dev, pdev->irq, NULL,
+						sam_irq_handler,
+						IRQF_ONESHOT,
+						dev_driver_string(dev), sam);
+		if (err) {
+			dev_err(dev, "failed to request irq %d\n", pdev->irq);
+			goto err_unmap;
+		}
+		err = sam_attach_irq(sam);
+		if (err) {
+			dev_err(dev, "failed to attach irq %d\n", pdev->irq);
+			goto err_irq;
+		}
+	}
+
+	err = mfd_add_devices(dev, pdev->bus->number, sam->mfd_cells,
+			      ARRAY_SIZE(sam->mfd_cells), &pdev->resource[0],
+			      0, NULL);
+	if (err < 0)
+		goto err_irq_attach;
+
+	/*
+	 * We don't know if this SAM supports MDIO.
+	 * Add client only if compatible node exists.
+	 */
+	sam_mfd_of_add_cell(dev, "jnx,mdio-sam", pdev->bus->number,
+				&pdev->resource[0]);
+
+	err = device_create_file(&pdev->dev, &dev_attr_version);
+	if (err < 0)
+		goto err_remove;
+
+	err = device_create_file(&pdev->dev, &dev_attr_board_id);
+	if (err < 0)
+		goto err_remove_files;
+
+	dev_info(dev,
+		 "SAM Jspec version %u.%u FPGA version %u.%u image 0x%x board 0x%x inserted\n",
+		 (sam->fpga_rev >> 24) & 0xff, (sam->fpga_rev >> 16) & 0xff,
+		 (sam->fpga_rev >> 8) & 0xff, sam->fpga_rev & 0xff,
+		 (sam->board_id >> 16) & 0xff,
+		 sam->board_id & 0xff);
+
+	return 0;
+
+err_remove_files:
+	device_remove_file(&pdev->dev, &dev_attr_version);
+	device_remove_file(&pdev->dev, &dev_attr_board_id);
+err_remove:
+	mfd_remove_devices(dev);
+err_irq_attach:
+	if (pdev->irq)
+		sam_detach_irq(sam);
+err_irq:
+	/* Call free_irq() before pci_disable_msi() */
+	if (pdev->irq)
+		devm_free_irq(&pdev->dev, pdev->irq, sam);
+err_unmap:
+	pci_disable_msi(pdev);
+	pci_iounmap(pdev, sam->membase);
+err_release:
+	pci_release_regions(pdev);
+err_disable:
+	pci_disable_device(pdev);
+	return err;
+}
+
+static void sam_fpga_remove(struct pci_dev *pdev)
+{
+	struct sam_fpga_data *sam = pci_get_drvdata(pdev);
+
+	mfd_remove_devices(&pdev->dev);
+	device_remove_file(&pdev->dev, &dev_attr_version);
+	device_remove_file(&pdev->dev, &dev_attr_board_id);
+	sam_disable_irq(&pdev->dev, SAM_IRQ_I2C, sam->irq_base, 0xffffffff);
+	sam_disable_irq(&pdev->dev, SAM_IRQ_GPIO, sam->irq_base, 0xffffffff);
+	if (pdev->irq) {
+		sam_detach_irq(sam);
+		devm_free_irq(&pdev->dev, pdev->irq, sam);
+	}
+	pci_disable_msi(pdev);
+	pci_iounmap(pdev, sam->membase);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+}
+
+static struct pci_device_id sam_fpga_ids[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_JUNIPER, PCI_DEVICE_ID_JNX_SAM) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_JUNIPER, PCI_DEVICE_ID_JNX_SAM_X) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_JUNIPER, PCI_DEVICE_ID_JNX_SAM_OMEGA) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_JUNIPER, PCI_DEVICE_ID_JNX_PAM) },
+	{ }
+};
+MODULE_DEVICE_TABLE(pci, sam_fpga_ids);
+
+static struct pci_driver sam_fpga_driver = {
+	.name = SAM_FPGA_MODULE_NAME,
+	.id_table = sam_fpga_ids,
+	.probe = sam_fpga_probe,
+	.remove = sam_fpga_remove,
+};
+
+static int __init sam_fpga_init(void)
+{
+	pr_info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
+
+	return pci_register_driver(&sam_fpga_driver);
+}
+
+static void __exit sam_fpga_exit(void)
+{
+	struct sam_core_list *entry, *t;
+
+	list_for_each_entry_safe(entry, t, &sam_core_list, node) {
+		list_del(&entry->node);
+		kfree(entry);
+	}
+	pci_unregister_driver(&sam_fpga_driver);
+}
+
+module_init(sam_fpga_init);
+module_exit(sam_fpga_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR(DRIVER_AUTHOR);
diff --git a/include/linux/mfd/sam.h b/include/linux/mfd/sam.h
new file mode 100644
index 0000000..d41b9fb
--- /dev/null
+++ b/include/linux/mfd/sam.h
@@ -0,0 +1,30 @@
+/*
+ * Functions exported from SAM mfd driver
+ *     Copyright (c) 2013 Juniper Networks <groeck at juniper.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef SAM_H
+#define SAM_H
+
+struct device;
+
+enum sam_irq_type {
+	SAM_IRQ_I2C = 0,
+	SAM_IRQ_GPIO,
+};
+
+struct sam_platform_data {
+	void (*enable_irq)(struct device *dev, enum sam_irq_type, int irq,
+			   u32 mask);
+	void (*disable_irq)(struct device *dev, enum sam_irq_type, int irq,
+			    u32 mask);
+	u32 (*irq_status)(struct device *dev, enum sam_irq_type, int irq);
+	void (*irq_status_clear)(struct device *dev, enum sam_irq_type, int irq,
+				 u32 mask);
+	int i2c_mux_channels;
+};
+#endif /* SAM_H */
-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:18:33 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:18:33 +0300
Subject: [PATCH 05/10] gpio: Introduce SAM gpio driver
In-Reply-To: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853518-22264-6-git-send-email-pantelis.antoniou@konsulko.com>

From: Guenter Roeck <groeck at juniper.net>

The SAM GPIO IP block is present in the Juniper PTX series
of routers as part of the SAM FPGA.

Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
Signed-off-by: Guenter Roeck <groeck at juniper.net>
Signed-off-by: Rajat Jain <rajatjain at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 drivers/gpio/Kconfig    |  11 +
 drivers/gpio/Makefile   |   1 +
 drivers/gpio/gpio-sam.c | 707 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 719 insertions(+)
 create mode 100644 drivers/gpio/gpio-sam.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 9c91de6..c25dbe9 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -384,6 +384,17 @@ config GPIO_RCAR
 	help
 	  Say yes here to support GPIO on Renesas R-Car SoCs.
 
+config GPIO_SAM
+	tristate "SAM FPGA GPIO"
+	depends on MFD_JUNIPER_SAM
+	default y if MFD_JUNIPER_SAM
+	help
+	  This driver supports the GPIO interfaces on the SAM FPGA which is
+	  present on the relevant Juniper platforms.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called gpio-sam.
+
 config GPIO_SPEAR_SPICS
 	bool "ST SPEAr13xx SPI Chip Select as GPIO support"
 	depends on PLAT_SPEAR
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index d397ea5..6691d8c 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -96,6 +96,7 @@ obj-$(CONFIG_GPIO_RC5T583)	+= gpio-rc5t583.o
 obj-$(CONFIG_GPIO_RDC321X)	+= gpio-rdc321x.o
 obj-$(CONFIG_GPIO_RCAR)		+= gpio-rcar.o
 obj-$(CONFIG_ARCH_SA1100)	+= gpio-sa1100.o
+obj-$(CONFIG_GPIO_SAM)		+= gpio-sam.o
 obj-$(CONFIG_GPIO_SCH)		+= gpio-sch.o
 obj-$(CONFIG_GPIO_SCH311X)	+= gpio-sch311x.o
 obj-$(CONFIG_GPIO_SODAVILLE)	+= gpio-sodaville.o
diff --git a/drivers/gpio/gpio-sam.c b/drivers/gpio/gpio-sam.c
new file mode 100644
index 0000000..5082050
--- /dev/null
+++ b/drivers/gpio/gpio-sam.c
@@ -0,0 +1,707 @@
+/*
+ * Copyright (C) 2012 - 2015 Juniper Networks
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/errno.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/mfd/sam.h>
+
+/* gpio status/configuration */
+#define SAM_GPIO_NEG_EDGE	(1 << 8)
+#define SAM_GPIO_NEG_EDGE_EN	(1 << 7)
+#define SAM_GPIO_POS_EDGE	(1 << 6)
+#define SAM_GPIO_POS_EDGE_EN	(1 << 5)
+#define SAM_GPIO_BLINK		(1 << 4)
+#define SAM_GPIO_OUT		(1 << 3)
+#define SAM_GPIO_OUT_TS		(1 << 2)
+#define SAM_GPIO_DEBOUNCE_EN	(1 << 1)
+#define SAM_GPIO_IN		(1 << 0)
+
+#define SAM_GPIO_BASE		0x1000
+
+#define SAM_MAX_NGPIO		512
+
+#define SAM_GPIO_ADDR(addr, nr)	((addr) + SAM_GPIO_BASE + (nr) * sizeof(u32))
+
+struct sam_gpio_irq_group {
+	int start;		/* 1st gpio pin */
+	int count;		/* # of pins in group */
+	int num_enabled;	/* # of enabled interrupts */
+};
+
+/**
+ * struct sam_gpio - GPIO private data structure.
+ * @base:			PCI base address of Memory mapped I/O register.
+ * @dev:			Pointer to device structure.
+ * @gpio:			Data for GPIO infrastructure.
+ * @gpio_base:			1st gpio pin
+ * @gpio_count:			# of gpio pins
+ * @irq_lock:			Lock used by interrupt subsystem
+ * @domain:			Pointer to interrupt domain
+ * @irq:			Interrupt # from parent
+ * @irq_high:			Second interrupt # from parent
+ *				(currently unused)
+ * @irq_group:			Interrupt group descriptions
+ *				(one group per interrupt bit)
+ * @irq_type:			The interrupt type for each gpio pin
+ */
+struct sam_gpio {
+	void __iomem *base;
+	struct device *dev;
+	struct gpio_chip gpio;
+	int gpio_base;
+	int gpio_count;
+	struct mutex irq_lock;
+	struct irq_domain *domain;
+	int irq;
+	int irq_high;
+	struct sam_gpio_irq_group irq_group[18];
+	u8 irq_type[SAM_MAX_NGPIO];
+	struct sam_platform_data *pdata;
+	const char **names;
+	u32 *export_flags;
+};
+#define to_sam(chip)	container_of((chip), struct sam_gpio, gpio)
+
+static void sam_gpio_bitop(struct sam_gpio *sam, unsigned int nr,
+			   u32 bit, bool set)
+{
+	u32 reg;
+
+	reg = ioread32(SAM_GPIO_ADDR(sam->base, nr));
+	if (set)
+		reg |= bit;
+	else
+		reg &= ~bit;
+	iowrite32(reg, SAM_GPIO_ADDR(sam->base, nr));
+	ioread32(SAM_GPIO_ADDR(sam->base, nr));
+}
+
+static int sam_gpio_debounce(struct gpio_chip *chip, unsigned int nr,
+			     unsigned int debounce)
+{
+	struct sam_gpio *sam = to_sam(chip);
+
+	sam_gpio_bitop(sam, nr, SAM_GPIO_DEBOUNCE_EN, debounce);
+
+	return 0;
+}
+
+static void sam_gpio_set(struct gpio_chip *chip, unsigned int nr, int val)
+{
+	struct sam_gpio *sam = to_sam(chip);
+
+	sam_gpio_bitop(sam, nr, SAM_GPIO_OUT, val);
+}
+
+static int sam_gpio_get(struct gpio_chip *chip, unsigned int nr)
+{
+	struct sam_gpio *sam = to_sam(chip);
+
+	return !!(ioread32(SAM_GPIO_ADDR(sam->base, nr)) & SAM_GPIO_IN);
+}
+
+static int sam_gpio_direction_output(struct gpio_chip *chip, unsigned int nr,
+				     int val)
+{
+	struct sam_gpio *sam = to_sam(chip);
+
+	sam_gpio_bitop(sam, nr, SAM_GPIO_OUT, val);
+	sam_gpio_bitop(sam, nr, SAM_GPIO_OUT_TS, false);
+	return 0;
+}
+
+static int sam_gpio_direction_input(struct gpio_chip *chip, unsigned int nr)
+{
+	struct sam_gpio *sam = to_sam(chip);
+
+	sam_gpio_bitop(sam, nr, SAM_GPIO_OUT_TS, true);
+	sam_gpio_bitop(sam, nr, SAM_GPIO_OUT, false);
+	return 0;
+}
+
+static void sam_gpio_setup(struct sam_gpio *sam)
+{
+	struct gpio_chip *chip = &sam->gpio;
+
+	chip->parent = sam->dev;
+	chip->label = dev_name(sam->dev);
+	chip->owner = THIS_MODULE;
+	chip->direction_input = sam_gpio_direction_input;
+	chip->get = sam_gpio_get;
+	chip->direction_output = sam_gpio_direction_output;
+	chip->set = sam_gpio_set;
+	chip->set_debounce = sam_gpio_debounce;
+	chip->dbg_show = NULL;
+	chip->base = sam->gpio_base;
+	chip->ngpio = sam->gpio_count;
+#ifdef CONFIG_OF_GPIO
+	chip->of_node = sam->dev->of_node;
+#endif
+	chip->names = sam->names;
+}
+
+static int sam_of_get_exports(struct device *dev, struct sam_gpio *sam)
+{
+	struct device_node *child, *exports;
+	int err = 0;
+
+	if (dev->of_node == NULL)
+		return 0;	/* No FDT node, we are done */
+
+	exports = of_get_child_by_name(dev->of_node, "gpio-exports");
+	if (exports == NULL)
+		return 0;	/* No exports, we are done */
+
+	if (of_get_child_count(exports) == 0)
+		return 0;	/* No children, we are done */
+
+	sam->names = devm_kzalloc(dev, sizeof(char *) * sam->gpio_count,
+				  GFP_KERNEL);
+	if (sam->names == NULL) {
+		err = -ENOMEM;
+		goto error;
+	}
+	sam->export_flags =
+		devm_kzalloc(dev, sizeof(u32) * sam->gpio_count, GFP_KERNEL);
+	if (sam->export_flags == NULL) {
+		err = -ENOMEM;
+		goto error;
+	}
+	for_each_child_of_node(exports, child) {
+		const char *label;
+		u32 pin, flags;
+
+		label = of_get_property(child, "label", NULL) ? : child->name;
+		err = of_property_read_u32_index(child, "pin", 0, &pin);
+		if (err)
+			break;
+		if (pin >= sam->gpio_count) {
+			err = -EINVAL;
+			break;
+		}
+		err = of_property_read_u32_index(child, "pin", 1, &flags);
+		if (err)
+			break;
+		/*
+		 * flags:
+		 * GPIOF_DIR_IN			bit 0=1
+		 * GPIOF_DIR_OUT		bit 0=0
+		 *	GPIOF_INIT_HIGH		bit 1=1
+		 * GPIOF_ACTIVE_LOW		bit 2=1
+		 * GPIOF_OPEN_DRAIN		bit 3=1
+		 * GPIOF_OPEN_SOURCE		bit 4=1
+		 * GPIOF_EXPORT			bit 5=1
+		 * GPIOF_EXPORT_CHANGEABLE	bit 6=1
+		 */
+		sam->names[pin] = label;
+		sam->export_flags[pin] = flags;
+	}
+error:
+	of_node_put(exports);
+	return err;
+}
+
+static int sam_gpio_of_init(struct device *dev, struct sam_gpio *sam)
+{
+	int err;
+	u32 val;
+	const u32 *igroup;
+	u32 group, start, count;
+	int i, iglen, ngpio;
+
+	if (of_have_populated_dt() && !dev->of_node) {
+		dev_err(dev, "No device node\n");
+		return -ENODEV;
+	}
+
+	err = of_property_read_u32(dev->of_node, "gpio-base", &val);
+	if (err)
+		val = -1;
+	sam->gpio_base = val;
+
+	err = of_property_read_u32(dev->of_node, "gpio-count", &val);
+	if (!err) {
+		if (val > SAM_MAX_NGPIO)
+			val = SAM_MAX_NGPIO;
+		sam->gpio_count = val;
+	}
+	/* validate gpio_count against chip data. Abort if chip data is bad. */
+	ngpio = ioread32(sam->base + 2 * sizeof(u32)) & 0xffff;
+	if (!ngpio || ngpio > SAM_MAX_NGPIO)
+		return -ENODEV;
+
+	if (!sam->gpio_count || sam->gpio_count > ngpio)
+		sam->gpio_count = ngpio;
+
+	igroup = of_get_property(dev->of_node, "gpio-interrupts", &iglen);
+	if (igroup) {
+		iglen /= sizeof(u32);
+		if (iglen < 3 || iglen % 3)
+			return -EINVAL;
+		iglen /= 3;
+		for (i = 0; i < iglen; i++) {
+			group = be32_to_cpu(igroup[i * 3]);
+			if (group >= ARRAY_SIZE(sam->irq_group))
+				return -EINVAL;
+			start = be32_to_cpu(igroup[i * 3 + 1]);
+			count = be32_to_cpu(igroup[i * 3 + 2]);
+			if (start >= sam->gpio_count || count == 0 ||
+			    start + count > sam->gpio_count)
+				return -EINVAL;
+			sam->irq_group[group].start = start;
+			sam->irq_group[group].count = count;
+		}
+	}
+
+	err = sam_of_get_exports(dev, sam);
+	return err;
+}
+
+static int sam_gpio_pin_to_irq_bit(struct sam_gpio *sam, int pin)
+{
+	int bit;
+
+	for (bit = 0; bit < ARRAY_SIZE(sam->irq_group); bit++) {
+		struct sam_gpio_irq_group *irq_group = &sam->irq_group[bit];
+
+		if (irq_group->count &&
+		    pin >= irq_group->start &&
+		    pin <= irq_group->start + irq_group->count)
+			return bit;
+	}
+	return -EINVAL;
+}
+
+static bool sam_gpio_irq_handle_group(struct sam_gpio *sam,
+				      struct sam_gpio_irq_group *irq_group)
+{
+	unsigned int virq = 0;
+	bool handled = false;
+	bool repeat;
+	int i;
+
+	/* no irq_group for the interrupt bit */
+	if (!irq_group->count)
+		return false;
+
+	WARN_ON(irq_group->num_enabled == 0);
+	do {
+		repeat = false;
+		for (i = 0; i < irq_group->count; i++) {
+			int pin = irq_group->start + i;
+			bool low, high;
+			u32 regval;
+			u8 type;
+
+			regval = ioread32(SAM_GPIO_ADDR(sam->base, pin));
+			/*
+			 * write back status to clear POS_EDGE and NEG_EDGE
+			 * status for this GPIO pin (status bits are
+			 * clear-on-one). This is necessary to clear the
+			 * high level interrupt status.
+			 * Also consider the interrupt to be handled in that
+			 * case, even if there is no taker.
+			 */
+			if (regval & (SAM_GPIO_POS_EDGE | SAM_GPIO_NEG_EDGE)) {
+				iowrite32(regval,
+					  SAM_GPIO_ADDR(sam->base, pin));
+				ioread32(SAM_GPIO_ADDR(sam->base, pin));
+				handled = true;
+			}
+
+			/*
+			 * Check if the pin changed its state.
+			 * If it did, and if the expected condition applies,
+			 * generate a virtual interrupt.
+			 * A pin can only generate an interrupt if
+			 * - interrupts are enabled for it
+			 * - it is configured as input
+			 */
+
+			if (!sam->irq_type[pin])
+				continue;
+			if (!(regval & SAM_GPIO_OUT_TS))
+				continue;
+
+			high = regval & (SAM_GPIO_IN | SAM_GPIO_POS_EDGE);
+			low = !(regval & SAM_GPIO_IN) ||
+				(regval & SAM_GPIO_NEG_EDGE);
+			type = sam->irq_type[pin];
+			if (((type & IRQ_TYPE_EDGE_RISING) &&
+			     (regval & SAM_GPIO_POS_EDGE)) ||
+			    ((type & IRQ_TYPE_EDGE_FALLING) &&
+			     (regval & SAM_GPIO_NEG_EDGE)) ||
+			    ((type & IRQ_TYPE_LEVEL_LOW) && low) ||
+			    ((type & IRQ_TYPE_LEVEL_HIGH) && high)) {
+				virq = irq_find_mapping(sam->domain, pin);
+				handle_nested_irq(virq);
+				if (type & (IRQ_TYPE_LEVEL_LOW
+					    | IRQ_TYPE_LEVEL_HIGH))
+					repeat = true;
+			}
+		}
+		schedule();
+	} while (repeat);
+
+	return handled;
+}
+
+static irqreturn_t sam_gpio_irq_handler(int irq, void *data)
+{
+	struct sam_gpio *sam = data;
+	struct sam_platform_data *pdata = sam->pdata;
+	irqreturn_t ret = IRQ_NONE;
+	bool handled;
+	u32 status;
+
+	do {
+		handled = false;
+		status = pdata->irq_status(sam->dev->parent, SAM_IRQ_GPIO,
+					   sam->irq);
+		pdata->irq_status_clear(sam->dev->parent, SAM_IRQ_GPIO,
+					sam->irq, status);
+		while (status) {
+			unsigned int bit;
+
+			bit = __ffs(status);
+			status &= ~(1 << bit);
+			handled =
+			  sam_gpio_irq_handle_group(sam, &sam->irq_group[bit]);
+			if (handled)
+				ret = IRQ_HANDLED;
+		}
+	} while (handled);
+
+	return ret;
+}
+
+static int sam_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
+{
+	struct sam_gpio *sam = to_sam(chip);
+
+	return irq_create_mapping(sam->domain, offset);
+}
+
+static void sam_irq_mask(struct irq_data *data)
+{
+	struct sam_gpio *sam = irq_data_get_irq_chip_data(data);
+	struct sam_platform_data *pdata = sam->pdata;
+	int bit = sam_gpio_pin_to_irq_bit(sam, data->hwirq);
+
+	if (bit < 0)
+		return;
+
+	if (--sam->irq_group[bit].num_enabled <= 0) {
+		pdata->disable_irq(sam->dev->parent, SAM_IRQ_GPIO, sam->irq,
+				   1 << bit);
+	}
+}
+
+static void sam_irq_unmask(struct irq_data *data)
+{
+	struct sam_gpio *sam = irq_data_get_irq_chip_data(data);
+	struct sam_platform_data *pdata = sam->pdata;
+	int bit = sam_gpio_pin_to_irq_bit(sam, data->hwirq);
+
+	if (bit < 0)
+		return;
+
+	sam->irq_group[bit].num_enabled++;
+	pdata->enable_irq(sam->dev->parent, SAM_IRQ_GPIO, sam->irq, 1 << bit);
+}
+
+static int sam_irq_set_type(struct irq_data *data, unsigned int type)
+{
+	struct sam_gpio *sam = irq_data_get_irq_chip_data(data);
+	int bit = sam_gpio_pin_to_irq_bit(sam, data->hwirq);
+
+	if (bit < 0)
+		return bit;
+
+	sam->irq_type[data->hwirq] = type & 0x0f;
+	sam_gpio_bitop(sam, data->hwirq, SAM_GPIO_OUT_TS, true);
+	sam_gpio_bitop(sam, data->hwirq, SAM_GPIO_DEBOUNCE_EN, type & 0x10);
+	sam_gpio_bitop(sam, data->hwirq,
+		       SAM_GPIO_POS_EDGE_EN | SAM_GPIO_POS_EDGE,
+		       type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH));
+	sam_gpio_bitop(sam, data->hwirq,
+		       SAM_GPIO_NEG_EDGE_EN | SAM_GPIO_NEG_EDGE,
+		       type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW));
+
+	return 0;
+}
+
+static void sam_irq_bus_lock(struct irq_data *data)
+{
+	struct sam_gpio *sam = irq_data_get_irq_chip_data(data);
+
+	mutex_lock(&sam->irq_lock);
+}
+
+static void sam_irq_bus_unlock(struct irq_data *data)
+{
+	struct sam_gpio *sam = irq_data_get_irq_chip_data(data);
+
+	/* Synchronize interrupts to chip */
+
+	mutex_unlock(&sam->irq_lock);
+}
+
+static struct irq_chip sam_irq_chip = {
+	.name = "gpio-sam",
+	.irq_mask = sam_irq_mask,
+	.irq_unmask = sam_irq_unmask,
+	.irq_set_type = sam_irq_set_type,
+	.irq_bus_lock = sam_irq_bus_lock,
+	.irq_bus_sync_unlock = sam_irq_bus_unlock,
+};
+
+static int sam_gpio_irq_map(struct irq_domain *domain, unsigned int irq,
+			    irq_hw_number_t hwirq)
+{
+	irq_set_chip_data(irq, domain->host_data);
+	irq_set_chip(irq, &sam_irq_chip);
+	irq_set_nested_thread(irq, true);
+
+	irq_set_noprobe(irq);
+
+	return 0;
+}
+
+static const struct irq_domain_ops sam_gpio_irq_domain_ops = {
+	.map = sam_gpio_irq_map,
+	.xlate = irq_domain_xlate_twocell,
+};
+
+static int sam_gpio_irq_setup(struct device *dev, struct sam_gpio *sam)
+{
+	int ret;
+
+	sam->domain = irq_domain_add_linear(dev->of_node,
+					    sam->gpio_count,
+					    &sam_gpio_irq_domain_ops,
+					    sam);
+	if (sam->domain == NULL)
+		return -ENOMEM;
+
+	ret = devm_request_threaded_irq(dev, sam->irq, NULL,
+					sam_gpio_irq_handler,
+					IRQF_ONESHOT,
+					dev_name(dev), sam);
+	if (ret)
+		goto out_remove_domain;
+
+	sam->gpio.to_irq = sam_gpio_to_irq;
+
+	if (!try_module_get(dev->parent->driver->owner)) {
+		ret = -EINVAL;
+		goto out_remove_domain;
+	}
+
+	return 0;
+
+out_remove_domain:
+	irq_domain_remove(sam->domain);
+	sam->domain = NULL;
+	return ret;
+}
+
+static void sam_gpio_irq_teardown(struct device *dev, struct sam_gpio *sam)
+{
+	int i, irq;
+	struct sam_platform_data *pdata = sam->pdata;
+
+	pdata->disable_irq(dev->parent, SAM_IRQ_GPIO, sam->irq, 0xffffffff);
+
+	for (i = 0; i < sam->gpio_count; i++) {
+		irq = irq_find_mapping(sam->domain, i);
+		if (irq > 0)
+			irq_dispose_mapping(irq);
+	}
+	irq_domain_remove(sam->domain);
+	module_put(dev->parent->driver->owner);
+}
+
+static int sam_gpio_unexport(struct sam_gpio *sam)
+{
+	int i;
+
+	if (!sam->export_flags)
+		return 0;
+
+	/* un-export all auto-exported pins */
+	for (i = 0; i < sam->gpio_count; i++) {
+		struct gpio_desc *desc = gpio_to_desc(sam->gpio.base + i);
+
+		if (desc == NULL)
+			continue;
+
+		if (sam->export_flags[i] & GPIOF_EXPORT)
+			gpiochip_free_own_desc(desc);
+	}
+	return 0;
+}
+
+static int sam_gpio_export(struct sam_gpio *sam)
+{
+	int i, ret;
+
+	if (!sam->export_flags)
+		return 0;
+
+	/* auto-export pins as requested */
+
+	for (i = 0; i < sam->gpio_count; i++) {
+		u32 flags = sam->export_flags[i];
+		struct gpio_desc *desc;
+
+		/* request and initialize exported pins */
+		if (!(flags & GPIOF_EXPORT))
+			continue;
+
+		desc  = gpiochip_request_own_desc(&sam->gpio, i, "sam-export");
+		if (IS_ERR(desc)) {
+			ret = PTR_ERR(desc);
+			goto error;
+		}
+		if (flags & GPIOF_DIR_IN) {
+			ret = gpiod_direction_input(desc);
+			if (ret)
+				goto error;
+		} else {
+			ret = gpiod_direction_output(desc, flags &
+						    (GPIOF_OUT_INIT_HIGH |
+						     GPIOF_ACTIVE_LOW));
+			if (ret)
+				goto error;
+		}
+		ret = gpiod_export(desc, flags & GPIOF_EXPORT_CHANGEABLE);
+
+		if (ret)
+			goto error;
+	}
+	return 0;
+
+error:
+	sam_gpio_unexport(sam);
+	return ret;
+}
+
+static int sam_gpio_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct sam_gpio *sam;
+	struct resource *res;
+	int ret;
+	struct sam_platform_data *pdata = dev_get_platdata(&pdev->dev);
+
+	sam = devm_kzalloc(dev, sizeof(*sam), GFP_KERNEL);
+	if (sam == NULL)
+		return -ENOMEM;
+
+	sam->dev = dev;
+	sam->pdata = pdata;
+	platform_set_drvdata(pdev, sam);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	sam->irq = platform_get_irq(pdev, 0);
+	sam->irq_high = platform_get_irq(pdev, 1);
+
+	sam->base = devm_ioremap_nocache(dev, res->start, resource_size(res));
+	if (!sam->base)
+		return -ENOMEM;
+
+	mutex_init(&sam->irq_lock);
+
+	ret = sam_gpio_of_init(dev, sam);
+	if (ret)
+		return ret;
+
+	sam_gpio_setup(sam);
+
+	if (pdata && sam->irq >= 0 && of_find_property(dev->of_node,
+					      "interrupt-controller", NULL)) {
+		ret = sam_gpio_irq_setup(dev, sam);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = gpiochip_add(&sam->gpio);
+	if (ret)
+		goto teardown;
+
+	ret = sam_gpio_export(sam);
+	if (ret)
+		goto teardown_remove;
+
+	return 0;
+
+teardown_remove:
+	gpiochip_remove(&sam->gpio);
+
+teardown:
+	if (sam->domain)
+		sam_gpio_irq_teardown(dev, sam);
+	return ret;
+}
+
+static int sam_gpio_remove(struct platform_device *pdev)
+{
+	struct sam_gpio *sam = platform_get_drvdata(pdev);
+	struct device *dev = &pdev->dev;
+
+	dev_info(dev, "remove\n");
+
+	sam_gpio_unexport(sam);
+
+	if (sam->domain)
+		sam_gpio_irq_teardown(dev, sam);
+
+	gpiochip_remove(&sam->gpio);
+
+	return 0;
+}
+
+static const struct of_device_id sam_gpio_ids[] = {
+	{ .compatible = "jnx,gpio-sam", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, sam_gpio_ids);
+
+static struct platform_driver sam_gpio_driver = {
+	.driver = {
+		.name = "gpio-sam",
+		.owner  = THIS_MODULE,
+		.of_match_table = sam_gpio_ids,
+	},
+	.probe = sam_gpio_probe,
+	.remove = sam_gpio_remove,
+};
+
+module_platform_driver(sam_gpio_driver);
+
+MODULE_DESCRIPTION("SAM FPGA GPIO Driver");
+MODULE_LICENSE("GPL");
-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:18:36 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:18:36 +0300
Subject: [PATCH 08/10] mtd: flash-sam: Bindings for Juniper's SAM FPGA flash
In-Reply-To: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853518-22264-9-git-send-email-pantelis.antoniou@konsulko.com>

From: Georgi Vlaev <gvlaev at juniper.net>

Add binding document for Junipers Flash IP block present
in the SAM FPGA on PTX series of routers.

Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 .../devicetree/bindings/mtd/flash-sam.txt          | 31 ++++++++++++++++++++++
 1 file changed, 31 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/flash-sam.txt

diff --git a/Documentation/devicetree/bindings/mtd/flash-sam.txt b/Documentation/devicetree/bindings/mtd/flash-sam.txt
new file mode 100644
index 0000000..bdf1d78
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/flash-sam.txt
@@ -0,0 +1,31 @@
+Flash device on a Juniper SAM FPGA
+
+These flash chips are found in the PTX series of Juniper routers.
+
+They are regular CFI compatible (Intel or AMD extended) flash chips with
+some special write protect/VPP bits that can be controlled by the machine's
+system controller.
+
+Required properties:
+- compatible : must be "jnx,flash-sam"
+
+Optional properties:
+- reg : memory address for the flash chip, note that this is not
+required since usually the device is a subdevice of the SAM MFD
+driver which fills in the register fields.
+
+For the rest of the properties, see mtd-physmap.txt.
+
+The device tree may optionally contain sub-nodes describing partitions of the
+address space. See partition.txt for more detail.
+
+Example:
+
+flash_sam {
+	compatible = "jnx,flash-sam";
+	partition at 0 {
+		reg = <0x0 0x400000>;
+		label = "pic0-golden";
+		read-only;
+	};
+};
-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:18:31 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:18:31 +0300
Subject: [PATCH 03/10] i2c: Juniper SAM I2C driver
In-Reply-To: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853518-22264-4-git-send-email-pantelis.antoniou@konsulko.com>

From: Maryam Seraj <mseraj at juniper.net>

Introduce SAM I2C driver for the I2C interfaces on the Juniper
SAM FPGA.

Signed-off-by: Maryam Seraj <mseraj at juniper.net>
Signed-off-by: Debjit Ghosh <dghosh at juniper.net>
Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
Signed-off-by: Guenter Roeck <groeck at juniper.net>
Signed-off-by: Rajat Jain <rajatjain at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 drivers/i2c/busses/Kconfig   |  11 +
 drivers/i2c/busses/Makefile  |   1 +
 drivers/i2c/busses/i2c-sam.c | 942 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 954 insertions(+)
 create mode 100644 drivers/i2c/busses/i2c-sam.c

diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 5c3993b..eeac4b2 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -833,6 +833,17 @@ config I2C_SH7760
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-sh7760.
 
+config I2C_SAM
+	tristate "Juniper SAM FPGA I2C Controller"
+	select I2C_MUX
+	depends on MFD_JUNIPER_SAM || MFD_JUNIPER_CBC
+	help
+	  This driver supports the I2C interfaces on the Juniper SAM FPGA
+	  which is present on the relevant Juniper platforms.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-sam.
+
 config I2C_SH_MOBILE
 	tristate "SuperH Mobile I2C Controller"
 	depends on HAS_DMA
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 37f2819..b99b229 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -79,6 +79,7 @@ obj-$(CONFIG_I2C_QUP)		+= i2c-qup.o
 obj-$(CONFIG_I2C_RIIC)		+= i2c-riic.o
 obj-$(CONFIG_I2C_RK3X)		+= i2c-rk3x.o
 obj-$(CONFIG_I2C_S3C2410)	+= i2c-s3c2410.o
+obj-$(CONFIG_I2C_SAM)		+= i2c-sam.o
 obj-$(CONFIG_I2C_SH7760)	+= i2c-sh7760.o
 obj-$(CONFIG_I2C_SH_MOBILE)	+= i2c-sh_mobile.o
 obj-$(CONFIG_I2C_SIMTEC)	+= i2c-simtec.o
diff --git a/drivers/i2c/busses/i2c-sam.c b/drivers/i2c/busses/i2c-sam.c
new file mode 100644
index 0000000..1ec930a
--- /dev/null
+++ b/drivers/i2c/busses/i2c-sam.c
@@ -0,0 +1,942 @@
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/i2c-mux.h>
+#include <linux/mfd/sam.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+
+#define SAM_DEB1(dev, fmt, args...) do { \
+	if (sam_debug >= 1) \
+		dev_err(dev, fmt, ## args); \
+	} while (0)
+#define SAM_DEB2(dev, fmt, args...) do { \
+	if (sam_debug >= 2) \
+		dev_err(dev, fmt, ## args); \
+	} while (0)
+#define SAM_DEB3(dev, fmt, args...) do { \
+	if (sam_debug >= 3) \
+		dev_err(dev, fmt, ## args); } \
+	while (0)
+
+static int sam_debug;
+
+#define DRIVER_DESC			"SAM FPGA I2C Driver"
+#define DRIVER_VERSION			"0.2"
+#define DRIVER_AUTHOR			"Maryam Seraj <mseraj at juniper.net>"
+
+#define SAM_FPGA_MODULE_NAME		"i2c-sam"
+
+#define SAM_I2C_MUX_MAX_CHAN		8
+
+#define SAM_I2C_DEV_ADDR_MASK		0x7f
+#define SAM_I2C_TBL_ENTRY_CMDS_NUM	2
+
+#define SAM_I2C_CMD_TABLE_SZ		256
+
+#define SAM_I2C_STS_DONE		(1 << 0)
+#define SAM_I2C_STS_PRIO_DONE		(1 << 1)
+#define SAM_I2C_STS_RUNNING		(1 << 2)
+#define SAM_I2C_STS_PRIO_RUNNING	(1 << 3)
+#define SAM_I2C_STS_ERR			(1 << 4)
+#define SAM_I2C_STS_PRIO_ERR		(1 << 5)
+#define SAM_I2C_STS_RDY			(1 << 6)
+#define SAM_I2C_STS_TR_TIMEOUT		(1 << 7)
+#define SAM_I2C_STS_CMD_TIMEOUT		(1 << 8)
+#define SAM_I2C_STS_CMD_TABLE_TIMEOUT	(1 << 9)
+
+#define SAM_I2C_STS_CLEAR_MASK		(SAM_I2C_STS_DONE \
+					 | SAM_I2C_STS_PRIO_DONE \
+					 | SAM_I2C_STS_TR_TIMEOUT \
+					 | SAM_I2C_STS_CMD_TIMEOUT \
+					 | SAM_I2C_STS_CMD_TABLE_TIMEOUT \
+					 | SAM_I2C_STS_ERR \
+					 | SAM_I2C_STS_PRIO_ERR)
+#define SAM_I2C_STS_CLEAR(x)	(((x) & ~0x3fb3) | SAM_I2C_STS_CLEAR_MASK)
+
+#define SAM_I2C_STS_TIMEOUT		(SAM_I2C_STS_TR_TIMEOUT \
+					 | SAM_I2C_STS_CMD_TIMEOUT \
+					 | SAM_I2C_STS_CMD_TABLE_TIMEOUT)
+
+#define SAM_I2C_DONE(s)		((s) & (SAM_I2C_STS_DONE | SAM_I2C_STS_ERR \
+					| SAM_I2C_STS_TIMEOUT))
+
+#define SAM_I2C_CTRL_RESET		(1 << 0)
+#define SAM_I2C_CTRL_GO			(1 << 1)
+#define SAM_I2C_CTRL_PRIO_GO		(1 << 2)
+#define SAM_I2C_CTRL_ABORT		(1 << 3)
+#define SAM_I2C_CTRL_PRIO_ABORT		(1 << 4)
+
+/* Priority ctrl & status bits are offset +1 from the regular */
+#define STS_DONE(p)			BIT(0 + (p))
+#define STS_RUNNING(p)			BIT(2 + (p))
+#define STS_ERR(p)			BIT(4 + (p))
+#define CTRL_GO(p)			BIT(1 + (p))
+#define CTRL_ABORT(p)			BIT(3 + (p))
+#define STS_I2C_DONE(s, p)		((s) & (STS_DONE(p) | STS_ERR(p) \
+					 | SAM_I2C_STS_TIMEOUT))
+
+struct sam_i2c_data {
+	void __iomem *membase;
+	void __iomem *masterbase;
+	int first_master;
+	int num_master;
+	int mux_channels;
+	u32 *speed;		/* bit mask, 1 for high speed */
+	bool prio;
+	bool reverse_fill;
+	struct i2c_adapter **adap;
+	struct device *dev;
+	int irq;
+	struct sam_platform_data *pdata;
+};
+
+struct sam_i2c_adapdata {
+	void __iomem *membase;
+	void __iomem *masterbase;
+	int channel;
+	int mux_channels;
+	int mux_select;
+	u32 speed;			/* bit mask, same as above */
+	int prio;
+	bool reverse_fill;
+	struct i2c_adapter adap;
+	struct i2c_mux_core *muxc;
+	wait_queue_head_t wait;
+	u32 status;
+	u32 control;
+	bool done;
+	bool polling;
+};
+
+/**************************** i2c stuff *****************************/
+
+#define SAM_FPGA_MUX_NAME    "sam-fpga-mux"
+
+enum i2c_accel_cmd_bits_s {
+	I2C_WRITE,		/* 000 */
+	I2C_READ,		/* 001 */
+	I2C_WRITE_STOP,		/* 010 */
+	I2C_READ_STOP,		/* 011 */
+	I2C_WRITE_REPSTART,	/* 100 */
+	I2C_READ_REPSTART	/* 101 */
+};
+
+#define I2C_CMD_STOP_BIT	(1 << 1)
+#define I2C_CMD_REPSTART_BIT	(1 << 2)
+
+#define PER_MASTER_MEM		0x1000
+#define I2C_OPTIONS_BASE	0x2000
+#define MASTER_MEM_BASE		0x8000
+
+#define CMD_ADDR(s, idx)	((s)->masterbase + 0x0000 + \
+				 PER_MASTER_MEM * (s)->channel + \
+				 (idx) * sizeof(u32))
+#define RES_ADDR(s, idx)	((s)->masterbase + 0x0400 + \
+				 PER_MASTER_MEM * (s)->channel + \
+				 (idx) * sizeof(u32))
+#define CMD_PRI_ADDR(s, idx)	((s)->masterbase + 0x0800 + \
+				 PER_MASTER_MEM * (s)->channel + \
+				 (idx) * sizeof(u32))
+#define RES_PRI_ADDR(s, idx)	((s)->masterbase + 0x0c00 + \
+				 PER_MASTER_MEM * (s)->channel + \
+				 (idx) * sizeof(u32))
+#define CTRL_ADDR(s)		((s)->membase + 0x2400 + 8 * (s)->channel)
+#define STAT_ADDR(s)		((s)->membase + 0x2404 + 8 * (s)->channel)
+
+#define sam_i2c_stat_clear(adata, val)					\
+	do {								\
+		iowrite32(SAM_I2C_STS_CLEAR(val), STAT_ADDR(adata));	\
+		ioread32(STAT_ADDR(adata));				\
+	} while (0)
+
+static int sam_i2c_wait_rdy(struct i2c_adapter *adap)
+{
+	struct sam_i2c_adapdata *adata = i2c_get_adapdata(adap);
+	u32 val;
+	unsigned long timeout;
+
+	val = ioread32(STAT_ADDR(adata));
+	if ((val & SAM_I2C_STS_RDY) && !(val & STS_RUNNING(adata->prio)))
+		return 0;
+
+	if (val & STS_RUNNING(adata->prio)) {
+		iowrite32(adata->control | CTRL_ABORT(adata->prio),
+			  CTRL_ADDR(adata));
+		ioread32(CTRL_ADDR(adata));
+		udelay(10);
+		iowrite32(adata->control, CTRL_ADDR(adata));
+		ioread32(CTRL_ADDR(adata));
+		udelay(100);
+	}
+
+	timeout = jiffies + adap->timeout;
+	adata->status = 0;
+	do {
+		val = ioread32(STAT_ADDR(adata)) | adata->status;
+		if ((val & SAM_I2C_STS_RDY) &&
+		    !(val & STS_RUNNING(adata->prio)))
+			return 0;
+
+		if (adata->polling) {
+			udelay(50);
+		} else {
+			adata->done = false;
+			adata->status = 0;
+			wait_event_timeout(adata->wait, adata->done,
+					   adap->timeout);
+		}
+
+	} while (time_before(jiffies, timeout));
+
+	return -EBUSY;
+}
+
+int sam_i2c_calc_start_entry(struct i2c_msg *msgs, int num, int reverse_fill)
+{
+	int i, len = 0;
+
+	/* Filling the table from start (offset 0) ? */
+	if (!reverse_fill)
+		return 0;
+
+	/* Calculate required table size from the message sizes */
+	if (num == 1 && msgs[0].len == 0)
+		len = 1;
+	else
+		for (i = 0; i < num; i++)
+			if (msgs[i].flags & I2C_M_RECV_LEN)
+				len += (I2C_SMBUS_BLOCK_MAX + 1);
+			else
+				len += msgs[i].len;
+
+	if (len > SAM_I2C_CMD_TABLE_SZ * 2)
+		return -E2BIG;
+
+	/* Always start from Command 0 */
+	return (SAM_I2C_CMD_TABLE_SZ * 2 - len) / 2;
+}
+
+static int sam_i2c_cmd_init(struct i2c_adapter *adap, struct i2c_msg *msgs,
+			    int num)
+{
+	struct sam_i2c_adapdata *adata = i2c_get_adapdata(adap);
+	struct device *dev = &adap->dev;
+	struct i2c_msg *msg;
+	int curmsg, cmds = 0;
+	int addr, i, len = 0, table_offset = 0;
+	u32 cmd_entry;
+	bool read;
+	u8 group;
+	u32 idx;
+	u8 cmd;
+
+	group = adata->mux_select;
+	addr = msgs[0].addr & SAM_I2C_DEV_ADDR_MASK;
+	cmd_entry = (group << 29) | (addr << 22);
+
+	/* Zero CMD table */
+	memset_io(CMD_ADDR(adata, 0), 0, SAM_I2C_CMD_TABLE_SZ * sizeof(u32));
+
+	idx = sam_i2c_calc_start_entry(msgs, num, adata->reverse_fill);
+	if (idx < 0)
+		return idx;
+
+	table_offset = idx;
+
+	for (curmsg = 0; curmsg < num; curmsg++) {
+		msg = &msgs[curmsg];
+		read = msg->flags & I2C_M_RD;
+
+		SAM_DEB1(dev, "  [%02d] %s %d bytes addr %#02x\n",
+			 curmsg, read ? "RD" : "WR",
+			 msg->len, addr);
+
+		len = msg->len;
+		if (len == 0 && curmsg == 0 && num == 1) {
+			/*
+			 * SMBus quick command, special case
+			 *
+			 * Always read; we don't want to risk that
+			 * a "WRITE_STOP" command as only command
+			 * would actually write anything into the chip.
+			 */
+			cmd = I2C_READ_STOP;
+			cmd_entry |= cmd << 19;
+			cmds = 1;
+			break;
+		}
+		/*
+		 * If the message is a SMBus block read message, read up to the
+		 * maximum block length. The command should succeed at least up
+		 * to the real block length, which will be returned in the first
+		 * data byte.
+		 */
+		if (read && (msg->flags & I2C_M_RECV_LEN))
+			len = I2C_SMBUS_BLOCK_MAX + 1;
+		for (i = 0; i < len; i++) {
+			cmd = read ? I2C_READ : I2C_WRITE;
+			if (i == len - 1) {
+				if (curmsg == num - 1)
+					cmd |= I2C_CMD_STOP_BIT;
+				else
+					cmd |= I2C_CMD_REPSTART_BIT;
+			}
+
+			if ((cmds % SAM_I2C_TBL_ENTRY_CMDS_NUM) == 0) {
+				/* cmd0/data0 */
+				cmd_entry |= cmd << 19;
+				if (!read)
+					cmd_entry |= (msg->buf[i] << 11);
+			} else {
+				/* cmd1/data1 */
+				cmd_entry |= cmd << 8;
+				if (!read)
+					cmd_entry |= msg->buf[i];
+			}
+			cmds++;
+			if (cmds % SAM_I2C_TBL_ENTRY_CMDS_NUM == 0) {
+				/*
+				 * One command entry is done!
+				 * Write it to the command table and start
+				 * putting together the next entry for
+				 * the same current i2c command, if needed.
+				 */
+				SAM_DEB2(dev,
+					 "reg-offset cmd_entry = 0x%08x, cmds = %d, @ %p\n",
+					 cmd_entry, cmds, CMD_ADDR(adata, idx));
+
+				iowrite32(cmd_entry, CMD_ADDR(adata, idx));
+				ioread32(CMD_ADDR(adata, idx));
+				idx++;
+
+				/* clean out everything but group and address */
+				cmd_entry &= 0xFFC00000;
+			}
+		}
+	}
+	/*
+	 * Zero out any remaining cmd/data part of the last
+	 * command entry into the command table of the given
+	 * master before kicking off the i2c engine for this
+	 * master.
+	 */
+	if (cmds % SAM_I2C_TBL_ENTRY_CMDS_NUM != 0) {
+		cmd_entry &= 0xFFFFF800;
+
+		SAM_DEB1(dev, "rest of cmd_entry = 0x%08x, cmds = %d, @ %p\n",
+			 cmd_entry, cmds, CMD_ADDR(adata, idx));
+
+		if (idx >= SAM_I2C_CMD_TABLE_SZ)
+			return -E2BIG;
+
+		iowrite32(cmd_entry, CMD_ADDR(adata, idx));
+		ioread32(CMD_ADDR(adata, idx));
+		idx++;
+		if (idx < SAM_I2C_CMD_TABLE_SZ) {
+			iowrite32(0, CMD_ADDR(adata, idx));
+			ioread32(CMD_ADDR(adata, idx));
+		}
+	}
+	return table_offset;
+}
+
+static u32 i2c_sam_wait_results(struct i2c_adapter *adap)
+{
+	struct sam_i2c_adapdata *adata = i2c_get_adapdata(adap);
+	struct device *dev = &adap->dev;
+	u32 val;
+
+	if (adata->polling) {
+		unsigned long timeout = jiffies + adap->timeout;
+
+		/*
+		 * Poll for results.
+		 * Only wait a short time per loop to avoid long access times.
+		 * At 100kHz, a single byte transfer takes about 100 uS,
+		 * so we don't want to wait much longer than that.
+		 */
+		do {
+			/*
+			 * We should really use usleep_range() here, but that
+			 * does not work and causes the system to lock up.
+			 * msleep() is slow, so use an active wait loop instead.
+			 */
+			udelay(50);
+			val = ioread32(STAT_ADDR(adata));
+			SAM_DEB1(dev, "status = 0x%08x @%p\n",
+				 val, STAT_ADDR(adata));
+			if (STS_I2C_DONE(val, adata->prio))
+				break;
+		} while (time_before(jiffies, timeout));
+	} else {
+		if (!wait_event_timeout(adata->wait, adata->done,
+					adap->timeout))
+			val = ioread32(STAT_ADDR(adata));
+		else
+			val = ioread32(STAT_ADDR(adata)) | adata->status;
+	}
+
+	sam_i2c_stat_clear(adata, val);
+
+	return val;
+}
+
+static int sam_i2c_read_data(struct i2c_adapter *adap, struct i2c_msg *msgs,
+			     int num, int table_offset)
+{
+	struct sam_i2c_adapdata *adata = i2c_get_adapdata(adap);
+	int offset = table_offset * 2;
+	struct device *dev = &adap->dev;
+	struct i2c_msg *msg;
+	u32 val, data;
+	bool valid;
+	int i, len;
+
+	msg = &msgs[num - 1];
+	len = msg->len;
+
+	if (num > 1)
+		offset += msgs[0].len;
+
+	SAM_DEB1(dev, "Reading %d bytes\n", len);
+
+	for (i = offset & 0xfffffffe; i < len + offset; i++) {
+		val = ioread32(RES_ADDR(adata, i / 2));
+		SAM_DEB2(dev, "data = 0x%08x @%p\n",
+			 val, RES_ADDR(adata, i / 2));
+		if (i >= offset) {
+			data = (val >> 11) & 0xff;	/* data_0  */
+			valid = val & 0x00200000;	/* valid_0 */
+			if (!valid)
+				return -EIO;
+			msg->buf[i - offset] = data;
+			if (i == offset &&
+			    (msg->flags & I2C_M_RECV_LEN)) {
+				if (data == 0 ||
+				    data > I2C_SMBUS_BLOCK_MAX)
+					return -EPROTO;
+				SAM_DEB1(dev, "SMBus block data, %d bytes\n",
+					 data);
+				len += data;
+			}
+		}
+		if (++i >= len + offset)
+			break;
+		if (i >= offset) {
+			data = val & 0xff;		/* data_1  */
+			valid = val & 0x00000400;	/* valid_1 */
+			if (!valid)
+				return -EIO;
+			msg->buf[i - offset] = data;
+			if (i == offset &&
+			    (msg->flags & I2C_M_RECV_LEN)) {
+				if (data == 0 ||
+				    data > I2C_SMBUS_BLOCK_MAX)
+					return -EPROTO;
+				SAM_DEB1(dev, "SMBus block data, %d bytes\n",
+					 data);
+				len += data;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int sam_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+	struct sam_i2c_adapdata *adata = i2c_get_adapdata(adap);
+	int ret, table_offset;
+	u32 val;
+
+	ret = sam_i2c_wait_rdy(adap);
+	if (ret < 0)
+		return ret;
+
+	ret = sam_i2c_cmd_init(adap, msgs, num);
+	if (ret < 0)
+		return ret;
+	table_offset = ret & 0xff;
+
+	sam_i2c_stat_clear(adata, ioread32(STAT_ADDR(adata)));
+
+	/*
+	 * Done with setting up the command table, now kick
+	 * off this transaction before waiting for the results.
+	 */
+
+	adata->done = false;
+	adata->status = 0;
+
+	iowrite32(adata->control | CTRL_GO(adata->prio) | table_offset << 24,
+		  CTRL_ADDR(adata));
+	ioread32(CTRL_ADDR(adata));	/* read back to flush */
+
+	val = i2c_sam_wait_results(adap);
+	if (val & STS_ERR(adata->prio)) {
+		dev_err(&adap->dev, "i2c transaction error\n");
+		return -EIO;
+	}
+	if ((val & SAM_I2C_STS_TIMEOUT) || !(val & STS_DONE(adata->prio))) {
+		SAM_DEB1(&adap->dev,
+			 "i2c transaction timeout, status=0x%x\n", val);
+		return -ETIMEDOUT;
+	}
+
+	SAM_DEB1(&adap->dev, "i2c transaction completed!!!\n");
+
+	/* SMBus quick command, special case */
+	if (num == 1 && msgs[0].len == 0) {
+		val = ioread32(RES_ADDR(adata, table_offset));
+		SAM_DEB1(&adap->dev, "quick cmd: data = 0x%08x\n", val);
+		return val & 0x00200000 ? 1 : -EIO;
+	}
+	/*
+	 * If this was a "read" request, go get the data.
+	 * Otherwise, we're done here!
+	 */
+	if (msgs[num - 1].flags & I2C_M_RD) {
+		ret = sam_i2c_read_data(adap, msgs, num, table_offset);
+		if (ret < 0)
+			return ret;
+	}
+
+	SAM_DEB1(&adap->dev, "Returning %d\n", num);
+	return num;
+}
+
+static u32 sam_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
+	  | I2C_FUNC_SMBUS_READ_BLOCK_DATA;
+}
+
+static const struct i2c_algorithm sam_i2c_algo = {
+	.master_xfer = sam_i2c_xfer,
+	.functionality = sam_i2c_func,
+};
+
+/*
+ * This is where the SAM I2C-accel needs to be initialized.
+ */
+static int sam_i2c_init_adap(struct i2c_adapter *adap)
+{
+	struct sam_i2c_adapdata *adata = i2c_get_adapdata(adap);
+	u32 val;
+
+	SAM_DEB1(&adap->dev, "bus_mstr = %d\n", adata->channel);
+
+	val = 0x00000f00;
+	val |= (adata->speed << 12) & 0x0000f000;
+	adata->control = val;
+	/*
+	 * Set the i2c speed for ALL ports of this master and enable them all
+	 */
+	iowrite32(val, CTRL_ADDR(adata));
+
+	return 0;
+}
+
+int sam_i2c_add_numbered_bus(struct i2c_adapter *adap)
+{
+	int rval;
+
+	SAM_DEB1(&adap->dev, "%s", __func__);
+
+	rval = sam_i2c_init_adap(adap);
+	if (rval)
+		return rval;
+
+	return i2c_add_numbered_adapter(adap);
+}
+/********** end of i2c adapter/accel stuff ************************************/
+
+/********** start of i2c accel mux/group stuff ********************************/
+static int sam_i2c_mux_select(struct i2c_mux_core *muxc, u32 chan)
+{
+	struct sam_i2c_adapdata *adata = i2c_mux_priv(muxc);
+
+	if (!adata)
+		return -ENODEV;
+	adata->mux_select = chan;
+
+	return 0;
+}
+
+static int sam_i2c_mux_init(struct i2c_adapter *adap)
+{
+	struct sam_i2c_adapdata *adata = i2c_get_adapdata(adap);
+	int chan, ret;
+
+	SAM_DEB1(&adap->dev, "%s Begin\n", __func__);
+
+	adata->muxc = i2c_mux_alloc(adap, &adap->dev, adata->mux_channels, 0, 0,
+				   sam_i2c_mux_select, NULL);
+	if (!adata->muxc)
+		return -ENOMEM;
+	adata->muxc->priv = adata;
+
+	for (chan = 0; chan < adata->mux_channels; chan++) {
+		ret = i2c_mux_add_adapter(adata->muxc, 0, chan, 0);
+		if (ret) {
+			dev_err(&adap->dev, "Failed to add adapter %d\n", chan);
+			i2c_mux_del_adapters(adata->muxc);
+			return ret;
+		}
+	}
+
+	SAM_DEB1(&adap->dev, "%s End\n", __func__);
+
+	return 0;
+}
+
+/********** end of i2c accel mux/group stuff **********************************/
+
+static void sam_core_of_init_options(struct device *dev,
+				     struct sam_i2c_data *sam)
+{
+	const __be32 *opt;
+	int len, i;
+
+	opt = of_get_property(dev->of_node, "i2c-options", &len);
+	if (!opt || len > 4 * sizeof(u32))
+		return;
+
+	for (i = 0; i < len; i += sizeof(u32))
+		iowrite32(be32_to_cpup(opt++),
+			  sam->membase + I2C_OPTIONS_BASE + i);
+}
+
+static int sam_core_of_init(struct device *dev, struct sam_i2c_data *sam,
+			    struct resource *res)
+{
+	int err;
+	int num_master, max_masters;
+	u32 speed, mux_channels, val, master_offset = MASTER_MEM_BASE;
+	int i, len;
+	const __be32 *bus_range, *regs;
+	struct device_node *child;
+	u32 master, mux;
+
+	num_master = ioread32(sam->membase + 0x0c);
+	sam->first_master = -1;
+
+	err = of_property_read_u32(dev->of_node, "master-offset", &val);
+	if (!err)
+		if (val + PER_MASTER_MEM <= resource_size(res)) {
+			master_offset = val;
+			dev_info(dev, "Master offset changed to 0x%08x", val);
+		}
+
+	sam->masterbase = sam->membase + master_offset;
+	max_masters = (resource_size(res) - master_offset) / PER_MASTER_MEM;
+
+	if (num_master <= 0 || num_master > max_masters)
+		return -EINVAL;
+	sam->num_master = num_master;
+
+	bus_range = of_get_property(dev->of_node, "i2c-bus-range", &len);
+	if (bus_range) {
+		if (len != 2 * sizeof(u32))
+			return -EINVAL;
+		sam->first_master = be32_to_cpu(bus_range[0]);
+		num_master = be32_to_cpu(bus_range[1]) - sam->first_master + 1;
+		if (num_master <= 0 || num_master > sam->num_master)
+			return -EINVAL;
+		sam->num_master = num_master;
+	}
+
+	sam->speed = devm_kcalloc(dev, sam->num_master, sizeof(u32),
+				  GFP_KERNEL);
+	if (!sam->speed)
+		return -ENOMEM;
+
+	sam->adap = devm_kcalloc(dev, sam->num_master,
+				 sizeof(struct i2c_adapter *), GFP_KERNEL);
+	if (!sam->adap)
+		return -ENOMEM;
+
+	/* Set default i2c speed to 100kHz for all channels */
+	for (i = 0; i < sam->num_master; i++)
+		sam->speed[i] = (1 << SAM_I2C_MUX_MAX_CHAN) - 1;
+
+	if (!dev->of_node) {
+		/*
+		 * Use default from platform data if the there is no FDT.
+		 * TODO: Use FDT once it is available
+		 */
+		sam->mux_channels = sam->pdata ?
+			sam->pdata->i2c_mux_channels : 2;
+		dev_warn(dev,
+			 "No FDT node for SAM, using default (%d)\n",
+			 sam->mux_channels);
+		return 0;
+	}
+
+	err = of_property_read_u32(dev->of_node, "mux-channels", &mux_channels);
+	if (err || !mux_channels || mux_channels > SAM_I2C_MUX_MAX_CHAN)
+		return -EINVAL;
+	sam->mux_channels = mux_channels;
+	sam->reverse_fill = of_property_read_bool(dev->of_node, "reverse-fill");
+	sam->prio = of_property_read_bool(dev->of_node, "priority-tables");
+	/* Priority tables are offset with 0x800 from the regular tables */
+	if (sam->prio)
+		sam->masterbase += 0x800;
+
+	for_each_child_of_node(dev->of_node, child) {
+		regs = of_get_property(child, "reg", &len);
+		if (!regs || len != 2 * sizeof(u32)) {
+			dev_err(dev, "did not find reg property or bad size\n");
+			return -EINVAL;
+		}
+		err = of_property_read_u32(child, "speed", &speed);
+		if (err || !speed)
+			continue;
+		if (speed != 100000 && speed != 400000) {
+			dev_err(dev, "Bad speed %d\n", speed);
+			return -EINVAL;
+		}
+		master = be32_to_cpu(regs[0]);
+		mux = be32_to_cpu(regs[1]);
+		if (master >= sam->num_master || mux >= sam->mux_channels) {
+			dev_err(dev,
+				"master/mux %d/%d out of range\n",
+				master, mux);
+			return -EINVAL;
+		}
+		if (speed == 400000)
+			sam->speed[master] &= ~(1 << mux);
+	}
+
+	sam_core_of_init_options(dev, sam);
+
+	return 0;
+}
+
+static struct i2c_adapter *sam_i2c_init_one(struct sam_i2c_data *sam,
+					    int channel)
+{
+	struct device *dev = sam->dev;
+	struct sam_i2c_adapdata *adata;
+	int err;
+
+	adata = devm_kzalloc(dev, sizeof(*adata), GFP_KERNEL);
+	if (!adata)
+		return ERR_PTR(-ENOMEM);
+
+	init_waitqueue_head(&adata->wait);
+	adata->adap.owner = THIS_MODULE;
+	adata->adap.algo = &sam_i2c_algo;
+	adata->adap.nr = (sam->first_master >= 0) ?
+			  sam->first_master + channel : -1;
+	adata->adap.timeout = HZ / 5;
+	adata->channel = channel;
+	adata->mux_channels = sam->mux_channels;
+	adata->membase = sam->membase;
+	adata->masterbase = sam->masterbase;
+	adata->speed = sam->speed[channel];
+	adata->polling = (sam->irq < 0);
+	adata->reverse_fill = sam->reverse_fill;
+	adata->prio = sam->prio & 1;
+	i2c_set_adapdata(&adata->adap, adata);
+	snprintf(adata->adap.name, sizeof(adata->adap.name),
+		 "%s:%d", dev_name(dev), channel);
+
+	adata->adap.dev.parent = dev;
+	err = sam_i2c_add_numbered_bus(&adata->adap);
+	if (err)
+		goto error;
+
+	err = sam_i2c_mux_init(&adata->adap);
+	if (err)
+		goto err_remove;
+
+	return &adata->adap;
+
+err_remove:
+	i2c_del_adapter(&adata->adap);
+error:
+	return ERR_PTR(err);
+}
+
+static void sam_i2c_cleanup_one(struct i2c_adapter *adap)
+{
+	struct sam_i2c_adapdata *adata = i2c_get_adapdata(adap);
+
+	i2c_mux_del_adapters(adata->muxc);
+	i2c_del_adapter(adap);
+}
+
+static irqreturn_t sam_i2c_irq_handler(int irq, void *data)
+{
+	struct sam_i2c_data *sam = data;
+	struct sam_platform_data *pdata = sam->pdata;
+	struct sam_i2c_adapdata *adata;
+	int bit;
+	u32 val, status, wake_status;
+	u32 mask = (1 << sam->num_master) - 1;
+
+	status = pdata->irq_status(sam->dev->parent, SAM_IRQ_I2C,
+				   sam->irq) & mask;
+	do {
+		wake_status = status;
+		/* Clear the 'done' bits */
+		while (status) {
+			bit = __ffs(status);
+			status &= ~BIT(bit);
+			adata = i2c_get_adapdata(sam->adap[bit]);
+			val = ioread32(STAT_ADDR(adata));
+			if (STS_I2C_DONE(val, adata->prio)) {
+				sam_i2c_stat_clear(adata, val);
+				if (!adata->done) {
+					adata->done = true;
+					adata->status = val;
+				}
+			}
+		}
+		/*
+		 * Clear the status bits *after* the done status is cleared,
+		 * as otherwise this will generate another unused interrupt.
+		 * On the CBC this will also clear the MSI INT_ACCELL.
+		 */
+		pdata->irq_status_clear(sam->dev->parent, SAM_IRQ_I2C, sam->irq,
+					wake_status);
+
+		/* Now wake the blocked transactions */
+		while (wake_status) {
+			bit = __ffs(wake_status);
+			wake_status &= ~BIT(bit);
+			adata = i2c_get_adapdata(sam->adap[bit]);
+			wake_up(&adata->wait);
+		}
+
+		/* Recheck the status again, as we might miss an MSI in
+		 * the window from the last check and the clear of the
+		 * pending interrupts. This does not affect the SAM INTx.
+		 */
+		status = pdata->irq_status(sam->dev->parent, SAM_IRQ_I2C,
+					   sam->irq) & mask;
+	} while (status);
+
+	return IRQ_HANDLED;
+}
+
+static const struct of_device_id sam_i2c_of_match[] = {
+	{ .compatible = "jnx,i2c-sam",},
+	{},
+};
+MODULE_DEVICE_TABLE(of, sam_i2c_of_match);
+
+
+static int sam_i2c_probe(struct platform_device *pdev)
+{
+	int err;
+	int i;
+	struct sam_i2c_data *sam;
+	struct i2c_adapter *adap;
+	struct resource *res;
+	struct device *dev = &pdev->dev;
+	struct sam_platform_data *pdata = dev_get_platdata(&pdev->dev);
+
+	/*
+	 * Allocate memory for the SAM FPGA info
+	 */
+	sam = devm_kzalloc(dev, sizeof(*sam), GFP_KERNEL);
+	if (!sam)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, sam);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	if (pdata)
+		sam->irq = platform_get_irq(pdev, 0);
+
+	sam->membase = devm_ioremap_nocache(dev, res->start,
+					    resource_size(res));
+	if (!sam->membase)
+		return -ENOMEM;
+
+	sam->dev = dev;
+	sam->pdata = pdata;
+
+	err = sam_core_of_init(dev, sam, res);
+	if (err)
+		return err;
+
+	/***** i2c init *****/
+
+	for (i = 0; i < sam->num_master; i++) {
+		adap = sam_i2c_init_one(sam, i);
+		if (IS_ERR(adap)) {
+			err = PTR_ERR(adap);
+			dev_err(dev,
+				"Failed to initialize adapter %d [base %d, index %d]: %d\n",
+				sam->first_master + i, sam->first_master, i,
+				err);
+			goto err_remove;
+		}
+		sam->adap[i] = adap;
+	}
+
+	if (sam->irq >= 0) {
+		err = devm_request_any_context_irq(dev, sam->irq,
+						sam_i2c_irq_handler, 0,
+						dev_name(dev), sam);
+		if (err < 0) {
+			dev_err(dev, "Failed to request interrupt %d: %d\n",
+				sam->irq, err);
+			goto err_remove;
+		}
+		pdata->enable_irq(dev->parent, SAM_IRQ_I2C, sam->irq,
+				  (1 << sam->num_master) - 1);
+	}
+
+	return 0;
+
+err_remove:
+	for (i--; i >= 0; i--)
+		sam_i2c_cleanup_one(sam->adap[i]);
+	return err;
+}
+
+static int sam_i2c_remove(struct platform_device *pdev)
+{
+	struct sam_i2c_data *sam = platform_get_drvdata(pdev);
+	struct sam_platform_data *pdata = sam->pdata;
+	int i;
+
+	if (sam->irq >= 0 && pdata)
+		pdata->disable_irq(pdev->dev.parent, SAM_IRQ_I2C, sam->irq,
+			(1 << sam->num_master) - 1);
+	for (i = 0; i < sam->num_master; i++)
+		sam_i2c_cleanup_one(sam->adap[i]);
+
+	return 0;
+}
+
+static struct platform_driver sam_i2c_driver = {
+	.driver = {
+		.name   = "i2c-sam",
+		.owner  = THIS_MODULE,
+		.of_match_table = sam_i2c_of_match,
+	},
+	.probe  = sam_i2c_probe,
+	.remove = sam_i2c_remove,
+};
+
+module_platform_driver(sam_i2c_driver);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+
+module_param(sam_debug, int, S_IWUSR | S_IRUGO);
-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:18:38 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:18:38 +0300
Subject: [PATCH 10/10] net: mdio-sam: Add device tree documentation for SAM
 MDIO
In-Reply-To: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853518-22264-11-git-send-email-pantelis.antoniou@konsulko.com>

From: Georgi Vlaev <gvlaev at juniper.net>

Add device tree bindings document for the SAM MDIO block
present in Juniper's SAM FPGA.

Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 Documentation/devicetree/bindings/net/mdio-sam.txt | 48 ++++++++++++++++++++++
 1 file changed, 48 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/mdio-sam.txt

diff --git a/Documentation/devicetree/bindings/net/mdio-sam.txt b/Documentation/devicetree/bindings/net/mdio-sam.txt
new file mode 100644
index 0000000..7d354e0
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/mdio-sam.txt
@@ -0,0 +1,48 @@
+Juniper SAM FPGA MFD MDIO bus properties.
+
+Required properties:
+- compatible : "jnx,mdio-sam"
+- reg : The start offset of the MDIO bus range
+- #address-cells = <1>;
+- #size-cells = <0>;
+
+Optional properties:
+
+Required properties for child nodes:
+- #address-cells = <1>;
+- #size-cells = <0>;
+- reg : The MDIO bus offset within the MDIO range.
+
+
+Example :
+
+	sam at 10 {
+		compatible = "jnx,sam";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		mdio-sam at 10 {
+			compatible = "jnx,mdio-sam";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0x40000>;
+
+			mdio0: mdio-sam at 0 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				reg = <0x0>;
+			};
+
+			mdio1: mdio-sam at 4000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				reg = <0x4000>;
+			};
+
+			mdio2: mdio-sam at 8000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				reg = <0x8000>;
+			};
+		};
+	};
-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:18:37 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:18:37 +0300
Subject: [PATCH 09/10] net: phy: Add MDIO driver for Juniper's SAM FPGA
In-Reply-To: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853518-22264-10-git-send-email-pantelis.antoniou@konsulko.com>

From: Georgi Vlaev <gvlaev at juniper.net>

Add driver for the MDIO IP block present in Juniper's
SAM FPGA.

This driver supports only Clause 45 of the 802.3 spec.

Note that due to the fact that there are no drivers for
Broadcom/Avago retimers on 10/40Ge path that are controlled
from the MDIO interface there is a method to have direct
access to registers via a debugfs interface.

Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 drivers/net/phy/Kconfig    |   8 +
 drivers/net/phy/Makefile   |   1 +
 drivers/net/phy/mdio-sam.c | 564 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 573 insertions(+)
 create mode 100644 drivers/net/phy/mdio-sam.c

diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 5078a0d..7d7f265 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -122,6 +122,14 @@ config MDIO_OCTEON
 	  buses. It is required by the Octeon and ThunderX ethernet device
 	  drivers on some systems.
 
+config MDIO_SAM
+	tristate "Juniper Networks SAM FPGA MDIO controller"
+	depends on MFD_JUNIPER_SAM
+	help
+	  This module provides a driver for the Juniper Network SAM FPGA MDIO
+	  buses. This hardware can be found in the Gladiator PIC SAM FPGA. This
+	  driver is client of the sam-core MFD driver.
+
 config MDIO_SUN4I
 	tristate "Allwinner sun4i MDIO interface support"
 	depends on ARCH_SUNXI
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index e58667d..c7631cf 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_MDIO_GPIO)		+= mdio-gpio.o
 obj-$(CONFIG_MDIO_HISI_FEMAC)	+= mdio-hisi-femac.o
 obj-$(CONFIG_MDIO_MOXART)	+= mdio-moxart.o
 obj-$(CONFIG_MDIO_OCTEON)	+= mdio-octeon.o
+obj-$(CONFIG_MDIO_SAM)		+= mdio-sam.o
 obj-$(CONFIG_MDIO_SUN4I)	+= mdio-sun4i.o
 obj-$(CONFIG_MDIO_THUNDER)	+= mdio-thunder.o
 obj-$(CONFIG_MDIO_XGENE)	+= mdio-xgene.o
diff --git a/drivers/net/phy/mdio-sam.c b/drivers/net/phy/mdio-sam.c
new file mode 100644
index 0000000..73cefa1
--- /dev/null
+++ b/drivers/net/phy/mdio-sam.c
@@ -0,0 +1,564 @@
+/*
+ * Juniper Networks SAM FPGA MDIO driver.
+ *
+ * Copyright (c) 2015, Juniper Networks
+ * Author: Georgi Vlaev <gvlaev at juniper.net>
+ *
+ * The MDIO bus driver supports GPQAM, GPCAM, GPQ28 FPGAs found
+ * on Juniper's 10/40/100GE Gladiator PIC cards. Only Clause 45
+ * access is currently available natively.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/of_mdio.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#endif
+
+#define MDIO_CMD1	0x0000 /* Command Table 1 */
+#define MDIO_CMD2	0x0800 /* Command Table 2 */
+#define MDIO_RESULT	0x1000 /* Result Table (RO) */
+#define MDIO_PRI_CMD1	0x1800 /* Priority Command Table 1 */
+#define MDIO_PRI_CMD2	0x2000 /* Priority Command Table 1 */
+#define MDIO_PRI_RESULT	0x2800 /* Priority Result Table (RO) */
+#define MDIO_TBL_CMD	0x3000 /* Table Command Register (WO) */
+#define MDIO_STATUS	0x3008 /* Master Status (RO) */
+#define MDIO_STATUS_INT	0x3010 /* Master Status Interrupt Mask (W1C) */
+
+/* MDIO_TBL_CMD */
+#define TBL_CMD_REG_ABORT	BIT(31) /* Regular Table ABORT */
+#define TBL_CMD_REG_GO		BIT(30) /* Regular Table GO */
+#define TBL_CMD_PRI_ABORT	BIT(29) /* Priority Table Abort */
+#define TBL_CMD_PRI_GO		BIT(28) /* Priority Table GO */
+#define TBL_CMD_SOFT_RESET	BIT(27) /* Soft Reset */
+
+/* MDIO_STATUS */
+#define STAT_REG_RDY	BIT(31) /* READY for Programming Regular Table */
+#define STAT_REG_DONE	BIT(30)	/* DONE SUCCESSFULLY WITH REGULAR TABLE */
+#define STAT_PRI_RDY	BIT(29) /* READY for Programming Priority Table */
+#define STAT_PRI_DONE	BIT(28) /* DONE SUCCESSFULLY WITH PRIORITY TABLE */
+#define STAT_REG_ERR	BIT(27) /* DONE WITH ERRORS for Regular Table */
+#define STAT_PRI_ERR	BIT(26) /* DONE WITH ERRORS for Priority Table */
+#define STAT_REG_PROG_ERR	BIT(25) /* Programming Err for Regular Table */
+#define STAT_PRI_PROG_ERR	BIT(24) /* Programming Err for Priority Table */
+
+/* MDIO_CMD2, MDIO_PRI_CMD2 */
+#define CMD2_ENABLE	BIT(17)
+#define CMD2_READ	BIT(16)
+
+/* MDIO_RESULT, MDIO_PRI_RESULT */
+#define RES_SUCCESS	BIT(17)
+#define RES_ERROR	BIT(16)
+
+#define MDIO_RDY_TMO	30 /* in msec */
+
+struct mdio_sam_data {
+	void __iomem *base;
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dir;
+	/* Clause 45 addressing
+	 * addr[5]: PHYAD
+	 * reg[21]: DEVAD 5 bits + REG 16 bits
+	 * value[16]
+	 */
+	u8 addr;	/* phyad */
+	u32 reg;	/* devad + reg = (devad & 0x1f) << 16 | reg */
+	u16 value;	/* value */
+#endif
+};
+
+/* raw_io binary attribute: read/write any device on the bus */
+static ssize_t
+mdio_sam_sysfs_write_raw_io(struct file *filp,
+			    struct kobject *kobj,
+			    struct bin_attribute *attr,
+			    char *buf, loff_t offset, size_t size)
+{
+	struct mii_bus *bus = to_mii_bus(container_of(kobj,
+					struct device, kobj));
+	int ret;
+	u32 reg = offset & 0x1fffff;
+	u8 phy = (offset >> 21) & 0x1f;
+
+	if (size != 2)
+		return -EINVAL;
+
+	ret = mdiobus_write(bus, phy, reg | MII_ADDR_C45, *(u16 *)buf);
+	if (ret)
+		return ret;
+
+	return size;
+}
+
+static ssize_t
+mdio_sam_sysfs_read_raw_io(struct file *filp,
+			   struct kobject *kobj,
+			   struct bin_attribute *attr,
+			   char *buf, loff_t offset, size_t size)
+{
+	struct mii_bus *bus = to_mii_bus(container_of(kobj,
+					struct device, kobj));
+	int ret;
+	u32 reg = offset & 0x1fffff;
+	u8 phy = (offset >> 21) & 0x1f;
+
+	if (size != 2)
+		return -EINVAL;
+
+	ret = mdiobus_read(bus, phy, reg | MII_ADDR_C45);
+	if (ret < 0)
+		return ret;
+
+	*(u16 *)buf = (u16)ret;
+
+	return size;
+}
+
+static struct bin_attribute bin_attr_raw_io = {
+	.attr = {.name = "raw_io", .mode = (S_IRUGO | S_IWUSR)},
+	.size = 0x4000000,
+	.read = mdio_sam_sysfs_read_raw_io,
+	.write = mdio_sam_sysfs_write_raw_io,
+};
+
+#ifdef CONFIG_DEBUG_FS
+/* debugfs: set/get register offset */
+static int mdio_sam_debugfs_addr_print(struct seq_file *s, void *p)
+{
+	struct mdio_sam_data *data = (struct mdio_sam_data *)s->private;
+
+	seq_printf(s, "0x%02x\n", data->addr);
+
+	return 0;
+}
+
+static int mdio_sam_debugfs_addr_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, mdio_sam_debugfs_addr_print, inode->i_private);
+}
+
+static ssize_t
+mdio_sam_debugfs_addr_write(struct file *file, const char __user *user_buf,
+			    size_t count, loff_t *ppos)
+{
+	struct mdio_sam_data *data =
+		((struct seq_file *)(file->private_data))->private;
+	unsigned long addr;
+	int err;
+
+	err = kstrtoul_from_user(user_buf, count, 0, &addr);
+	if (err)
+		return err;
+
+	if (addr > 0x1f)
+		return -EINVAL;
+
+	data->addr = (u8)(addr);
+
+	return count;
+}
+
+static const struct file_operations mdio_sam_debugfs_addr_fops = {
+	.open = mdio_sam_debugfs_addr_open,
+	.write = mdio_sam_debugfs_addr_write,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
+/* debugfs: set/get register offset */
+static int mdio_sam_debugfs_reg_print(struct seq_file *s, void *p)
+{
+	struct mdio_sam_data *data = (struct mdio_sam_data *)s->private;
+
+	seq_printf(s, "0x%06X\n", data->reg);
+
+	return 0;
+}
+
+static int mdio_sam_debugfs_reg_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, mdio_sam_debugfs_reg_print, inode->i_private);
+}
+
+static ssize_t
+mdio_sam_debugfs_reg_write(struct file *file, const char __user *user_buf,
+			   size_t count, loff_t *ppos)
+{
+	struct mdio_sam_data *data =
+		((struct seq_file *)(file->private_data))->private;
+	unsigned long reg;
+	int err;
+
+	err = kstrtoul_from_user(user_buf, count, 0, &reg);
+	if (err)
+		return err;
+
+	if (reg > 0x1fffff)
+		return -EINVAL;
+
+	data->reg = reg;
+
+	return count;
+}
+
+static const struct file_operations mdio_sam_debugfs_reg_fops = {
+	.open = mdio_sam_debugfs_reg_open,
+	.write = mdio_sam_debugfs_reg_write,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
+/* debugfs: set/get register value */
+static int mdio_sam_debugfs_val_print(struct seq_file *s, void *p)
+{
+	struct mii_bus *bus = (struct mii_bus *)s->private;
+	struct mdio_sam_data *data = bus->priv;
+	int ret;
+
+	ret = mdiobus_read(bus, data->addr, data->reg | MII_ADDR_C45);
+	if (ret < 0)
+		return ret;
+
+	seq_printf(s, "0x%04X\n", ret);
+	return 0;
+}
+
+static int mdio_sam_debugfs_val_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, mdio_sam_debugfs_val_print, inode->i_private);
+}
+
+static ssize_t
+mdio_sam_debugfs_val_write(struct file *file, const char __user *user_buf,
+			   size_t count, loff_t *ppos)
+{
+	struct mii_bus *bus =
+		((struct seq_file *)(file->private_data))->private;
+	struct mdio_sam_data *data = bus->priv;
+	unsigned long value;
+	int ret;
+
+	ret = kstrtoul_from_user(user_buf, count, 0, &value);
+	if (ret)
+		return ret;
+
+	ret = mdiobus_write(bus, data->addr, data->reg | MII_ADDR_C45, value);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static const struct file_operations mdio_sam_debugfs_val_fops = {
+	.open = mdio_sam_debugfs_val_open,
+	.write = mdio_sam_debugfs_val_write,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
+static int mdio_sam_debugfs_init(struct mii_bus *bus)
+{
+	struct dentry *file;
+	struct mdio_sam_data *data = bus->priv;
+
+	data->dir = debugfs_create_dir(bus->id, NULL);
+	if (!data->dir)
+		return -ENOMEM;
+
+/* phy */
+	file = debugfs_create_file("addr", (S_IRUGO | S_IWUSR),
+				   data->dir, data,
+				   &mdio_sam_debugfs_addr_fops);
+	if (!file)
+		goto err;
+
+/* reg */
+	file = debugfs_create_file("reg", (S_IRUGO | S_IWUSR),
+				   data->dir, data,
+				   &mdio_sam_debugfs_reg_fops);
+	if (!file)
+		goto err;
+
+/* value */
+	file = debugfs_create_file("value", (S_IRUGO | S_IWUSR),
+				   data->dir, bus,
+				   &mdio_sam_debugfs_val_fops);
+	if (!file)
+		goto err;
+
+	return 0;
+err:
+	debugfs_remove_recursive(data->dir);
+	dev_err(&bus->dev, "failed to create debugfs entries.\n");
+
+	return -ENOMEM;
+}
+
+static void mdio_sam_debugfs_remove(struct mii_bus *bus)
+{
+	struct mdio_sam_data *data = bus->priv;
+
+	debugfs_remove_recursive(data->dir);
+}
+#endif
+
+static int mdio_sam_stat_wait(struct mii_bus *bus, u32 wait_mask)
+{
+	struct mdio_sam_data *data = bus->priv;
+	unsigned long timeout;
+	u32 stat;
+
+	timeout = jiffies + msecs_to_jiffies(MDIO_RDY_TMO);
+	do {
+		stat = ioread32(data->base + MDIO_STATUS);
+		if (stat & wait_mask)
+			return 0;
+
+		usleep_range(50, 100);
+	} while (time_before(jiffies, timeout));
+
+	return -EBUSY;
+}
+
+static int mdio_sam_read(struct mii_bus *bus, int phy_id, int regnum)
+{
+	struct mdio_sam_data *data = bus->priv;
+	u32 command, res;
+	int ret;
+
+	/* mdiobus_read holds the bus->mdio_lock mutex */
+
+	if (!(regnum & MII_ADDR_C45))
+		return -ENXIO;
+
+	ret = mdio_sam_stat_wait(bus, STAT_REG_RDY);
+	if (ret < 0)
+		return ret;
+
+	command = regnum & 0x1fffff; /* regnum = (dev_id << 16) | reg */
+	command |= ((phy_id & 0x1f) << 21);
+
+	iowrite32(command, data->base + MDIO_CMD1);
+	ioread32(data->base + MDIO_CMD1);
+	iowrite32(CMD2_READ | CMD2_ENABLE, data->base + MDIO_CMD2);
+	ioread32(data->base + MDIO_CMD2);
+	iowrite32(TBL_CMD_REG_GO, data->base + MDIO_TBL_CMD);
+	ioread32(data->base + MDIO_TBL_CMD);
+
+	usleep_range(50, 100);
+
+	ret = mdio_sam_stat_wait(bus, (STAT_REG_DONE | STAT_REG_ERR));
+	if (ret < 0)
+		return ret;
+
+	res = ioread32(data->base + MDIO_RESULT);
+
+	if (res & RES_ERROR || !(res & RES_SUCCESS))
+		return -EIO;
+
+	return (res & 0xffff);
+}
+
+static int mdio_sam_write(struct mii_bus *bus, int phy_id, int regnum, u16 val)
+{
+	struct mdio_sam_data *data = bus->priv;
+	u32 command;
+	int ret;
+
+	/* mdiobus_write holds the bus->mdio_lock mutex */
+
+	if (!(regnum & MII_ADDR_C45))
+		return -ENXIO;
+
+	ret = mdio_sam_stat_wait(bus, STAT_REG_RDY);
+	if (ret < 0)
+		return ret;
+
+	command = regnum & 0x1fffff; /* regnum = (dev_id << 16) | reg */
+	command |= ((phy_id & 0x1f) << 21);
+
+	iowrite32(command, data->base + MDIO_CMD1);
+	ioread32(data->base + MDIO_CMD1);
+	iowrite32(CMD2_ENABLE | val, data->base + MDIO_CMD2);
+	ioread32(data->base + MDIO_CMD2);
+	iowrite32(TBL_CMD_REG_GO, data->base + MDIO_TBL_CMD);
+	ioread32(data->base + MDIO_TBL_CMD);
+
+	usleep_range(50, 100);
+
+	ret = mdio_sam_stat_wait(bus, (STAT_REG_DONE | STAT_REG_ERR));
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int mdio_sam_reset(struct mii_bus *bus)
+{
+	struct mdio_sam_data *data = bus->priv;
+
+	iowrite32(TBL_CMD_SOFT_RESET, data->base + MDIO_TBL_CMD);
+	ioread32(data->base + MDIO_TBL_CMD);
+	mdelay(10);
+	iowrite32(0, data->base + MDIO_TBL_CMD);
+	ioread32(data->base + MDIO_TBL_CMD);
+
+	/* zero tables */
+	memset_io(data->base + MDIO_CMD1, 0, 0x1000);
+	memset_io(data->base + MDIO_PRI_CMD1, 0, 0x1000);
+
+	return 0;
+}
+
+static int mdio_sam_of_register_bus(struct platform_device *pdev,
+				    struct device_node *np, void __iomem *base)
+{
+	struct mii_bus *bus;
+	struct mdio_sam_data *data;
+	u32 reg;
+	int ret;
+
+	bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*data));
+	if (!bus)
+		return -ENOMEM;
+
+	/* bus offset */
+	ret = of_property_read_u32(np, "reg", &reg);
+	if (ret)
+		return -ENODEV;
+
+	data = bus->priv;
+	data->base = base + reg;
+
+	bus->parent = &pdev->dev;
+	bus->name = "mdio-sam";
+	bus->read = mdio_sam_read;
+	bus->write = mdio_sam_write;
+	bus->reset = mdio_sam_reset;
+	snprintf(bus->id, MII_BUS_ID_SIZE, "mdiosam-%x-%x", pdev->id, reg);
+
+	ret = of_mdiobus_register(bus, np);
+	if (ret < 0)
+		return ret;
+#ifdef CONFIG_DEBUG_FS
+	ret = mdio_sam_debugfs_init(bus);
+	if (ret < 0)
+		goto err_unregister;
+#endif
+	ret = device_create_bin_file(&bus->dev, &bin_attr_raw_io);
+	if (ret)
+		goto err_debugfs;
+
+	return 0;
+
+err_debugfs:
+#ifdef CONFIG_DEBUG_FS
+	mdio_sam_debugfs_remove(bus);
+#endif
+err_unregister:
+	mdiobus_unregister(bus);
+
+	return ret;
+}
+
+static int mdio_sam_of_unregister_bus(struct device_node *np)
+{
+	struct mii_bus *bus;
+
+	bus = of_mdio_find_bus(np);
+	if (bus) {
+		device_remove_bin_file(&bus->dev, &bin_attr_raw_io);
+#ifdef CONFIG_DEBUG_FS
+		mdio_sam_debugfs_remove(bus);
+#endif
+		mdiobus_unregister(bus);
+	}
+	return 0;
+}
+
+static int mdio_sam_probe(struct platform_device *pdev)
+{
+	struct device_node *np;
+	struct resource *res;
+	void __iomem *base;
+	int ret;
+
+	if (!pdev->dev.of_node)
+		return -ENODEV;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_nocache(&pdev->dev, res->start,
+				    resource_size(res));
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	for_each_available_child_of_node(pdev->dev.of_node, np) {
+		ret = mdio_sam_of_register_bus(pdev, np, base);
+		if (ret)
+			goto err;
+	}
+
+	return 0;
+err:
+	/* roll back everything */
+	for_each_available_child_of_node(pdev->dev.of_node, np)
+		mdio_sam_of_unregister_bus(np);
+
+	return ret;
+}
+
+static int mdio_sam_remove(struct platform_device *pdev)
+{
+	struct device_node *np;
+
+	for_each_available_child_of_node(pdev->dev.of_node, np)
+		mdio_sam_of_unregister_bus(np);
+
+	return 0;
+}
+
+static const struct of_device_id mdio_sam_of_match[] = {
+	{ .compatible = "jnx,mdio-sam" },
+	{  }
+};
+MODULE_DEVICE_TABLE(of, mdio_sam_of_match);
+
+static struct platform_driver mdio_sam_driver = {
+	.probe = mdio_sam_probe,
+	.remove = mdio_sam_remove,
+	.driver = {
+		.name = "mdio-sam",
+		.owner = THIS_MODULE,
+		.of_match_table = mdio_sam_of_match,
+	},
+};
+
+module_platform_driver(mdio_sam_driver);
+
+MODULE_ALIAS("platform:mdio-sam");
+MODULE_AUTHOR("Georgi Vlaev <gvlaev at juniper.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Juniper Networks SAM MDIO bus driver");
-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:19:30 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:19:30 +0300
Subject: [PATCH 0/4] Introduce Juniper PTXPMB Extended driver
Message-ID: <1475853574-22339-1-git-send-email-pantelis.antoniou@konsulko.com>

Add Juniper's PTXPMB Extended FPGA driver. Those FPGAs
are present in Juniper's PTX series of routers.

The MFD driver provices a gpio device.

There are full device tree binding documents for the
master mfd driver and for the slave driver.

This patchset is against mainline as of today: v4.8-9431-g3477d16
and is dependent on the "Juniper prerequisites" and
"Juniper infrastructure" patchsets sent earlier.

Georgi Vlaev (2):
  mfd: ptxpmb-ext-cpld: Add documentation for PTXPMB extended CPLD
  gpio: ptxpmb-ext-cpld: Document bindings of PTXPMB extended CPLD

Guenter Roeck (2):
  mfd: ptxpmb: Add separate driver for extended CPLD
  gpio: ptxpmb-ext-cpld: Add driver for Juniper's PTXPMB extended CPLD

 .../bindings/gpio/jnx,gpio-ptxpmb-ext-cpld.txt     |  36 ++
 .../bindings/mfd/jnx-ptxpmb-ext-cpld.txt           |  35 ++
 drivers/gpio/Kconfig                               |  11 +
 drivers/gpio/Makefile                              |   1 +
 drivers/gpio/gpio-ptxpmb-ext-cpld.c                | 430 +++++++++++++++++++++
 drivers/mfd/Kconfig                                |  13 +
 drivers/mfd/Makefile                               |   1 +
 drivers/mfd/ptxpmb-ext-cpld-core.c                 | 221 +++++++++++
 include/linux/mfd/ptxpmb_ext_cpld.h                |  42 ++
 9 files changed, 790 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/gpio/jnx,gpio-ptxpmb-ext-cpld.txt
 create mode 100644 Documentation/devicetree/bindings/mfd/jnx-ptxpmb-ext-cpld.txt
 create mode 100644 drivers/gpio/gpio-ptxpmb-ext-cpld.c
 create mode 100644 drivers/mfd/ptxpmb-ext-cpld-core.c
 create mode 100644 include/linux/mfd/ptxpmb_ext_cpld.h

-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:19:31 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:19:31 +0300
Subject: [PATCH 1/4] mfd: ptxpmb: Add separate driver for extended CPLD
In-Reply-To: <1475853574-22339-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853574-22339-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853574-22339-2-git-send-email-pantelis.antoniou@konsulko.com>

From: Guenter Roeck <groeck at juniper.net>

Extended CPLD only exists on certain boards (SPMB) and by itself requires
an MFD driver, since it supports its own interrupts and sub-devices.
It also needs to provide support for SIB hotplug. It is cleaner and easier
to maintain it as separate driver.

Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
Signed-off-by: Guenter Roeck <groeck at juniper.net>
Signed-off-by: JawaharBalaji Thirumalaisamy <jawaharb at juniper.net>
Signed-off-by: Tom Kavanagh <tkavanagh at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 drivers/mfd/Kconfig                 |  13 +++
 drivers/mfd/Makefile                |   1 +
 drivers/mfd/ptxpmb-ext-cpld-core.c  | 221 ++++++++++++++++++++++++++++++++++++
 include/linux/mfd/ptxpmb_ext_cpld.h |  42 +++++++
 4 files changed, 277 insertions(+)
 create mode 100644 drivers/mfd/ptxpmb-ext-cpld-core.c
 create mode 100644 include/linux/mfd/ptxpmb_ext_cpld.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 75b46a1..7e1fa14 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1371,6 +1371,19 @@ config MFD_JUNIPER_SAM
 	  This driver can be built as a module. If built as a module it will be
 	  called "sam-core"
 
+config MFD_JUNIPER_EXT_CPLD
+	tristate "Juniper PTX PMB Extended CPLD"
+	depends on PTXPMB_COMMON
+	default y if PTXPMB_COMMON
+	select MFD_CORE
+	help
+	  Select this to enable the PTX PMB Extended CPLD multi-function kernel
+	  driver for the applicable Juniper platforms.
+
+	  This driver can be built as a module. If built as a module it will be
+	  called "ptxpmb-ext-cpld"
+
+
 config MFD_TWL4030_AUDIO
 	bool "TI TWL4030 Audio"
 	depends on TWL4030_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 71a8ba6..da94482 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -150,6 +150,7 @@ obj-$(CONFIG_AB8500_DEBUG)	+= ab8500-debugfs.o
 obj-$(CONFIG_AB8500_GPADC)	+= ab8500-gpadc.o
 obj-$(CONFIG_MFD_JUNIPER_CPLD)	+= ptxpmb-cpld-core.o
 obj-$(CONFIG_MFD_JUNIPER_SAM)	+= sam-core.o
+obj-$(CONFIG_MFD_JUNIPER_EXT_CPLD) += ptxpmb-ext-cpld-core.o
 obj-$(CONFIG_MFD_DB8500_PRCMU)	+= db8500-prcmu.o
 # ab8500-core need to come after db8500-prcmu (which provides the channel)
 obj-$(CONFIG_AB8500_CORE)	+= ab8500-core.o ab8500-sysctrl.o
diff --git a/drivers/mfd/ptxpmb-ext-cpld-core.c b/drivers/mfd/ptxpmb-ext-cpld-core.c
new file mode 100644
index 0000000..a1b1793
--- /dev/null
+++ b/drivers/mfd/ptxpmb-ext-cpld-core.c
@@ -0,0 +1,221 @@
+/*
+ * Juniper PTX PMB Extended CPLD multi-function core driver
+ *
+ * Copyright (C) 2012 Juniper Networks
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/mfd/core.h>
+#include <linux/of.h>
+#include <linux/sched.h>
+#include <linux/mfd/ptxpmb_ext_cpld.h>
+#include <linux/jnx/jnx-subsys.h>
+
+struct pmb_ext_cpld_core {
+	struct device		*dev;
+	struct pmb_boot_cpld_ext __iomem *cpld;
+	spinlock_t		lock;
+	int			irq0, irq1;
+	wait_queue_head_t	wqh;
+};
+
+static irqreturn_t pmb_ext_cpld_core_interrupt(int irq, void *dev_data)
+{
+	struct pmb_ext_cpld_core *cpld = dev_data;
+	unsigned char __iomem *data;
+	int i;
+	u8 buffer[48];
+
+	dev_info(cpld->dev, "interrupt %d sib presence=0x%x irq status=0x%x\n",
+		 irq, ioread16(&cpld->cpld->sib_presence),
+		 ioread16(&cpld->cpld->sib_irq_status));
+
+	data = (u8 *)cpld->cpld;
+	for (i = 0; i < 48; i++)
+		buffer[i] = ioread8(data + i);
+
+	print_hex_dump(KERN_INFO, dev_name(cpld->dev), DUMP_PREFIX_OFFSET,
+		       16, 4, buffer, 48, false);
+
+	spin_lock(&cpld->wqh.lock);
+
+	/* clear interrupt, wake up any handlers */
+	wake_up_locked(&cpld->wqh);
+
+	spin_unlock(&cpld->wqh.lock);
+
+	return IRQ_HANDLED;
+}
+
+static ssize_t show_sib_status(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct pmb_ext_cpld_core *cpld = dev_get_drvdata(dev);
+
+	WARN_ONCE(1,
+		  "sib_status is deprecated and should no longer be used for presence detection\n");
+
+	return sprintf(buf, "0x%04x\n",
+		       ioread16(&cpld->cpld->sib_presence));
+}
+
+static DEVICE_ATTR(sib_status, S_IRUGO, show_sib_status, NULL);
+
+static struct resource pmb_ext_cpld_resources[] = {
+	{
+		.start	= 0,
+		.end	= sizeof(struct pmb_boot_cpld_ext) - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct mfd_cell pmb_ext_cpld_cells[] = {
+	{
+		.name = "gpio-ptxpmb-ext-cpld",
+		.num_resources = ARRAY_SIZE(pmb_ext_cpld_resources),
+		.resources = pmb_ext_cpld_resources,
+		.of_compatible = "jnx,gpio-ptxpmb-ext-cpld",
+	},
+};
+
+static int pmb_ext_cpld_core_probe(struct platform_device *pdev)
+{
+	static struct pmb_ext_cpld_core *cpld;
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	int error;
+	u16 asid;
+
+	cpld = devm_kzalloc(dev, sizeof(*cpld), GFP_KERNEL);
+	if (!cpld)
+		return -ENOMEM;
+
+	cpld->dev = dev;
+	dev_set_drvdata(dev, cpld);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	cpld->cpld = devm_ioremap_resource(dev, res);
+	if (IS_ERR(cpld->cpld))
+		return PTR_ERR(cpld->cpld);
+
+	cpld->irq0 = platform_get_irq(pdev, 0);
+	if (cpld->irq0 >= 0) {
+		error = devm_request_threaded_irq(dev, cpld->irq0, NULL,
+						  pmb_ext_cpld_core_interrupt,
+						  IRQF_TRIGGER_RISING |
+						  IRQF_TRIGGER_FALLING |
+						  IRQF_ONESHOT,
+						  dev_name(dev), cpld);
+		if (error < 0)
+			return error;
+	}
+
+	cpld->irq1 = platform_get_irq(pdev, 1);
+	if (cpld->irq1 >= 0) {
+		error = devm_request_threaded_irq(dev, cpld->irq1, NULL,
+						  pmb_ext_cpld_core_interrupt,
+						  IRQF_TRIGGER_RISING |
+						  IRQF_TRIGGER_FALLING |
+						  IRQF_ONESHOT,
+						  dev_name(dev), cpld);
+		if (error < 0)
+			return error;
+	}
+
+	spin_lock_init(&cpld->lock);
+	init_waitqueue_head(&cpld->wqh);
+
+	asid = ioread16be(&cpld->cpld->cb_assembly_id);
+
+	dev_info(dev, "Ext CPLD rev %u.%u CB asy 0x%x CB rev %u.%u\n",
+		 ioread8(&cpld->cpld->major_rev),
+		 ioread8(&cpld->cpld->minor_rev),
+		 asid,
+		 ioread8(&cpld->cpld->cb_major_version),
+		 ioread8(&cpld->cpld->cb_minor_version));
+
+	dev_info(dev, "SIB status=0x%x SIB irq status=0x%x\n",
+		 ioread16(&cpld->cpld->sib_presence),
+		 ioread16(&cpld->cpld->sib_irq_status));
+
+	error = device_create_file(dev, &dev_attr_sib_status);
+	if (error)
+		return error;
+	error = mfd_add_devices(dev, pdev->id, pmb_ext_cpld_cells,
+				ARRAY_SIZE(pmb_ext_cpld_cells), res,
+				0, NULL);
+	if (error < 0)
+		goto abort;
+
+	iowrite16(0xffff, &cpld->cpld->sib_presence_irq_en);
+	iowrite16(0xffff, &cpld->cpld->sib_irq_en);
+
+	return 0;
+
+abort:
+	device_remove_file(dev, &dev_attr_sib_status);
+	return error;
+}
+
+static int pmb_ext_cpld_core_remove(struct platform_device *pdev)
+{
+	mfd_remove_devices(&pdev->dev);
+	device_remove_file(&pdev->dev, &dev_attr_sib_status);
+	return 0;
+}
+
+static const struct of_device_id pmb_ext_cpld_of_ids[] = {
+	{ .compatible = "jnx,ptxpmb-ext-cpld" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pmb_ext_cpld_of_ids);
+
+static struct platform_driver pmb_ext_cpld_core_driver = {
+	.probe		= pmb_ext_cpld_core_probe,
+	.remove		= pmb_ext_cpld_core_remove,
+	.driver		= {
+		.name	= "ptxpmb-ext-cpld",
+		.of_match_table = pmb_ext_cpld_of_ids,
+		.owner	= THIS_MODULE,
+	}
+};
+
+static int __init pmb_ext_cpld_core_init(void)
+{
+	return platform_driver_register(&pmb_ext_cpld_core_driver);
+}
+module_init(pmb_ext_cpld_core_init);
+
+static void __exit pmb_ext_cpld_core_exit(void)
+{
+	platform_driver_unregister(&pmb_ext_cpld_core_driver);
+}
+module_exit(pmb_ext_cpld_core_exit);
+
+MODULE_DESCRIPTION("Juniper PTX PMB Extended CPLD Core Driver");
+MODULE_AUTHOR("Guenter Roeck <groeck at juniper.net>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ptxpmb-cpld");
diff --git a/include/linux/mfd/ptxpmb_ext_cpld.h b/include/linux/mfd/ptxpmb_ext_cpld.h
new file mode 100644
index 0000000..bac9a73
--- /dev/null
+++ b/include/linux/mfd/ptxpmb_ext_cpld.h
@@ -0,0 +1,42 @@
+/*---------------------------------------------------------------------------
+ *
+ * ptxpmb_ext_cpld_core.h
+ *     Copyright (c) 2012, 2013 Juniper Networks
+ *
+ *---------------------------------------------------------------------------
+ */
+
+#ifndef PTXPMB_EXT_CPLD_CORE_H
+#define PTXPMB_EXT_CPLD_CORE_H
+
+/*
+ * Extended CPLD registers
+ */
+struct pmb_boot_cpld_ext {
+	u8 major_rev;			/* 0x00 */
+	u8 minor_rev;			/* 0x01 */
+	u16 sib_presence;		/* 0x02 */
+	u8 unused0[4];			/* 0x04 */
+	u16 sib_presence_irq_en;	/* 0x08 */
+	u8 unused1[4];			/* 0x0a */
+	u16 sib_irq_status;		/* 0x0e */
+	u8 unused2[4];			/* 0x10 */
+	u16 sib_irq_en;			/* 0x14 */
+	u8 unused3[4];			/* 0x16 */
+	u8 i2c_group;			/* 0x1a */
+	u8 i2c_mux_sel;			/* 0x1b */
+	u8 re_status;			/* 0x1c */
+	u8 unused4[0x24 - 0x1d];	/* 0x1d */
+	u16 cb_assembly_id;		/* 0x24 */
+	u8 cb_major_version;		/* 0x26 */
+	u8 cb_minor_version;		/* 0x27 */
+	u8 unused5[0x40 - 0x28];	/* 0x28 */
+	u8 spare_a;			/* 0x40 */
+	u8 spare_b;			/* 0x41 */
+	u8 spare_c;			/* 0x42 */
+	u8 spare_d;			/* 0x43 */
+	u8 spare_e;			/* 0x44 */
+	u8 unused6[0x3ff - 0x45];	/* 0x45 */
+};
+
+#endif /* PTXPMB_EXT_CPLD_CORE_H */
-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:19:34 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:19:34 +0300
Subject: [PATCH 4/4] gpio: ptxpmb-ext-cpld: Document bindings of PTXPMB
 extended CPLD
In-Reply-To: <1475853574-22339-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853574-22339-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853574-22339-5-git-send-email-pantelis.antoniou@konsulko.com>

From: Georgi Vlaev <gvlaev at juniper.net>

Add device tree bindings document for the GPIO driver of
Juniper's PTXPMB extended CPLD.

Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 .../bindings/gpio/jnx,gpio-ptxpmb-ext-cpld.txt     | 36 ++++++++++++++++++++++
 1 file changed, 36 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/gpio/jnx,gpio-ptxpmb-ext-cpld.txt

diff --git a/Documentation/devicetree/bindings/gpio/jnx,gpio-ptxpmb-ext-cpld.txt b/Documentation/devicetree/bindings/gpio/jnx,gpio-ptxpmb-ext-cpld.txt
new file mode 100644
index 0000000..87f01b9
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/jnx,gpio-ptxpmb-ext-cpld.txt
@@ -0,0 +1,36 @@
+Juniper PTXPMB extended CPLD GPIO block
+
+Required properties:
+
+- compatible:
+    Must be "jnx,gpio-ptxpmb-ext-cpld"
+
+- #gpio-cells:
+    Should be <2>.  The first cell is the pin number (within the controller's
+    pin space), and the second is used for the following flags:
+	bit[0]: direction (0 = out, 1 = in)
+	bit[1]: init high
+	bit[2]: active low
+
+- gpio-controller:
+    Specifies that the node is a GPIO controller.
+
+- interrupt-controller:
+    Specifies that the node is an interrupt controller.
+
+Optional properties:
+
+- reg:
+    Address and length of the register set for the device. Usually supplied
+    by the parent MFD device.
+
+
+Example:
+
+gpio_ext_cpld: cpld-ext-gpio {
+	compatible = "jnx,gpio-ptxpmb-ext-cpld";
+	#gpio-cells = <2>;
+	#interrupt-cells = <2>;
+	gpio-controller;
+	interrupt-controller;
+};
-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:19:32 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:19:32 +0300
Subject: [PATCH 2/4] mfd: ptxpmb-ext-cpld: Add documentation for PTXPMB
 extended CPLD
In-Reply-To: <1475853574-22339-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853574-22339-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853574-22339-3-git-send-email-pantelis.antoniou@konsulko.com>

From: Georgi Vlaev <gvlaev at juniper.net>

Add DT bindings document for the PTXPMB extended CPLD device.

Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 .../bindings/mfd/jnx-ptxpmb-ext-cpld.txt           | 35 ++++++++++++++++++++++
 1 file changed, 35 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/jnx-ptxpmb-ext-cpld.txt

diff --git a/Documentation/devicetree/bindings/mfd/jnx-ptxpmb-ext-cpld.txt b/Documentation/devicetree/bindings/mfd/jnx-ptxpmb-ext-cpld.txt
new file mode 100644
index 0000000..098a548a
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/jnx-ptxpmb-ext-cpld.txt
@@ -0,0 +1,35 @@
+* Device tree bindings for Juniper's PTXPMB Extended CPLD FPGA MFD driver
+
+The device supports a gpio block which is described in the
+jnx-gpio-ptxpmb-ext-cpld document.
+
+Required properties:
+
+- compatible:		"jnx,ptxpmb-ext-cpld"
+
+- reg:			contains offset/length value for device state control
+			registers space.
+
+Optional properties:
+
+- interrupts:		The interrupt line(s) the /IRQ signal(s) for the device is
+			connected to.
+
+- interrupt-parent:	The parent interrupt controller.
+
+Example:
+
+ext-cpld at 1,0 {
+	compatible = "jnx,ptxpmb-ext-cpld";
+	reg = <0x1 0 0x1000>;
+	interrupt-parent = <&mpic>;
+	interrupts = <7 2>, <8 2>;
+
+	gpio_ext_cpld: cpld-ext-gpio {
+		compatible = "jnx,gpio-ptxpmb-ext-cpld";
+		#gpio-cells = <2>;
+		#interrupt-cells = <2>;
+		gpio-controller;
+		interrupt-controller;
+	};
+};
-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:19:33 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:19:33 +0300
Subject: [PATCH 3/4] gpio: ptxpmb-ext-cpld: Add driver for Juniper's PTXPMB
 extended CPLD
In-Reply-To: <1475853574-22339-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853574-22339-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853574-22339-4-git-send-email-pantelis.antoniou@konsulko.com>

From: Guenter Roeck <groeck at juniper.net>

This IP block is present in the PTXPMB extended CPLD present on
Junipers PTX series of routers and provides SIB connector status pins
as GPIO pins for use with other drivers.

Signed-off-by: Guenter Roeck <groeck at juniper.net>
Signed-off-by: JawaharBalaji Thirumalaisamy <jawaharb at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 drivers/gpio/Kconfig                |  11 +
 drivers/gpio/Makefile               |   1 +
 drivers/gpio/gpio-ptxpmb-ext-cpld.c | 430 ++++++++++++++++++++++++++++++++++++
 3 files changed, 442 insertions(+)
 create mode 100644 drivers/gpio/gpio-ptxpmb-ext-cpld.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index c25dbe9..281029b 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -371,6 +371,17 @@ config GPIO_PTXPMB_CPLD
 	  This driver can also be built as a module.  If so, the module
 	  will be called gpio-ptxpmb-cpld.
 
+config GPIO_PTXPMB_EXT_CPLD
+	tristate "PTXPMB Extended CPLD GPIO"
+	depends on MFD_JUNIPER_EXT_CPLD
+	default y if MFD_JUNIPER_EXT_CPLD
+	help
+	  This driver exports various bits on the Juniper Control Board
+	  Extended CPLD as GPIO pins to userspace.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called gpio-ptxpmb-ext-cpld.
+
 config GPIO_PXA
 	bool "PXA GPIO support"
 	depends on ARCH_PXA || ARCH_MMP
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 6691d8c..ec890c7 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -91,6 +91,7 @@ obj-$(CONFIG_GPIO_PCH)		+= gpio-pch.o
 obj-$(CONFIG_GPIO_PISOSR)	+= gpio-pisosr.o
 obj-$(CONFIG_GPIO_PL061)	+= gpio-pl061.o
 obj-$(CONFIG_GPIO_PTXPMB_CPLD)	+= gpio-ptxpmb-cpld.o
+obj-$(CONFIG_GPIO_PTXPMB_EXT_CPLD) += gpio-ptxpmb-ext-cpld.o
 obj-$(CONFIG_GPIO_PXA)		+= gpio-pxa.o
 obj-$(CONFIG_GPIO_RC5T583)	+= gpio-rc5t583.o
 obj-$(CONFIG_GPIO_RDC321X)	+= gpio-rdc321x.o
diff --git a/drivers/gpio/gpio-ptxpmb-ext-cpld.c b/drivers/gpio/gpio-ptxpmb-ext-cpld.c
new file mode 100644
index 0000000..0152f0b
--- /dev/null
+++ b/drivers/gpio/gpio-ptxpmb-ext-cpld.c
@@ -0,0 +1,430 @@
+/*
+ * Copyright (C) 2012 Juniper networks
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/gpio.h>
+#include <linux/errno.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+
+#include <linux/mfd/ptxpmb_ext_cpld.h>
+
+#define EXT_CPLD_NGPIO	32	/*  0..15: SIB presence bits	*/
+				/* 16..31: SIB interrupt status	*/
+
+/**
+ * struct ext_cpld_gpio - GPIO private data structure.
+ * @base: PCI base address of Memory mapped I/O register.
+ * @dev: Pointer to device structure.
+ * @gpio: Data for GPIO infrastructure.
+ */
+struct ext_cpld_gpio {
+	void __iomem *base;
+	struct device *dev;
+	struct gpio_chip gpio;
+	struct mutex irq_lock;
+	struct mutex work_lock;
+	struct irq_domain *domain;
+	int irq;
+	u8 irq_type[EXT_CPLD_NGPIO];
+	u16 sib_presence_cache;
+	u16 sib_presence_irq_enabled;
+	u16 sib_irq_status_cache;
+	u16 sib_irq_enabled;
+	struct delayed_work work;
+};
+
+static int ext_cpld_gpio_get(struct gpio_chip *gpio, unsigned int nr)
+{
+	struct ext_cpld_gpio *chip = container_of(gpio,
+						  struct ext_cpld_gpio, gpio);
+	struct pmb_boot_cpld_ext *cpld = chip->base;
+	u16 *addr = nr < 16 ? &cpld->sib_presence : &cpld->sib_irq_status;
+	u16 val;
+
+	val = ioread16(addr);
+	if (nr < 16)
+		chip->sib_presence_cache = val;
+	else
+		chip->sib_irq_status_cache = val;
+
+	return !!(val & (1 << (nr & 15)));
+}
+
+static int ext_cpld_gpio_direction_input(struct gpio_chip *gpio,
+					 unsigned int nr)
+{
+	/* all pins are input pins */
+	return 0;
+}
+
+static int ext_cpld_gpio_to_irq(struct gpio_chip *gpio, unsigned int offset)
+{
+	struct ext_cpld_gpio *chip = container_of(gpio,
+						  struct ext_cpld_gpio, gpio);
+
+	return irq_create_mapping(chip->domain, offset);
+}
+
+static void ext_cpld_irq_mask(struct irq_data *data)
+{
+	struct ext_cpld_gpio *chip = irq_data_get_irq_chip_data(data);
+	struct pmb_boot_cpld_ext *cpld = chip->base;
+	u16 *addr = data->hwirq < 16 ?
+		&cpld->sib_presence_irq_en : &cpld->sib_irq_en;
+	u16 mask = 1 << (data->hwirq & 0x0f);
+
+	if (chip->irq)
+		iowrite16(ioread16(addr) & ~mask, addr);
+
+	if (data->hwirq < 16)
+		chip->sib_presence_irq_enabled &= ~mask;
+	else
+		chip->sib_irq_enabled &= ~mask;
+}
+
+static void ext_cpld_irq_unmask(struct irq_data *data)
+{
+	struct ext_cpld_gpio *chip = irq_data_get_irq_chip_data(data);
+	struct pmb_boot_cpld_ext *cpld = chip->base;
+	u16 *addr = data->hwirq < 16 ?
+		&cpld->sib_presence_irq_en : &cpld->sib_irq_en;
+	u16 mask = 1 << (data->hwirq & 0x0f);
+
+	if (chip->irq)
+		iowrite16(ioread16(addr) | mask, addr);
+
+	if (data->hwirq < 16)
+		chip->sib_presence_irq_enabled |= mask;
+	else
+		chip->sib_irq_enabled |= mask;
+}
+
+static int ext_cpld_irq_set_type(struct irq_data *data, unsigned int type)
+{
+	struct ext_cpld_gpio *chip = irq_data_get_irq_chip_data(data);
+
+	chip->irq_type[data->hwirq] = type & 0x0f;
+
+	return 0;
+}
+
+static void ext_cpld_irq_bus_lock(struct irq_data *data)
+{
+	struct ext_cpld_gpio *chip = irq_data_get_irq_chip_data(data);
+
+	mutex_lock(&chip->irq_lock);
+}
+
+static void ext_cpld_irq_bus_unlock(struct irq_data *data)
+{
+	struct ext_cpld_gpio *chip = irq_data_get_irq_chip_data(data);
+
+	/* Synchronize interrupts to chip */
+
+	mutex_unlock(&chip->irq_lock);
+}
+
+static struct irq_chip ext_cpld_irq_chip = {
+	.name = "gpio-ext-cpld",
+	.irq_mask = ext_cpld_irq_mask,
+	.irq_unmask = ext_cpld_irq_unmask,
+	.irq_set_type = ext_cpld_irq_set_type,
+	.irq_bus_lock = ext_cpld_irq_bus_lock,
+	.irq_bus_sync_unlock = ext_cpld_irq_bus_unlock,
+};
+
+static int ext_cpld_gpio_irq_map(struct irq_domain *domain, unsigned int irq,
+				 irq_hw_number_t hwirq)
+{
+	pr_info("ext_cpld_gpio_irq_map irq %d hwirq %d\n", irq, (int)hwirq);
+
+	irq_set_chip_data(irq, domain->host_data);
+	irq_set_chip(irq, &ext_cpld_irq_chip);
+	irq_set_nested_thread(irq, true);
+
+	irq_set_noprobe(irq);
+
+	return 0;
+}
+
+static const struct irq_domain_ops ext_cpld_gpio_irq_domain_ops = {
+	.map = ext_cpld_gpio_irq_map,
+	.xlate = irq_domain_xlate_twocell,
+};
+
+static void __ext_cpld_gpio_irq_work(struct ext_cpld_gpio *chip,
+				     u16 *datap, u16 *cachep,
+				     unsigned long enabled, int base)
+{
+	u16 data, cache;
+	unsigned int pos;
+
+	cache = *cachep;
+	data = ioread16(datap);
+
+	for_each_set_bit(pos, &enabled, 16) {
+		u16 mask = 1 << pos;
+		u16 bit;
+		int type;
+
+		bit = data & mask;
+		if (bit == (cache & mask))
+			continue;
+
+		type = chip->irq_type[base + pos];
+		/*
+		 * check irq->type for match. Only handle edge triggered
+		 * interrupts; anything else doesn't make sense here.
+		 * TBD: While this is correct for insertion status interrupts,
+		 * we may need to support level triggered interrupts to handle
+		 * the irq status register.
+		 */
+		if (((type & IRQ_TYPE_EDGE_RISING) && bit) ||
+		    ((type & IRQ_TYPE_EDGE_FALLING) && !bit)) {
+			int virq = irq_find_mapping(chip->domain, base + pos);
+
+			handle_nested_irq(virq);
+		}
+	}
+	*cachep = data;
+}
+
+static void ext_cpld_gpio_irq_work(struct ext_cpld_gpio *chip)
+{
+	struct pmb_boot_cpld_ext *cpld = chip->base;
+
+	mutex_lock(&chip->work_lock);
+
+	__ext_cpld_gpio_irq_work(chip, &cpld->sib_presence,
+				 &chip->sib_presence_cache,
+				 chip->sib_presence_irq_enabled,
+				 0);
+
+	__ext_cpld_gpio_irq_work(chip, &cpld->sib_irq_status,
+				 &chip->sib_irq_status_cache,
+				 chip->sib_irq_enabled,
+				 16);
+
+	mutex_unlock(&chip->work_lock);
+}
+
+static irqreturn_t ext_cpld_gpio_irq_handler(int irq, void *data)
+{
+	struct ext_cpld_gpio *chip = data;
+	struct pmb_boot_cpld_ext *cpld = chip->base;
+
+	pr_info("ext_cpld got interrupt %d 0x%x:0x%x\n", irq,
+		ioread16(&cpld->sib_presence),
+		ioread16(&cpld->sib_irq_status));
+
+	ext_cpld_gpio_irq_work(chip);
+
+	return IRQ_HANDLED;
+}
+
+static void ext_cpld_gpio_worker(struct work_struct *work)
+{
+	struct ext_cpld_gpio *chip = container_of(work, struct ext_cpld_gpio,
+						  work.work);
+
+	ext_cpld_gpio_irq_work(chip);
+	schedule_delayed_work(&chip->work, 1);
+}
+
+static int ext_cpld_gpio_irq_setup(struct device *dev,
+				   struct ext_cpld_gpio *chip)
+{
+	int ret;
+
+	chip->domain = irq_domain_add_linear(dev->of_node, EXT_CPLD_NGPIO,
+					     &ext_cpld_gpio_irq_domain_ops,
+					     chip);
+	if (!chip->domain)
+		return -ENOMEM;
+
+	INIT_DELAYED_WORK(&chip->work, ext_cpld_gpio_worker);
+
+	if (chip->irq) {
+		dev_info(dev, "Setting up interrupt %d\n", chip->irq);
+		ret = devm_request_threaded_irq(dev, chip->irq, NULL,
+						ext_cpld_gpio_irq_handler,
+						IRQF_ONESHOT,
+						dev_name(dev), chip);
+		if (ret)
+			goto out_remove_domain;
+	} else {
+		schedule_delayed_work(&chip->work, 1);
+	}
+
+	chip->gpio.to_irq = ext_cpld_gpio_to_irq;
+
+	return 0;
+
+out_remove_domain:
+	irq_domain_remove(chip->domain);
+	return ret;
+}
+
+static void ext_cpld_gpio_irq_teardown(struct device *dev,
+				       struct ext_cpld_gpio *chip)
+{
+	struct pmb_boot_cpld_ext *cpld = chip->base;
+	int i;
+
+	if (chip->irq) {
+		iowrite16(0, &cpld->sib_presence_irq_en);
+		iowrite16(0, &cpld->sib_irq_en);
+	}
+
+	for (i = 0; i < EXT_CPLD_NGPIO; i++) {
+		int irq = irq_find_mapping(chip->domain, i);
+
+		if (irq > 0)
+			irq_dispose_mapping(irq);
+	}
+	irq_domain_remove(chip->domain);
+}
+
+static int ext_cpld_gpio_of_xlate(struct gpio_chip *gpio,
+				  const struct of_phandle_args *gpiospec,
+				  u32 *flags)
+{
+	if (WARN_ON(gpio->of_gpio_n_cells < 2))
+		return -EINVAL;
+
+	if (WARN_ON(gpiospec->args_count < gpio->of_gpio_n_cells))
+		return -EINVAL;
+
+	if (gpiospec->args[0] > gpio->ngpio)
+		return -EINVAL;
+
+	if (flags)
+		*flags = gpiospec->args[1] >> 16;
+
+	return gpiospec->args[0];
+}
+
+static void ext_cpld_gpio_setup(struct ext_cpld_gpio *chip)
+{
+	struct gpio_chip *gpio = &chip->gpio;
+
+	gpio->label = dev_name(chip->dev);
+	gpio->owner = THIS_MODULE;
+	gpio->get = ext_cpld_gpio_get;
+	gpio->direction_input = ext_cpld_gpio_direction_input;
+	gpio->dbg_show = NULL;
+	gpio->base = -1;
+	gpio->ngpio = EXT_CPLD_NGPIO;
+	gpio->can_sleep = 0;
+	gpio->of_node = chip->dev->of_node;
+	gpio->of_xlate = ext_cpld_gpio_of_xlate;
+	gpio->of_gpio_n_cells = 2;
+}
+
+static int ext_cpld_gpio_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct pmb_boot_cpld_ext *cpld;
+	struct ext_cpld_gpio *chip;
+	struct resource *res;
+	int ret;
+
+	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	chip->dev = dev;
+	platform_set_drvdata(pdev, chip);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	chip->base = devm_ioremap(dev, res->start, resource_size(res));
+	if (!chip->base)
+		return -ENOMEM;
+
+	cpld = chip->base;
+	chip->sib_presence_cache = ioread16(&cpld->sib_presence);
+
+	mutex_init(&chip->irq_lock);
+	mutex_init(&chip->work_lock);
+	ext_cpld_gpio_setup(chip);
+
+	ret = ext_cpld_gpio_irq_setup(dev, chip);
+	if (ret < 0)
+		return ret;
+
+	ret = gpiochip_add(&chip->gpio);
+	if (ret) {
+		dev_err(dev, "Extended CPLD gpio: Failed to register GPIO\n");
+		goto teardown;
+	}
+	return 0;
+
+teardown:
+	if (chip->domain)
+		ext_cpld_gpio_irq_teardown(dev, chip);
+	return ret;
+}
+
+static int ext_cpld_gpio_remove(struct platform_device *pdev)
+{
+	struct ext_cpld_gpio *chip = platform_get_drvdata(pdev);
+
+	cancel_delayed_work_sync(&chip->work);
+	if (chip->domain)
+		ext_cpld_gpio_irq_teardown(&pdev->dev, chip);
+
+	gpiochip_remove(&chip->gpio);
+
+	return 0;
+}
+
+static const struct of_device_id ext_cpld_gpio_ids[] = {
+	{ .compatible = "jnx,gpio-ptxpmb-ext-cpld", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, ext_cpld_gpio_ids);
+
+static struct platform_driver ext_cpld_gpio_driver = {
+	.driver = {
+		.name = "gpio-ptxpmb-ext-cpld",
+		.owner  = THIS_MODULE,
+		.of_match_table = ext_cpld_gpio_ids,
+	},
+	.probe = ext_cpld_gpio_probe,
+	.remove = ext_cpld_gpio_remove,
+};
+
+static int __init ext_cpld_gpio_init(void)
+{
+	return platform_driver_register(&ext_cpld_gpio_driver);
+}
+module_init(ext_cpld_gpio_init);
+
+static void __exit ext_cpld_gpio_exit(void)
+{
+	platform_driver_unregister(&ext_cpld_gpio_driver);
+}
+module_exit(ext_cpld_gpio_exit);
+
+MODULE_DESCRIPTION("Extended CPLD FPGA GPIO Driver");
+MODULE_LICENSE("GPL");
-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:21:57 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:21:57 +0300
Subject: [PATCH 0/7] Introduce PTX1K Boot FPGA driver
Message-ID: <1475853724-22557-1-git-send-email-pantelis.antoniou@konsulko.com>

Add Juniper's PTX1K Boot FPGA driver. Those FPGAs
are present in Juniper's PTX series of routers.

The MFD driver provices watchdog/mtd/hwmon devices.

There are full device tree binding documents for the
master mfd driver and for the slave driver.

This patchset is against mainline as of today: v4.8-9431-g3477d16
and is dependent on the "Juniper prerequisites" and
"Juniper infrastructure" patchsets sent earlier.

Georgi Vlaev (7):
  mfd: Add PTX1K I2CS BootFPGA MFD driver
  mfd: dt-bindings: Add bindings for the Juniper PTX1K Boot FPGA
  watchdog: Add PTX1K I2CS BootFPGA watchdog driver.
  watchdog: ptx1kbf-wdt: Add ptx1kbf device tree bindings
  mtd: ptx1kbf: Add PTX1K BootFPGA MTD driver
  mtd: ptx1kbf: Bindings for Juniper's PTX1K Boot FPGA
  hwmon: ptx1kbf: Add PTX1K I2CS BootFPGA sensor driver

 .../devicetree/bindings/mfd/jnx-ptx1k-bootfpga.txt |  34 ++
 .../devicetree/bindings/mtd/ptx1kbf-mtd.txt        |  23 +
 .../bindings/watchdog/jnx-ptx1kbf-wdt.txt          |  17 +
 drivers/hwmon/Kconfig                              |  17 +
 drivers/hwmon/Makefile                             |   1 +
 drivers/hwmon/jnx_ptx1kbf_hwmon.c                  | 123 ++++
 drivers/mfd/Kconfig                                |  11 +
 drivers/mfd/Makefile                               |   1 +
 drivers/mfd/ptx1k-bootfpga.c                       | 462 ++++++++++++++
 drivers/mtd/devices/Kconfig                        |  10 +
 drivers/mtd/devices/Makefile                       |   1 +
 drivers/mtd/devices/jnx_ptx1kbf_mtd.c              | 677 +++++++++++++++++++++
 drivers/watchdog/Kconfig                           |  15 +
 drivers/watchdog/Makefile                          |   1 +
 drivers/watchdog/jnx_ptx1kbf_wdt.c                 | 229 +++++++
 include/linux/mfd/ptx1k-bootfpga.h                 |  93 +++
 16 files changed, 1715 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/jnx-ptx1k-bootfpga.txt
 create mode 100644 Documentation/devicetree/bindings/mtd/ptx1kbf-mtd.txt
 create mode 100644 Documentation/devicetree/bindings/watchdog/jnx-ptx1kbf-wdt.txt
 create mode 100644 drivers/hwmon/jnx_ptx1kbf_hwmon.c
 create mode 100644 drivers/mfd/ptx1k-bootfpga.c
 create mode 100644 drivers/mtd/devices/jnx_ptx1kbf_mtd.c
 create mode 100644 drivers/watchdog/jnx_ptx1kbf_wdt.c
 create mode 100644 include/linux/mfd/ptx1k-bootfpga.h

-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:22:03 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:22:03 +0300
Subject: [PATCH 6/7] mtd: ptx1kbf: Bindings for Juniper's PTX1K Boot FPGA
In-Reply-To: <1475853724-22557-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853724-22557-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853724-22557-7-git-send-email-pantelis.antoniou@konsulko.com>

From: Georgi Vlaev <gvlaev at juniper.net>

Add binding document for Junipers Flash IP block present
in the PTX1K Boot FPGA on PTX series of routers.

Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 .../devicetree/bindings/mtd/ptx1kbf-mtd.txt        | 23 ++++++++++++++++++++++
 1 file changed, 23 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/ptx1kbf-mtd.txt

diff --git a/Documentation/devicetree/bindings/mtd/ptx1kbf-mtd.txt b/Documentation/devicetree/bindings/mtd/ptx1kbf-mtd.txt
new file mode 100644
index 0000000..4e25060
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/ptx1kbf-mtd.txt
@@ -0,0 +1,23 @@
+Flash device on a PTX1K Boot FPGA
+
+These flash chips are found in the PTX series of Juniper routers.
+
+Required properties:
+- compatible : must be "jnx,flash-sam"
+
+Optional properties:
+- reg : memory address for the flash chip, note that this is not
+required since usually the device is a subdevice of the SAM MFD
+driver which fills in the register fields.
+
+For the rest of the properties, see mtd-physmap.txt.
+
+The device tree may optionally contain sub-nodes describing partitions of the
+address space. See partition.txt for more detail.
+
+Example:
+
+ptx1kbf_mtd {
+	compatible = "jnx,ptx1kbf-mtd";
+	/* usually the whole flash is used */
+};
-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:22:04 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:22:04 +0300
Subject: [PATCH 7/7] hwmon: ptx1kbf: Add PTX1K I2CS BootFPGA sensor driver
In-Reply-To: <1475853724-22557-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853724-22557-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853724-22557-8-git-send-email-pantelis.antoniou@konsulko.com>

From: Georgi Vlaev <gvlaev at juniper.net>

The drivers allows reading CPU, PCH and DIMM modules teperatures
from the I2CS FPGA via the SMLink1 to the PCH.

Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
Signed-off-by: Guenter Roeck <groeck at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 drivers/hwmon/Kconfig             |  17 ++++++
 drivers/hwmon/Makefile            |   1 +
 drivers/hwmon/jnx_ptx1kbf_hwmon.c | 123 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 141 insertions(+)
 create mode 100644 drivers/hwmon/jnx_ptx1kbf_hwmon.c

diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index b9348d2..5b66c7b 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -674,6 +674,23 @@ config SENSORS_JNX_FAN
 	  This driver can also be built as a module.  If so, the module
 	  will be called jnx-fan.
 
+config SENSORS_JNX_PTX1KBF
+	tristate "Juniper Networks PTX1000 I2CS BootFPGA thermal sensors"
+	depends on MFD_JUNIPER_PTX1KBF
+	help
+	  If you say yes here you get support for the hardware
+	  monitoring features of the Juniper Networks PTX1000 I2CS BootFPGA
+	  on the LPC bus. The CPU's digital thermal sensor can be read over
+	  the PECI interface. PECI is connected to the PCH and the PCH's
+	  Management Engine (ME) can be configured to poll CPU and DIMM
+	  temperatures over the PECI interface. Then, it is possible for an
+	  external I2C master (in the I2CS FPGA) to read CPU, DIMM and PCH
+	  temperatures from the PCH over SMLink1 (which is connected to the board
+	  I2C tree).
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called jnx_ptx1kbf_hwmon.
+
 config SENSORS_POWR1220
 	tristate "Lattice POWR1220 Power Monitoring"
 	depends on I2C
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index eea631e..a3dedef 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_SENSORS_INA3221)	+= ina3221.o
 obj-$(CONFIG_SENSORS_IT87)	+= it87.o
 obj-$(CONFIG_SENSORS_JC42)	+= jc42.o
 obj-$(CONFIG_SENSORS_JNX_FAN)   += jnx-fan.o
+obj-$(CONFIG_SENSORS_JNX_PTX1KBF)	+= jnx_ptx1kbf_hwmon.o
 obj-$(CONFIG_SENSORS_JZ4740)	+= jz4740-hwmon.o
 obj-$(CONFIG_SENSORS_K8TEMP)	+= k8temp.o
 obj-$(CONFIG_SENSORS_K10TEMP)	+= k10temp.o
diff --git a/drivers/hwmon/jnx_ptx1kbf_hwmon.c b/drivers/hwmon/jnx_ptx1kbf_hwmon.c
new file mode 100644
index 0000000..a9d6562
--- /dev/null
+++ b/drivers/hwmon/jnx_ptx1kbf_hwmon.c
@@ -0,0 +1,123 @@
+/*
+ * Juniper Networks PTX1K RCB I2CS Boot FPGA hwmon driver
+ *
+ * Copyright (C) 2014 Juniper Networks. All rights reserved.
+ * Author: Georgi Vlaev <gvlaev at juniper.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/mfd/ptx1k-bootfpga.h>
+
+#define DRVNAME "jnx-ptx1kbf-hwmon"
+
+struct bf_hwmon {
+	void __iomem *base;
+};
+
+static const char *const bf_temp_label[] = {
+	"CPU", "PCH", "DIMM1", "DIMM2"
+};
+
+static ssize_t bf_show_temp(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	struct bf_hwmon *hwmon = dev_get_drvdata(dev);
+	int channel = to_sensor_dev_attr(attr)->index;
+
+	return sprintf(buf, "%d\n", be16_to_cpu(ioread16(hwmon->base +
+				BOOT_FPGA_CPU_TEMP_MSB + (channel * 2))));
+}
+
+static ssize_t bf_show_label(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	int channel = to_sensor_dev_attr(attr)->index;
+
+	return sprintf(buf, "%s\n", bf_temp_label[channel]);
+}
+
+/* CPU Temp */
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, bf_show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, bf_show_label, NULL, 0);
+/* PCH Temp */
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, bf_show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, bf_show_label, NULL, 1);
+/* DIMM1 Temp */
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, bf_show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, bf_show_label, NULL, 2);
+/* DIMM2 Temp */
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, bf_show_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, bf_show_label, NULL, 3);
+
+static struct attribute *bf_attrs[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_label.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_label.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_label.dev_attr.attr,
+	&sensor_dev_attr_temp4_input.dev_attr.attr,
+	&sensor_dev_attr_temp4_label.dev_attr.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(bf);
+
+static int bf_hwmon_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device *hwmon_dev;
+	struct bf_hwmon *hwmon;
+	struct resource *mem;
+
+	hwmon = devm_kzalloc(dev, sizeof(*hwmon), GFP_KERNEL);
+	if (!hwmon)
+		return -ENOMEM;
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem) {
+		dev_err(&pdev->dev, "Failed to get platform mmio resource\n");
+		return -ENOENT;
+	}
+
+	hwmon->base = devm_ioremap_nocache(dev, mem->start, resource_size(mem));
+	if (IS_ERR(hwmon->base)) {
+		dev_err(dev, "Failed to ioremap mmio memory\n");
+		return PTR_ERR(hwmon->base);
+	}
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev, "jnx_ptx1kbf",
+							   hwmon, bf_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static struct platform_driver bf_hwmon_driver = {
+	.probe  = bf_hwmon_probe,
+	.driver = {
+		.name = DRVNAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+module_platform_driver(bf_hwmon_driver);
+
+MODULE_DESCRIPTION("Juniper Networks PTX1K RCB I2CS Boot FPGA hwmon driver");
+MODULE_AUTHOR("Georgi Vlaev <gvlaev at juniper.net>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRVNAME);
-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:22:01 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:22:01 +0300
Subject: [PATCH 4/7] watchdog: ptx1kbf-wdt: Add ptx1kbf device tree bindings
In-Reply-To: <1475853724-22557-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853724-22557-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853724-22557-5-git-send-email-pantelis.antoniou@konsulko.com>

From: Georgi Vlaev <gvlaev at juniper.net>

Add binding document for the watchdog driver of PTX1K Boot FPGA.

Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 .../devicetree/bindings/watchdog/jnx-ptx1kbf-wdt.txt    | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/watchdog/jnx-ptx1kbf-wdt.txt

diff --git a/Documentation/devicetree/bindings/watchdog/jnx-ptx1kbf-wdt.txt b/Documentation/devicetree/bindings/watchdog/jnx-ptx1kbf-wdt.txt
new file mode 100644
index 0000000..0aa8086
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/jnx-ptx1kbf-wdt.txt
@@ -0,0 +1,17 @@
+Juniper's PTX1K Boot FPGA watchdog driver
+
+Required properties:
+
+- compatible:	Should be "jnx,ptx1kbf-wdt"
+
+Optional properties:
+
+- reg : Specifies base physical address and size of the registers. It is
+  optional since the MFD parent driver supplies it, but can be overridden.
+
+Example:
+
+wdt {
+	compatible = "jnx,ptx1kbf-wdt";
+	/* no properties defined */
+};
-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:21:59 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:21:59 +0300
Subject: [PATCH 2/7] mfd: dt-bindings: Add bindings for the Juniper PTX1K Boot
 FPGA
In-Reply-To: <1475853724-22557-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853724-22557-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853724-22557-3-git-send-email-pantelis.antoniou@konsulko.com>

From: Georgi Vlaev <gvlaev at juniper.net>

Add device tree bindings for the Juniper PTX1K Boot FPGA MFD driver.

Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 .../devicetree/bindings/mfd/jnx-ptx1k-bootfpga.txt | 34 ++++++++++++++++++++++
 1 file changed, 34 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/jnx-ptx1k-bootfpga.txt

diff --git a/Documentation/devicetree/bindings/mfd/jnx-ptx1k-bootfpga.txt b/Documentation/devicetree/bindings/mfd/jnx-ptx1k-bootfpga.txt
new file mode 100644
index 0000000..596dec7
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/jnx-ptx1k-bootfpga.txt
@@ -0,0 +1,34 @@
+* Device tree bindings for Juniper's PTX1K boot FPGA MFD driver
+
+The device supports a hardware watchdog, a flash MTD device and
+a hwmon sensor device. The bindings of those drivers are described
+in the jnx-ptx1kbf-wdt, jnx-ptx1kbf-mtd and jnx-ptx1kbf-hwmon documents.
+
+Required properties:
+
+- compatible:		"ptx1k-bootfpga"
+
+- reg:			contains offset/length value for device state control
+			registers space.
+
+Example:
+
+bootfpga at 10000 {
+	compatible = "jnx,ptx1k-bootfpga";
+	reg = <0x10000 0x100>;
+
+	wdt {
+		compatible = "jnx,ptx1kbf-wdt";
+		/* no properties required */
+	};
+
+	mtd {
+		compatible = "jnx,ptx1kbf-mtd";
+		/* use the full device */
+	};
+
+	hwmon {
+		compatible = "jnx,ptx1kbf-hwmon";
+		/* no properties required */
+	};
+};
-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:18:34 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:18:34 +0300
Subject: [PATCH 06/10] gpio: sam: Document bindings of SAM FPGA GPIO block
In-Reply-To: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853518-22264-7-git-send-email-pantelis.antoniou@konsulko.com>

From: Georgi Vlaev <gvlaev at juniper.net>

Add device tree bindings document for the GPIO driver of
Juniper's SAM FPGA.

Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 .../devicetree/bindings/gpio/jnx,gpio-sam.txt      | 110 +++++++++++++++++++++
 1 file changed, 110 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/gpio/jnx,gpio-sam.txt

diff --git a/Documentation/devicetree/bindings/gpio/jnx,gpio-sam.txt b/Documentation/devicetree/bindings/gpio/jnx,gpio-sam.txt
new file mode 100644
index 0000000..514c350
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/jnx,gpio-sam.txt
@@ -0,0 +1,110 @@
+Juniper SAM FPGA GPIO block
+
+The controller's registers are organized as sets of eight 32-bit
+registers with each set controlling a bank of up to 32 pins.  A single
+interrupt is shared for all of the banks handled by the controller.
+
+Required properties:
+
+- compatible:
+    Must be "jnx,gpio-sam"
+
+- #gpio-cells:
+    Should be <2>.  The first cell is the pin number (within the controller's
+    pin space), and the second is used for the following flags:
+	bit[0]: direction (0 = out, 1 = in)
+	bit[1]: init high
+	bit[2]: active low
+	bit[3]: open drain
+	bit[4]: open drain
+
+- gpio-controller:
+    Specifies that the node is a GPIO controller.
+
+Optional properties:
+
+- reg:
+    This driver is part of the SAM FPGA MFD driver, so the
+    address range is supplied by that driver. However you can
+    override using this property.
+
+- gpio-base:
+    Base of the GPIO pins of this instance. If not present use system allocated.
+
+- gpio-count:
+    Number of GPIO pins of this instance. If not present read the number from
+    the one configured in the FPGA data. Maximum number is 512.
+
+- #interrupt-cells:
+    Should be <2>.  The first cell is the GPIO number, the second should specify
+    flags.  The following subset of flags is supported:
+    - bits[16,4:0] trigger type and level flags
+	bit  0: rising edge interrupt
+	bit  1: falling edge interrupt
+	bit  2: active high interrupt
+	bit  3: active low interrupt
+	bit  4: enable debounce
+	bit 16: signal is active low
+    See also Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
+
+- gpio-interrupts:
+    A number of triples that define the mapping of interrupt groupsb to a range of
+    pins. The first cell defines the interrupt group, the second is the start of
+    the pin range and the third the number of pins in the range.
+
+- gpio-exports:
+    A subnode containing the list of pins that will be exported to user-space.
+    Each subnode contains:
+    Required properties:
+	- pin: The gpio to be exported and the relevant flags.
+    Optional properties:
+        - label: The label to use for export; if not supplied use the node name.
+
+Example:
+
+gpio20: gpio-sam {
+	compatible = "jnx,gpio-sam";
+	gpio-controller;
+	interrupt-controller;
+	/* 1st cell: gpio pin
+	 * 2nd cell: flags (bit mask)
+	 * bit  0: rising edge interrupt
+	 * bit  1: falling edge interrupt
+	 * bit  2: active high interrupt
+	 * bit  3: active low interrupt
+	 * bit  4: enable debounce
+	 * bit 16: signal is active low
+	 */
+	#interrupt-cells = <2>;
+	#gpio-cells = <2>;
+	gpio-count = <340>;
+	/* 1st cell: gpio interrupt status bit
+	 * 2nd cell: 1st pin
+	 * 3rd cell: # of pins
+	 */
+	gpio-interrupts =
+		<0 0 32>,	/* TL / TQ */
+		<1 32 32>,	/* PIC 1 */
+		<2 32 32>,	/* PIC 1 spare */
+		<7 148 32>,	/* PIC 0 */
+		<8 170 32>,	/* PIC 0 spare */
+		<16 318 22>;	/* FPC */
+
+	gpio-exports {
+		/*
+		 * flags:
+		 * GPIOF_DIR_IN			bit 0=1
+		 * GPIOF_DIR_OUT		bit 0=0
+		 * GPIOF_INIT_HIGH		bit 1=1
+		 *   GPIOF_INIT_HIGH is raw, not translated
+		 * GPIOF_ACTIVE_LOW		bit 2=1
+		 * GPIOF_OPEN_DRAIN		bit 3=1
+		 * GPIOF_OPEN_SOURCE		bit 4=1
+		 * GPIOF_EXPORT			bit 5=1
+		 * GPIOF_EXPORT_CHANGEABLE      bit 6=1
+		 */
+		tl0-rst {
+			pin = < 8 0x24 >;
+		};
+	};
+};
-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:17:31 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:17:31 +0300
Subject: [PATCH 10/10] mtd: ngpmb_nvram: Add bindings for Juniper's ngpmb NVRAM
In-Reply-To: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853451-22121-11-git-send-email-pantelis.antoniou@konsulko.com>

From: Georgi Vlaev <gvlaev at juniper.net>

Add device tree binging document for the ngpmb NVRAM device.

Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 .../devicetree/bindings/mtd/ngpmb-nvram.txt        | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/ngpmb-nvram.txt

diff --git a/Documentation/devicetree/bindings/mtd/ngpmb-nvram.txt b/Documentation/devicetree/bindings/mtd/ngpmb-nvram.txt
new file mode 100644
index 0000000..297ad0e
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/ngpmb-nvram.txt
@@ -0,0 +1,22 @@
+Non Volatile RAM device on a Juniper NG PMB FPGA
+
+These devices are found in the PTX series of Juniper routers.
+
+Required properties:
+- compatible : must be "jnx,ngpmb-nvram"
+
+Optional properties:
+- reg : memory address for the RAM, note that this is not
+required since usually the device is a subdevice of the SAM MFD
+driver which fills in the register fields.
+
+For the rest of the properties, see mtd-physmap.txt.
+
+The device tree may optionally contain sub-nodes describing partitions of the
+address space. See partition.txt for more detail.
+
+Example:
+
+ngpmb_nvram {
+	compatible = "jnx,ngpmb-nvram";
+};
-- 
1.9.1



From krzk at kernel.org  Fri Oct  7 08:48:40 2016
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 7 Oct 2016 18:48:40 +0300
Subject: [PATCH 1/3] mtd: s3c2410: make ecc mode configurable via
 platform data
In-Reply-To: <1475711217-974-2-git-send-email-sergio.prado@e-labworks.com>
References: <1475711217-974-1-git-send-email-sergio.prado@e-labworks.com>
 <1475711217-974-2-git-send-email-sergio.prado@e-labworks.com>
Message-ID: <20161007154840.GA4222@kozik-lap>

On Wed, Oct 05, 2016 at 08:46:55PM -0300, Sergio Prado wrote:
> Removing CONFIG_MTD_NAND_S3C2410_HWECC option and adding a ecc_mode
> field in the drivers's platform data structure so it can be selectable
> via platform data.
> 
> Also setting this field to NAND_ECC_SOFT in all boards using this
> driver since none of them had CONFIG_MTD_NAND_S3C2410_HWECC enabled.
> 
> Signed-off-by: Sergio Prado <sergio.prado at e-labworks.com>
> ---
>  arch/arm/mach-s3c24xx/common-smdk.c            |   1 +
>  arch/arm/mach-s3c24xx/mach-anubis.c            |   1 +
>  arch/arm/mach-s3c24xx/mach-at2440evb.c         |   1 +
>  arch/arm/mach-s3c24xx/mach-bast.c              |   1 +
>  arch/arm/mach-s3c24xx/mach-gta02.c             |   1 +
>  arch/arm/mach-s3c24xx/mach-jive.c              |   1 +
>  arch/arm/mach-s3c24xx/mach-mini2440.c          |   1 +
>  arch/arm/mach-s3c24xx/mach-osiris.c            |   1 +
>  arch/arm/mach-s3c24xx/mach-qt2410.c            |   1 +
>  arch/arm/mach-s3c24xx/mach-rx1950.c            |   1 +
>  arch/arm/mach-s3c24xx/mach-rx3715.c            |   1 +
>  arch/arm/mach-s3c24xx/mach-vstms.c             |   1 +
>  arch/arm/mach-s3c64xx/mach-hmt.c               |   1 +
>  arch/arm/mach-s3c64xx/mach-mini6410.c          |   1 +
>  arch/arm/mach-s3c64xx/mach-real6410.c          |   1 +
>  drivers/mtd/nand/Kconfig                       |   9 --
>  drivers/mtd/nand/s3c2410.c                     | 119 +++++++++++++------------
>  include/linux/platform_data/mtd-nand-s3c2410.h |   6 +-
>  18 files changed, 79 insertions(+), 70 deletions(-)
>


Acked-by: Krzysztof Kozlowski <krzk at kernel.org>

Best regards,
Krzysztof



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:22:02 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:22:02 +0300
Subject: [PATCH 5/7] mtd: ptx1kbf: Add PTX1K BootFPGA MTD driver
In-Reply-To: <1475853724-22557-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853724-22557-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853724-22557-6-git-send-email-pantelis.antoniou@konsulko.com>

From: Georgi Vlaev <gvlaev at juniper.net>

This patch adds a MTD driver for configuration updates of the
Xilinx Spartan 3AN based FPGAs on the PTX1K RE boards. The
driver is client of the ptx1k-bootfpga driver.

Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 drivers/mtd/devices/Kconfig           |  10 +
 drivers/mtd/devices/Makefile          |   1 +
 drivers/mtd/devices/jnx_ptx1kbf_mtd.c | 677 ++++++++++++++++++++++++++++++++++
 3 files changed, 688 insertions(+)
 create mode 100644 drivers/mtd/devices/jnx_ptx1kbf_mtd.c

diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index f5a9032..25a1c4a 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -155,6 +155,16 @@ config MTD_SAM_FLASH
 	  This driver can also be built as a module. When it is so the name of
 	  the module is flash-sam.
 
+config MTD_JNX_PTX1KBF
+	tristate "Juniper I2CS BootFPGA MTD driver"
+	depends on MFD_JUNIPER_PTX1KBF
+	help
+	  This enables the MTD driver for the Juniper I2CS BootFPGA.
+	  The driver is used to perform software upgrades of the RE's
+	  Spartan 3AN XC3S50AN, XC3S200AN, XCS400AN, XC3S700AN and
+	  XC3S1400AN based I2CS. The I2CS BootFPGA must implement the
+	  remote upgrade software interface.
+
 config JNX_PMB_NVRAM
 	tristate "Juniper FPC PMB NVRAM Driver"
 	depends on (PTXPMB_COMMON || JNX_PTX_NGPMB)
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
index 7556311..e1adfa5 100644
--- a/drivers/mtd/devices/Makefile
+++ b/drivers/mtd/devices/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_MTD_ST_SPI_FSM)    += st_spi_fsm.o
 obj-$(CONFIG_MTD_POWERNV_FLASH)	+= powernv_flash.o
 
 obj-$(CONFIG_MTD_SAM_FLASH)	+= sam-flash.o
+obj-$(CONFIG_MTD_JNX_PTX1KBF)	+= jnx_ptx1kbf_mtd.o
 obj-$(CONFIG_JNX_PMB_NVRAM)     += jnx_pmb_nvram.o
 
 CFLAGS_docg3.o			+= -I$(src)
diff --git a/drivers/mtd/devices/jnx_ptx1kbf_mtd.c b/drivers/mtd/devices/jnx_ptx1kbf_mtd.c
new file mode 100644
index 0000000..3bc17be
--- /dev/null
+++ b/drivers/mtd/devices/jnx_ptx1kbf_mtd.c
@@ -0,0 +1,677 @@
+/*
+ * Juniper Networks PTX1K RCB I2CS Boot FPGA MTD driver
+ * FPGA upgrades of the Spartan3AN/XC3S700 based I2CS.
+ *
+ * Copyright (C) 2015 Juniper Networks. All rights reserved.
+ * Author: Georgi Vlaev <gvlaev at juniper.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/delay.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mfd/ptx1k-bootfpga.h>
+
+#define DEFAULT_BUSY_TIMEOUT	5	/* default timeout (msec) */
+#define PAGE_BUFFER_TXFER	400	/* page->sram transfer (usec) */
+
+/* FLASH_IF_CONTROL commands */
+#define CONTROL_READ_SID	0x80
+#define CONTROL_READ_DID	0x04
+#define CONTROL_READ_STATUS	0x08
+#define CONTROL_SECTOR_ERASE	0x20
+#define CONTROL_PAGE_ERASE	0x40
+#define CONTROL_PAGE_WRITE	0x02
+#define CONTROL_PAGE_READ	0x01
+#define CONTROL_SP_READ		0x02
+#define CONTROL_SP_WRITE	0x08
+#define CONTROL_SP_UALL		0x01
+
+/* FLASH_IF_STATUS bits */
+#define STATUS_BUSY		BIT(0)
+#define STATUS_ILLEGAL_WRITE	BIT(1)
+#define STATUS_ILLEGAL_ERASE	BIT(2)
+#define STATUS_ILLEGAL (STATUS_ILLEGAL_WRITE | STATUS_ILLEGAL_ERASE)
+#define STATUS_POWER_2_ADDR	BIT(3)
+#define STATUS_SID_I2CS		0x1F /* I2CS Spartan3AN FPGA */
+
+/* RU_CONFIG_CONTROL_STATUS bits */
+#define RU_CCS_USER_IMAGE	BIT(7)
+#define RU_CCS_RECONFIG		BIT(5)
+
+#define MASK_SPARE_PAGE		0x1f
+#define MASK_SPARE_SECTOR	0x1fff
+
+#define SECTOR_UNPROTECT	0x00
+#define SECTOR_PROTECT		0xff
+
+struct bfmtd_info {
+	const char *name;
+	u8 device_id;		/* flash id as reported by the fpga */
+	size_t flash_size;	/* total flash size */
+	size_t page_size;	/* read/write page size */
+	size_t sector_size;	/* erase sector size */
+	size_t nr_pages;	/* total number of pages */
+	size_t nr_sectors;	/* total number of sectors */
+	size_t writesize;	/* write size */
+	size_t writebufsize;	/* internal fpga sram buffer size (bytes) */
+	size_t spare_size;	/* additional bytes per page in 'default' mode*/
+	/*
+	 * Timeouts are defined in the Xilinx "In-System Flash (ISF) Upgrade
+	 * User Guide". Our values will add 20% on top of ISF ones
+	 */
+	u16 page_erase_tmo;	/* page erase timeout (msec) */
+	u16 sector_erase_tmo;	/* sector erase timeout (msec) */
+	u16 buffer_program_tmo;	/* sram buffer program timeout (msec) */
+};
+
+/*
+ * Definitions in power-of-2 addressing mode.
+ * Reconfigure sizes if default mode is detected.
+ */
+static struct bfmtd_info bfmtd_info_db[] = {
+	{
+		.name = "XC3S50AN",
+		.device_id = 0x22,
+		.flash_size = 256 * 512,
+		.page_size = 256,
+		.nr_pages = 512,
+		.nr_sectors = 4,
+		.sector_size = 256 * 128,
+		.writesize = 1,
+		.writebufsize = 256,
+		.spare_size = 8,
+		.page_erase_tmo = 38,
+		.sector_erase_tmo = 3000,
+		.buffer_program_tmo = 5,
+	},
+	{
+		.name = "XC3S200AN/XC3S400AN",
+		.device_id = 0x24,
+		.flash_size = 256 * 2048,
+		.page_size = 256,
+		.nr_pages = 2048,
+		.nr_sectors = 8,
+		.sector_size = 256 * 256,
+		.writesize = 1,
+		.writebufsize = 256,
+		.spare_size = 8,
+		.page_erase_tmo = 38,
+		.sector_erase_tmo = 6000,
+		.buffer_program_tmo = 5,
+	},
+	{
+		.name = "XC3S700AN",
+		.device_id = 0x25,
+		.flash_size = 256 * 4096,
+		.page_size = 256,
+		.nr_pages = 4096,
+		.nr_sectors = 16,
+		.sector_size = 256 * 256,
+		.writesize = 1,
+		.writebufsize = 256,
+		.spare_size = 8,
+		.page_erase_tmo = 42,
+		.sector_erase_tmo = 6000,
+		.buffer_program_tmo = 8,
+	},
+	{
+		.name = "XC3S1400AN",
+		.device_id = 0x26,
+		.flash_size = 512 * 4096,
+		.page_size = 512,
+		.nr_pages = 4096,
+		.nr_sectors = 16,
+		.sector_size = 512 * 256,
+		.writesize = 1,
+		.writebufsize = 512,
+		.spare_size = 8,
+		.page_erase_tmo = 42,
+		.sector_erase_tmo = 6000,
+		.buffer_program_tmo = 8,
+	},
+};
+
+struct bf_mtd {
+	void __iomem *base;
+	struct device *dev;
+	struct mtd_info mtd;
+	struct bfmtd_info *info;
+	struct mutex lock;
+};
+
+/*
+ * bfmtd_busy_wait()
+ *	Wait for busy[0] flag in the FLASH_IF_STATUS register
+ */
+static int bfmtd_busy_wait(struct bf_mtd *bfmtd, unsigned long max_wait)
+{
+	u8 status;
+	unsigned long timeout = jiffies + msecs_to_jiffies(max_wait);
+
+	udelay(50);
+	do {
+		status = ioread8(bfmtd->base + BOOT_FPGA_FLASH_IF_STATUS(3));
+		if (!(status & STATUS_BUSY))
+			return 0;
+
+		if (status & STATUS_ILLEGAL)
+			return -EACCES;
+
+		usleep_range(50, 100);
+	} while (time_before(jiffies, timeout));
+
+	return -ETIMEDOUT;
+}
+
+/*
+ * bfmtd_read_status()
+ *	Read FLASH_IF_STATUS regsters
+ */
+static int bfmtd_read_status(struct bf_mtd *bfmtd, u8 control_cmd,
+				u8 status_index)
+{
+	int ret;
+
+	iowrite8(control_cmd,
+		 bfmtd->base + BOOT_FPGA_FLASH_IF_CONTROL(3));
+
+	ret = bfmtd_busy_wait(bfmtd, DEFAULT_BUSY_TIMEOUT);
+	if (ret)
+		return ret;
+
+	return ioread8(bfmtd->base +
+			BOOT_FPGA_FLASH_IF_STATUS(status_index));
+}
+
+/* Device ID */
+static inline int bfmtd_read_did(struct bf_mtd *bfmtd)
+{
+	return bfmtd_read_status(bfmtd, CONTROL_READ_DID, 1);
+}
+
+/* Silicon ID */
+static inline int bfmtd_read_sid(struct bf_mtd *bfmtd)
+{
+	return bfmtd_read_status(bfmtd, CONTROL_READ_SID, 2);
+}
+
+/* ^2 addressing mode */
+static inline int bfmtd_read_p2addr(struct bf_mtd *bfmtd)
+{
+	return bfmtd_read_status(bfmtd, CONTROL_READ_STATUS, 3);
+}
+
+/*
+ * bfmtd_calc_flash_addr()
+ *
+ * We have to support 2 different addressing schemes.
+ * The page_size can be 256, 264, 512, 528.
+ * The page_size in the default addressing mode are 264 and 528.
+ * The same is valid for the sector addresses.
+ * Calculate the page/sector address from the page_size/sectro_size.
+ *
+ * Example (XC3S700AN):
+ * Page#	Default addressing	Power of 2 addressing
+ * 0		0x000 - 0x107		0x000 - 0xFF
+ * 1		0x200 - 0x307		0x100 - 0x1FF
+ * 2		0x400 - 0x507		0x200 - 0x2FF
+ */
+static u32 bfmtd_calc_flash_addr(u32 addr, u32 size, u32 mask)
+{
+	/* spare = 0,8,16 for pages and 0,1024,2048,4096 for sectors */
+	u32 spare = size & mask;
+
+	if (!spare) /* power-of-2 mode */
+		return addr & ~(size - 1);
+
+	/* default mode, use spare to get the page/sector address */
+	addr /= size;
+	addr *= (spare << 6);
+
+	return addr;
+}
+
+/*
+ * bfmtd_read_page()
+ *	Transfer a page from the flash into the sram buffer
+ */
+static int bfmtd_read_page(struct bf_mtd *bfmtd, u32 addr, u8 *buf,
+				size_t len)
+{
+	int ret;
+	u32 page_addr, page_ofs;
+	u16 buff_addr;
+	size_t retlen, page_size =  bfmtd->info->page_size;
+
+	if (len > page_size)
+		len = page_size;
+
+	page_ofs = addr % page_size;
+	retlen = len - page_ofs;
+
+	if (!retlen || addr + retlen > bfmtd->info->flash_size)
+		return -EINVAL;
+
+	ret = bfmtd_busy_wait(bfmtd, DEFAULT_BUSY_TIMEOUT);
+	if (ret)
+		return ret;
+
+	/* Calculate the page address */
+	page_addr = bfmtd_calc_flash_addr(addr, page_size, MASK_SPARE_PAGE);
+
+	/* Set page address, byte count and trigger write */
+	iowrite32(be32_to_cpu(page_addr),
+		bfmtd->base + BOOT_FPGA_FLASH_IF_ADDR(0));
+	/* byte count (N), denotes (N + 1) */
+	iowrite32(be32_to_cpu(len - 1),
+		bfmtd->base + BOOT_FPGA_FLASH_IF_BYTE_COUNT(0));
+	iowrite8(CONTROL_PAGE_READ,
+		bfmtd->base + BOOT_FPGA_FLASH_IF_CONTROL(3));
+
+	/* Wait the fpga the fetch the page into the sram buffer (400 usec) */
+	ret = bfmtd_busy_wait(bfmtd, DEFAULT_BUSY_TIMEOUT);
+	if (ret)
+		return ret;
+
+	for (buff_addr = page_ofs; buff_addr < len; buff_addr++) {
+		iowrite16(be16_to_cpu(buff_addr),
+			bfmtd->base + BOOT_FPGA_FLASH_IF_READ_BUF_ADDR_MSB);
+		*buf = ioread8(bfmtd->base + BOOT_FPGA_FLASH_IF_READ_BUF_DATA);
+		buf++;
+	}
+
+	return retlen;
+}
+
+/*
+ * bfmtd_is_protected()
+ *	Check if the sector @addr is protected
+ */
+static int bfmtd_is_protected(struct bf_mtd *bfmtd, u32 addr)
+{
+	u8 protected_sectors[16];
+	int n_sector, ret = 0;
+	u16 buff_addr;
+
+	if (addr > bfmtd->info->flash_size)
+		return -EINVAL;
+
+	n_sector = addr / bfmtd->info->sector_size;
+
+	/* Read the protected sector array */
+	iowrite8(CONTROL_SP_READ,
+		bfmtd->base + BOOT_FPGA_FLASH_IF_CONTROL(2));
+
+	ret = bfmtd_busy_wait(bfmtd, DEFAULT_BUSY_TIMEOUT);
+	if (ret)
+		return ret;
+
+	for (buff_addr = 0; buff_addr < bfmtd->info->nr_sectors; buff_addr++) {
+		iowrite16(be16_to_cpu(buff_addr),
+			bfmtd->base + BOOT_FPGA_FLASH_IF_READ_BUF_ADDR_MSB);
+		protected_sectors[buff_addr] =
+			ioread8(bfmtd->base + BOOT_FPGA_FLASH_IF_READ_BUF_DATA);
+	}
+
+	if (protected_sectors[n_sector] == SECTOR_PROTECT) {
+		dev_err(bfmtd->dev, "Sector #%d is protected\n", n_sector);
+		return -EACCES;
+	}
+
+	return 0;
+}
+
+/*
+ * bfmtd_erase_region()
+ *	Erase pages or sectors.
+ *	Note: The control (0xa5a5a5a5) words are written on page boundary.
+ */
+static int bfmtd_erase_region(struct bf_mtd *bfmtd, u32 addr)
+{
+	struct mtd_info *mtd = &bfmtd->mtd;
+	u32 flash_addr, mask, timeout;
+	u8 cmd;
+	int ret;
+
+	if (addr > bfmtd->info->flash_size)
+		return -EINVAL;
+
+	ret = bfmtd_is_protected(bfmtd, addr);
+	if (ret)
+		return ret;
+
+	ret = bfmtd_busy_wait(bfmtd, DEFAULT_BUSY_TIMEOUT);
+	if (ret)
+		return ret;
+
+	/* sector/page erase mode ? */
+	if (bfmtd->info->page_size == mtd->erasesize) {
+		mask = MASK_SPARE_PAGE;
+		timeout = bfmtd->info->page_erase_tmo;
+		cmd = CONTROL_PAGE_ERASE;
+	} else {
+		mask = MASK_SPARE_SECTOR;
+		timeout = bfmtd->info->sector_erase_tmo;
+		cmd = CONTROL_SECTOR_ERASE;
+	}
+
+	/* Calculate the page/sector address */
+	flash_addr = bfmtd_calc_flash_addr(addr, mtd->erasesize, mask);
+
+	/* Set page/sector address, byte count and trigger erase */
+	iowrite32(be32_to_cpu(flash_addr),
+		bfmtd->base + BOOT_FPGA_FLASH_IF_ADDR(0));
+	iowrite8(cmd, bfmtd->base + BOOT_FPGA_FLASH_IF_CONTROL(3));
+
+	/* Wait the fpga the flush the buffer */
+	ret = bfmtd_busy_wait(bfmtd, timeout);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+/*
+ * bfmtd_write_page()
+ *	Write a page content in the sram buffer and then to flash device
+ */
+static int bfmtd_write_page(struct bf_mtd *bfmtd, u32 addr, const u8 *buf,
+				size_t len)
+{
+	int ret;
+	u32 page_addr, page_ofs;
+	u16 buff_addr;
+	size_t retlen, page_size =  bfmtd->info->page_size;
+
+	if (len > page_size)
+		len = page_size;
+
+	page_ofs = addr % page_size;
+	retlen = len - page_ofs;
+
+	if (!retlen || addr + retlen > bfmtd->info->flash_size)
+		return -EINVAL;
+
+	ret = bfmtd_busy_wait(bfmtd, DEFAULT_BUSY_TIMEOUT);
+	if (ret)
+		return ret;
+
+	/* Fill the internal fpga buffer */
+	for (buff_addr = page_ofs; buff_addr < len; buff_addr++) {
+		iowrite16(be16_to_cpu(buff_addr),
+			bfmtd->base + BOOT_FPGA_FLASH_IF_WRITE_BUF_ADDR_MSB);
+		iowrite8(*buf, bfmtd->base + BOOT_FPGA_FLASH_IF_WRITE_BUF_DATA);
+		buf++;
+	}
+
+	/* Calculate the page address */
+	page_addr = bfmtd_calc_flash_addr(addr, page_size, MASK_SPARE_PAGE);
+
+	/* Set page address, byte count and trigger write */
+	iowrite32(be32_to_cpu(page_addr),
+		bfmtd->base + BOOT_FPGA_FLASH_IF_ADDR(0));
+	iowrite32(be32_to_cpu(len - 1),
+		bfmtd->base + BOOT_FPGA_FLASH_IF_BYTE_COUNT(0));
+	iowrite8(CONTROL_PAGE_WRITE,
+		bfmtd->base + BOOT_FPGA_FLASH_IF_CONTROL(3));
+
+	/* Wait the fpga the flush the buffer */
+	ret = bfmtd_busy_wait(bfmtd, bfmtd->info->buffer_program_tmo);
+	if (ret)
+		return ret;
+
+	return retlen;
+}
+
+/*
+ * bfmtd_read()
+ *	MTD read
+ */
+static int bfmtd_read(struct mtd_info *mtd, loff_t from, size_t len,
+			size_t *retlen, u8 *buf)
+{
+	struct bf_mtd *bfmtd = container_of(mtd, struct bf_mtd, mtd);
+	int ret, read = 0;
+
+	mutex_lock(&bfmtd->lock);
+	while (len) {
+		ret = bfmtd_read_page(bfmtd, from, buf, len);
+		if (ret < 0) {
+			dev_err(bfmtd->dev, "RD @0x%llx, size %ld failed (%d)",
+					from, len, ret);
+			mutex_unlock(&bfmtd->lock);
+			return ret;
+		}
+		read += ret;
+		len -= ret;
+		from += ret;
+		buf += ret;
+	}
+	mutex_unlock(&bfmtd->lock);
+
+	*retlen = read;
+
+	return 0;
+}
+
+/*
+ * bfmtd_write()
+ *	MTD write
+ */
+static int bfmtd_write(struct mtd_info *mtd, loff_t to, size_t len,
+				size_t *retlen, const u8 *buf)
+{
+	struct bf_mtd *bfmtd = container_of(mtd, struct bf_mtd, mtd);
+	int ret, written = 0;
+
+	mutex_lock(&bfmtd->lock);
+	while (len) {
+		ret = bfmtd_write_page(bfmtd, to, buf, len);
+		if (ret < 0) {
+			dev_err(bfmtd->dev, "WR @0x%llx, size %ld failed (%d)",
+					to, len, ret);
+			mutex_unlock(&bfmtd->lock);
+			return ret;
+		}
+		written += ret;
+		len -= ret;
+		to += ret;
+		buf += ret;
+	}
+	mutex_unlock(&bfmtd->lock);
+
+	*retlen = written;
+
+	return 0;
+}
+
+/*
+ * bfmtd_erase()
+ *	MTD erase
+ */
+static int bfmtd_erase(struct mtd_info *mtd, struct erase_info *ei)
+{
+	struct bf_mtd *bfmtd = container_of(mtd, struct bf_mtd, mtd);
+	u32  start_addr, end_addr, addr;
+	int len, ret = 0;
+
+	len = ei->len;
+	start_addr =  ei->addr;
+	end_addr = start_addr + len - 1;
+
+	ei->state = MTD_ERASE_DONE;
+	addr = start_addr;
+	mutex_lock(&bfmtd->lock);
+	while (addr < end_addr) {
+		ret = bfmtd_erase_region(bfmtd, addr);
+		if (ret < 0) {
+			dev_err(bfmtd->dev, "Erase @0x%x, size %d failed (%d)",
+					addr, mtd->erasesize, ret);
+			ei->state = MTD_ERASE_FAILED;
+			break;
+		}
+		addr += mtd->erasesize;
+	}
+	mutex_unlock(&bfmtd->lock);
+
+	mtd_erase_callback(ei);
+
+	return ret;
+}
+
+static int bfmtd_init_mtd(struct bf_mtd *bfmtd)
+{
+	struct mtd_info *mtd;
+	struct bfmtd_info *info = NULL;
+	int ret, i;
+
+	ret = bfmtd_read_sid(bfmtd);
+	if (ret < 0)
+		return ret;
+
+	if (ret != STATUS_SID_I2CS) {
+		dev_err(bfmtd->dev, "Unsupported silicon id: %u", ret);
+		return -ENODEV;
+	}
+
+	ret = bfmtd_read_did(bfmtd);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < ARRAY_SIZE(bfmtd_info_db); i++) {
+		if (bfmtd_info_db[i].device_id == ret) {
+			info = &bfmtd_info_db[i];
+			break;
+		}
+	}
+
+	if (!info) {
+		dev_err(bfmtd->dev, "Unsupported device id: %u", ret);
+		return -ENODEV;
+	}
+
+	ret = bfmtd_read_p2addr(bfmtd);
+	if (ret < 0)
+		return ret;
+
+	/* Reconfigure sizes if not in "power-of-2" addressing mode */
+	if (!(ret & STATUS_POWER_2_ADDR)) {
+		info->page_size += info->spare_size;
+		info->writebufsize = info->page_size;
+		info->flash_size = info->page_size * info->nr_pages;
+		info->sector_size = info->flash_size / info->nr_sectors;
+	}
+
+	dev_info(bfmtd->dev, "%s configuration flash in \'%s\' addressing mode\n",
+			info->name,
+			(ret & STATUS_POWER_2_ADDR) ? "power-of-2" : "default");
+
+	ret = ioread8(bfmtd->base + BOOT_FPGA_RU_CONFIG_CONTROL_STATUS);
+	dev_info(bfmtd->dev, "active FPGA configuration: %s\n",
+			(ret & RU_CCS_USER_IMAGE) ? "user" : "golden");
+
+	bfmtd->info = info;
+	mtd = &bfmtd->mtd;
+	mtd->name = dev_name(bfmtd->dev);
+	mtd->type = MTD_NORFLASH;
+	mtd->flags = MTD_CAP_NORFLASH;
+	mtd->erasesize = info->page_size;
+	mtd->writesize = info->writesize;
+	mtd->writebufsize = info->writebufsize;
+	mtd->size = info->flash_size;
+	mtd->_erase = bfmtd_erase;
+	mtd->_read = bfmtd_read;
+	mtd->_write = bfmtd_write;
+
+	return 0;
+}
+
+static int bfmtd_probe(struct platform_device *pdev)
+{
+	struct mtd_part_parser_data ppdata = {};
+	struct bf_mtd *bfmtd;
+	struct resource *mem;
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	bfmtd = devm_kzalloc(dev, sizeof(*bfmtd), GFP_KERNEL);
+	if (!bfmtd)
+		return -ENOMEM;
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem) {
+		dev_err(dev, "Failed to get platform mmio resource\n");
+		return -ENOENT;
+	}
+
+	bfmtd->base = devm_ioremap_nocache(dev, mem->start, resource_size(mem));
+	if (IS_ERR(bfmtd->base)) {
+		dev_err(dev, "Failed to ioremap mmio memory\n");
+		return PTR_ERR(bfmtd->base);
+	}
+
+	bfmtd->dev = dev;
+	ret = bfmtd_init_mtd(bfmtd);
+	if (ret)
+		return ret;
+
+	ret = mtd_device_parse_register(&bfmtd->mtd, NULL, &ppdata, NULL, 0);
+	if (ret) {
+		dev_err(dev, "Failed to register MTD device (%d)\n", ret);
+		return ret;
+	}
+
+	mutex_init(&bfmtd->lock);
+
+	platform_set_drvdata(pdev, bfmtd);
+
+	return ret;
+}
+
+static int bfmtd_remove(struct platform_device *pdev)
+{
+	struct bf_mtd *bfmtd = platform_get_drvdata(pdev);
+
+	mtd_device_unregister(&bfmtd->mtd);
+
+	return 0;
+}
+
+static const struct of_device_id ptx1kbf_mtd_ids[] = {
+	{ .compatible = "jnx,ptx1kbf-mtd", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, ptx1kbf_mtd_ids);
+
+static struct platform_driver bfmtd_driver = {
+	.probe  = bfmtd_probe,
+	.remove = bfmtd_remove,
+	.driver = {
+		.name = "jnx-ptx1kbf-mtd",
+		.owner = THIS_MODULE,
+		.of_match_table = ptx1kbf_mtd_ids,
+	},
+};
+
+module_platform_driver(bfmtd_driver);
+
+MODULE_DESCRIPTION("Juniper Networks PTX1K RCB I2CS Boot FPGA MTD driver");
+MODULE_AUTHOR("Georgi Vlaev <gvlaev at juniper.net>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:jnx-ptx1kbf-mtd");
-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:22:00 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:22:00 +0300
Subject: [PATCH 3/7] watchdog: Add PTX1K I2CS BootFPGA watchdog driver.
In-Reply-To: <1475853724-22557-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853724-22557-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853724-22557-4-git-send-email-pantelis.antoniou@konsulko.com>

From: Georgi Vlaev <gvlaev at juniper.net>

This driver allows using the I2CS watchdog on PTX1K. The
BootFPGA implements a watchdog that allows setting timeout
from predefined set of values from 15 msec to 491 sec.

Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
Signed-off-by: Guenter Roeck <groeck at juniper.net>
Signed-off-by: JawaharBalaji Thirumalaisamy <jawaharb at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 drivers/watchdog/Kconfig           |  15 +++
 drivers/watchdog/Makefile          |   1 +
 drivers/watchdog/jnx_ptx1kbf_wdt.c | 229 +++++++++++++++++++++++++++++++++++++
 3 files changed, 245 insertions(+)
 create mode 100644 drivers/watchdog/jnx_ptx1kbf_wdt.c

diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 2554f47..a3761eb 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -1033,6 +1033,21 @@ config IT87_WDT
 	  To compile this driver as a module, choose M here: the module will
 	  be called it87_wdt.
 
+config JNX_PTX1KBF_WDT
+	tristate "Juniper Networks PTX1000 I2CS BootFPGA Watchdog"
+	depends on X86 && MFD_JUNIPER_PTX1KBF
+	---help---
+	  This is the driver for the watchdog timer built-in on the Juniper
+	  Networks PTX1000 I2CS/BootFPGA and acessible from the LPC bus. The
+	  BootFPGA watchdog allows several predefined thresholds, so this
+	  driver will select a value close to these static values: 15 ms,
+	  30 ms, 60 ms, 120 ms, 240 ms, 480 ms, 960 ms, 1920 ms, 3840 ms,
+	  7680 ms, 15360 ms, 30720 ms, 61440 ms, 122880 ms, 245760 ms and
+	  516096 ms.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called jnx_ptx1kbf_wdt.
+
 config HP_WATCHDOG
 	tristate "HP ProLiant iLO2+ Hardware Watchdog Timer"
 	depends on X86 && PCI
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 942b795..f9fafdf 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -111,6 +111,7 @@ endif
 obj-$(CONFIG_IT8712F_WDT) += it8712f_wdt.o
 obj-$(CONFIG_IT87_WDT) += it87_wdt.o
 obj-$(CONFIG_JNX_PTXPMB_WDT) += ptxpmb_wdt.o
+obj-$(CONFIG_JNX_PTX1KBF_WDT) += jnx_ptx1kbf_wdt.o
 obj-$(CONFIG_HP_WATCHDOG) += hpwdt.o
 obj-$(CONFIG_KEMPLD_WDT) += kempld_wdt.o
 obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
diff --git a/drivers/watchdog/jnx_ptx1kbf_wdt.c b/drivers/watchdog/jnx_ptx1kbf_wdt.c
new file mode 100644
index 0000000..7d3e0b7
--- /dev/null
+++ b/drivers/watchdog/jnx_ptx1kbf_wdt.c
@@ -0,0 +1,229 @@
+/*
+ * Juniper Networks PTX1K RCB I2CS Boot FPGA watchdog driver
+ *
+ * Copyright (C) 2014 Juniper Networks. All rights reserved.
+ * Author: Georgi Vlaev <gvlaev at juniper.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/watchdog.h>
+#include <linux/mfd/ptx1k-bootfpga.h>
+
+#define WDT_MIN_TIMEOUT		1
+#define WDT_MAX_TIMEOUT		491
+#define WDT_DEFAULT_TIMEOUT	60	/* default heartbeat in seconds */
+
+#define DRVNAME "jnx-ptx1kbf-wdt"
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+
+#define MSW_NOWAYOUT __MODULE_STRING(WATCHDOG_NOWAYOUT)
+MODULE_PARM_DESC(nowayout,
+		 "Cannot be stopped once started (def=" MSW_NOWAYOUT ")");
+
+struct ptx1kbf_wdt {
+	void __iomem *base;
+	struct watchdog_device wdt_dev;
+};
+
+/*
+ * The BOOT_FPGA_WATCHDOG_TIMER_THRESHOLD register defines the watchdog
+ * timer thresholds in ms: 0x0 = 15 ms, 0x1 = 30 ms, ...  0xD = 122880 ms,
+ * 0xE = 245760 ms, 0xF = 492520 ms, or value = (2^index * 15)
+ */
+static int ptx1kbf_index_to_timeout(u8 reg)
+{
+	return ((1 << (reg & WTT_THRESHOLD_MASK)) * 15) / 1000;
+}
+
+static u8 ptx1kbf_timeout_to_index(unsigned int timeout)
+{
+	return fls(timeout * 1000 / 15) & WTT_THRESHOLD_MASK;
+}
+
+static int ptx1kbf_wdt_set_timeout(struct watchdog_device *wdt_dev,
+				   unsigned int timeout)
+{
+	struct ptx1kbf_wdt *wdt = watchdog_get_drvdata(wdt_dev);
+	u8 reg, index;
+
+	if (timeout > WDT_MAX_TIMEOUT)
+		return -EINVAL;
+
+	index = ptx1kbf_timeout_to_index(timeout);
+
+	reg = ioread8(wdt->base + BOOT_FPGA_WATCHDOG_TIMER_THRESHOLD);
+	reg &= ~WTT_THRESHOLD_MASK;
+	reg |= index;
+	iowrite8(reg, wdt->base + BOOT_FPGA_WATCHDOG_TIMER_THRESHOLD);
+
+	/* Set the actual timeout supported by the watchdog */
+	wdt->wdt_dev.timeout = ptx1kbf_index_to_timeout(index);
+
+	return 0;
+}
+
+static int ptx1kbf_wdt_ping(struct watchdog_device *wdt_dev)
+{
+	return ptx1kbf_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
+}
+
+static int ptx1kbf_wdt_start(struct watchdog_device *wdt_dev)
+{
+	struct ptx1kbf_wdt *wdt = watchdog_get_drvdata(wdt_dev);
+	int ret;
+	u8 reg;
+
+	ret = ptx1kbf_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
+	if (ret < 0)
+		return ret;
+
+	reg = ioread8(wdt->base + BOOT_FPGA_BOOT_CONTROL);
+	reg |= BC_WDT_ENA;
+	iowrite8(reg, wdt->base + BOOT_FPGA_BOOT_CONTROL);
+
+	return 0;
+}
+
+static int ptx1kbf_wdt_stop(struct watchdog_device *wdt_dev)
+{
+	struct ptx1kbf_wdt *wdt = watchdog_get_drvdata(wdt_dev);
+	u8 reg;
+
+	reg = ioread8(wdt->base + BOOT_FPGA_BOOT_CONTROL);
+	reg &= ~BC_WDT_ENA;
+	iowrite8(reg, wdt->base + BOOT_FPGA_BOOT_CONTROL);
+
+	return 0;
+}
+
+static struct watchdog_info ptx1kbf_wdt_info = {
+	.options	= WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
+			  WDIOF_MAGICCLOSE,
+	.identity	= "PTX1K BootFPGA Watchdog",
+	.firmware_version = 0,
+};
+
+static const struct watchdog_ops ptx1kbf_wdt_ops = {
+	.owner = THIS_MODULE,
+	.start = ptx1kbf_wdt_start,
+	.stop = ptx1kbf_wdt_stop,
+	.ping = ptx1kbf_wdt_ping,
+	.set_timeout = ptx1kbf_wdt_set_timeout,
+};
+
+static int ptx1kbf_wdt_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct resource *res;
+	struct ptx1kbf_wdt *wdt;
+	u8 reset_reason1, reset_reason2;
+	unsigned int timeout;
+
+	wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+	if (!wdt)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	wdt->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(wdt->base))
+		return PTR_ERR(wdt->base);
+
+	platform_set_drvdata(pdev, wdt);
+	wdt->wdt_dev.info = &ptx1kbf_wdt_info;
+	wdt->wdt_dev.ops = &ptx1kbf_wdt_ops;
+	wdt->wdt_dev.min_timeout = WDT_MIN_TIMEOUT;
+	wdt->wdt_dev.max_timeout = WDT_MAX_TIMEOUT;
+	wdt->wdt_dev.timeout = WDT_DEFAULT_TIMEOUT;
+	wdt->wdt_dev.parent = &pdev->dev;
+
+	reset_reason1 = ioread8(wdt->base + BOOT_FPGA_RESET_REASON1);
+	reset_reason2 = ioread8(wdt->base + BOOT_FPGA_RESET_REASON2);
+	if (reset_reason1 & RR1_MSTR)
+		wdt->wdt_dev.bootstatus |= WDIOF_EXTERN1;
+	else if (reset_reason1 & RR1_BUTTON)
+		wdt->wdt_dev.bootstatus |= WDIOF_EXTERN2;
+	else if (reset_reason1 & RR1_WDOG)
+		wdt->wdt_dev.bootstatus |= WDIOF_CARDRESET;
+	else if (reset_reason1 & RR1_POWER_FAIL)
+		wdt->wdt_dev.bootstatus |= WDIOF_POWERUNDER;
+	else if (reset_reason1 & RR1_THERM_TRIP)
+		wdt->wdt_dev.bootstatus |= WDIOF_OVERHEAT;
+	else if (reset_reason1 & RR2_AUTO_POWER_OFF)
+		wdt->wdt_dev.bootstatus |= WDIOF_FANFAULT;
+
+	/* Report the FPGA/WDT version */
+	ptx1kbf_wdt_info.firmware_version =
+				ioread8(wdt->base + BOOT_FPGA_VERSION);
+
+	/*
+	 * The PTX1K BIOS configures the timeout when the FPGA watchdog
+	 * is enabled. Index values < 0x07 set thresholds bellow 1s,
+	 * so we can ignore them
+	 */
+	timeout = ptx1kbf_index_to_timeout(ioread8(wdt->base +
+				BOOT_FPGA_WATCHDOG_TIMER_THRESHOLD));
+
+	watchdog_init_timeout(&wdt->wdt_dev, timeout, &pdev->dev);
+	watchdog_set_nowayout(&wdt->wdt_dev, nowayout);
+	watchdog_set_drvdata(&wdt->wdt_dev, wdt);
+
+	/* Stop the watchdog if BIOS has enabled it */
+	ptx1kbf_wdt_stop(&wdt->wdt_dev);
+
+	ret = watchdog_register_device(&wdt->wdt_dev);
+	if (ret)
+		return ret;
+
+	dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)",
+		 wdt->wdt_dev.timeout, nowayout);
+
+	return 0;
+}
+
+static int ptx1kbf_wdt_remove(struct platform_device *pdev)
+{
+	struct ptx1kbf_wdt *wdt = platform_get_drvdata(pdev);
+
+	watchdog_unregister_device(&wdt->wdt_dev);
+
+	return 0;
+}
+
+static const struct of_device_id ptx1kbf_wdt_of_ids[] = {
+	{ .compatible = "jnx,ptx1kbf-wdt", NULL },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ptx1kbf_wdt_of_ids);
+
+static struct platform_driver ptx1kbf_wdt_driver = {
+	.probe	= ptx1kbf_wdt_probe,
+	.remove = ptx1kbf_wdt_remove,
+	.driver = {
+		.name = DRVNAME,
+		.owner = THIS_MODULE,
+		.of_match_table = ptx1kbf_wdt_of_ids,
+	},
+};
+
+module_platform_driver(ptx1kbf_wdt_driver);
+
+MODULE_DESCRIPTION("Juniper Networks PTX1K RCB I2CS Boot FPGA watchdog driver");
+MODULE_AUTHOR("Georgi Vlaev <gvlaev at juniper.net>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRVNAME);
-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:21:58 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:21:58 +0300
Subject: [PATCH 1/7] mfd: Add PTX1K I2CS BootFPGA MFD driver
In-Reply-To: <1475853724-22557-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853724-22557-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853724-22557-2-git-send-email-pantelis.antoniou@konsulko.com>

From: Georgi Vlaev <gvlaev at juniper.net>

The driver allows access to the BootFPGA logic of the I2CS FPGA
@0xfed5000 from the LPC bus. The driver exports debugfs entries
for manipulating registers and device attrs for reading board and
FPGA IDs and switching the active BIOS flash. The client devices
created by the MFD driver depend on the PCB and FPGA version
numbers. PTX1K (etch1) RE boards support only watchdog clients.
Warn on using engineering releases (FPGA version = 0xEE) and
disable clients on revisions known to cause problems.

- watchdog - jnx_ptx1kbf_wdt
- mtd - jnx_ptx1kbf_mtd (etch2)
- hwmon - jnx_ptx1kbf_hwmon (etch2)

Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
Signed-off-by: Guenter Roeck <groeck at juniper.net>
Signed-off-by: JawaharBalaji Thirumalaisamy <jawaharb at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 drivers/mfd/Kconfig                |  11 +
 drivers/mfd/Makefile               |   1 +
 drivers/mfd/ptx1k-bootfpga.c       | 462 +++++++++++++++++++++++++++++++++++++
 include/linux/mfd/ptx1k-bootfpga.h |  93 ++++++++
 4 files changed, 567 insertions(+)
 create mode 100644 drivers/mfd/ptx1k-bootfpga.c
 create mode 100644 include/linux/mfd/ptx1k-bootfpga.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 82493d5..a2564ba 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1417,6 +1417,17 @@ config MFD_JUNIPER_I2CS
 	  This driver can be built as a module. If built as a module it will be
 	  called "jnx_i2cs"
 
+config MFD_JUNIPER_PTX1KBF
+	tristate "Juniper PTX1K RCB I2CS BootFPGA"
+	depends on JNX_PTX1K_RCB
+	select MFD_CORE
+	help
+	  Select this to enable the I2CS Boot FPGA multi-function kernel driver.
+	  This FPGA is present on the PTX1K RCB.
+
+	  This driver can be built as a module. If built as a module it will be
+	  called "ptx1k-bootfpga"
+
 config MFD_TWL4030_AUDIO
 	bool "TI TWL4030 Audio"
 	depends on TWL4030_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 215d9cf..1661b82 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -153,6 +153,7 @@ obj-$(CONFIG_MFD_JUNIPER_SAM)	+= sam-core.o
 obj-$(CONFIG_MFD_JUNIPER_EXT_CPLD) += ptxpmb-ext-cpld-core.o
 obj-$(CONFIG_MFD_JUNIPER_CBC)	+= cbc-core.o
 obj-$(CONFIG_MFD_JUNIPER_I2CS)	+= jnx-i2cs-core.o
+obj-$(CONFIG_MFD_JUNIPER_PTX1KBF) += ptx1k-bootfpga.o
 obj-$(CONFIG_MFD_DB8500_PRCMU)	+= db8500-prcmu.o
 # ab8500-core need to come after db8500-prcmu (which provides the channel)
 obj-$(CONFIG_AB8500_CORE)	+= ab8500-core.o ab8500-sysctrl.o
diff --git a/drivers/mfd/ptx1k-bootfpga.c b/drivers/mfd/ptx1k-bootfpga.c
new file mode 100644
index 0000000..5ab2ed2
--- /dev/null
+++ b/drivers/mfd/ptx1k-bootfpga.c
@@ -0,0 +1,462 @@
+/*
+ * Juniper Networks PTX1K RCB I2CS Boot FPGA multi-function core driver
+ *
+ * Copyright (C) 2014 Juniper Networks. All rights reserved.
+ * Author: Georgi Vlaev <gvlaev at juniper.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/acpi.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/ptx1k-bootfpga.h>
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#endif
+
+struct ptx1kbf_core {
+	struct device	*dev;
+	void __iomem	*base;
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dir;
+	u8 addr;				/* any register offsset */
+	struct debugfs_blob_wrapper blob;	/* regspace page blob */
+#endif
+};
+
+static struct resource ptx1kbf_resources[] = {
+	{
+		.start	= 0,
+		.end	= 0xff,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct mfd_cell ptx1kbf_cells[] = {
+	{
+		.name = "jnx-ptx1kbf-wdt",
+		.num_resources = ARRAY_SIZE(ptx1kbf_resources),
+		.resources = ptx1kbf_resources,
+		.of_compatible = "jnx,ptx1kbf-wdt",
+	}, {
+		.name = "jnx-ptx1kbf-mtd",
+		.num_resources = ARRAY_SIZE(ptx1kbf_resources),
+		.resources = ptx1kbf_resources,
+		.of_compatible = "jnx,ptx1kbf-mtd",
+	}, {
+		.name = "jnx-ptx1kbf-hwmon",
+		.num_resources = ARRAY_SIZE(ptx1kbf_resources),
+		.resources = ptx1kbf_resources,
+		.of_compatible = "jnx,ptx1kbf-hwmon",
+	},
+};
+
+/* ptx1k-bootfpga debugfs */
+#ifdef CONFIG_DEBUG_FS
+/* debugfs: set/get register offset */
+static int bf_debugfs_addr_print(struct seq_file *s, void *p)
+{
+	struct ptx1kbf_core *bf = (struct ptx1kbf_core *)s->private;
+
+	seq_printf(s, "0x%02X\n", bf->addr);
+
+	return 0;
+}
+
+static int bf_debugfs_addr_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, bf_debugfs_addr_print, inode->i_private);
+}
+
+static ssize_t bf_debugfs_addr_write(struct file *file,
+	const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	struct ptx1kbf_core *bf =
+		((struct seq_file *)(file->private_data))->private;
+	unsigned long addr;
+	int err;
+
+	err = kstrtoul_from_user(user_buf, count, 0, &addr);
+	if (err)
+		return err;
+
+	if (addr > ptx1kbf_resources[0].end) {
+		dev_err(bf->dev, "register offset out of range\n");
+		return -EINVAL;
+	}
+	bf->addr = addr;
+
+	return count;
+}
+
+static const struct file_operations bf_debugfs_addr_fops = {
+	.open = bf_debugfs_addr_open,
+	.write = bf_debugfs_addr_write,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
+/* debugfs: set/get register value */
+static int bf_debugfs_val_print(struct seq_file *s, void *p)
+{
+	struct ptx1kbf_core *bf = (struct ptx1kbf_core *)s->private;
+
+	seq_printf(s, "0x%02X\n", ioread8(bf->base + bf->addr));
+
+	return 0;
+}
+
+static int bf_debugfs_val_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, bf_debugfs_val_print, inode->i_private);
+}
+
+static ssize_t bf_debugfs_val_write(struct file *file,
+	const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	struct ptx1kbf_core *bf =
+		((struct seq_file *)(file->private_data))->private;
+	unsigned long value;
+	int err;
+
+	err = kstrtoul_from_user(user_buf, count, 0, &value);
+	if (err)
+		return err;
+
+	iowrite8(value & 0xff, bf->base + bf->addr);
+
+	return count;
+}
+
+static const struct file_operations bf_debugfs_val_fops = {
+	.open = bf_debugfs_val_open,
+	.write = bf_debugfs_val_write,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
+static int bf_debugfs_init(struct ptx1kbf_core *bf)
+{
+	struct dentry *file;
+
+	bf->dir = debugfs_create_dir("ptx1k-bootfpga", NULL);
+	if (!bf->dir)
+		return -ENOMEM;
+
+/* Register dump */
+	bf->blob.size = resource_size(&ptx1kbf_resources[0]);
+	bf->blob.data = bf->base;
+
+	file = debugfs_create_blob("reg-dump", S_IFREG | S_IRUSR, bf->dir,
+				   &bf->blob);
+	if (!file)
+		goto err;
+
+/* Any register @base */
+	file = debugfs_create_file("reg-address", (S_IRUGO | S_IWUSR),
+		bf->dir, bf, &bf_debugfs_addr_fops);
+	if (!file)
+		goto err;
+
+	file = debugfs_create_file("reg-value", (S_IRUGO | S_IWUSR),
+		bf->dir, bf, &bf_debugfs_val_fops);
+	if (!file)
+		goto err;
+
+	return 0;
+err:
+	debugfs_remove_recursive(bf->dir);
+	dev_err(bf->dev, "failed to create debugfs entries.\n");
+
+	return -ENOMEM;
+}
+
+static void bf_debugfs_remove(struct ptx1kbf_core *bf)
+{
+	debugfs_remove_recursive(bf->dir);
+}
+#endif /* CONFIG_DEBUG_FS */
+
+/* Export FPGA board revisions and status as device attrs */
+static ssize_t bf_reg_show(struct device *dev, char *buf, u8 reg)
+{
+	struct ptx1kbf_core *bf = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%02x\n", ioread8(bf->base + reg));
+}
+
+static ssize_t bf_version_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	return bf_reg_show(dev, buf, BOOT_FPGA_VERSION);
+}
+
+static ssize_t bf_board_id_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	return bf_reg_show(dev, buf, BOOT_FPGA_BOARD_ID);
+}
+
+static ssize_t bf_jspec_version_show(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	return bf_reg_show(dev, buf, BOOT_FPGA_JSPEC_VERSION);
+}
+
+static ssize_t bf_pcb_version_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	return bf_reg_show(dev, buf, BOOT_FPGA_PCB_VERSION);
+}
+
+static ssize_t bf_chassis_type_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	return bf_reg_show(dev, buf, BOOT_FPGA_CHASSIS_TYPE);
+}
+
+/* active_flash: (BIOS) Switch bethween FlashA and FlashB */
+static ssize_t bf_active_flash_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct ptx1kbf_core *bf = dev_get_drvdata(dev);
+	u8 reg = ioread8(bf->base + BOOT_FPGA_BOOT_CONTROL);
+
+	return sprintf(buf, "%u\n", (u8)(reg & BC_FLASH_SELECT) >> 4);
+}
+
+static ssize_t bf_active_flash_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct ptx1kbf_core *bf = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+	u8 reg;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	if (val > 1)
+		return -EINVAL;
+
+	reg = ioread8(bf->base + BOOT_FPGA_BOOT_CONTROL);
+	reg &= ~BC_FLASH_SELECT;
+	reg |= (u8)((val << 4) & BC_FLASH_SELECT);
+	iowrite8(reg, bf->base + BOOT_FPGA_BOOT_CONTROL);
+
+	return count;
+}
+
+static DEVICE_ATTR(version, S_IRUGO, bf_version_show, NULL);
+static DEVICE_ATTR(board_id, S_IRUGO, bf_board_id_show, NULL);
+static DEVICE_ATTR(jspec_version, S_IRUGO, bf_jspec_version_show, NULL);
+static DEVICE_ATTR(pcb_version, S_IRUGO, bf_pcb_version_show, NULL);
+static DEVICE_ATTR(chassis_type, S_IRUGO, bf_chassis_type_show, NULL);
+static DEVICE_ATTR(active_flash, S_IRUGO | S_IWUSR, bf_active_flash_show,
+		bf_active_flash_store);
+
+static struct attribute *bf_attrs[] = {
+	&dev_attr_version.attr,
+	&dev_attr_board_id.attr,
+	&dev_attr_jspec_version.attr,
+	&dev_attr_pcb_version.attr,
+	&dev_attr_chassis_type.attr,
+	&dev_attr_active_flash.attr,
+	NULL,
+};
+
+static struct attribute_group bf_attr_group = {
+	.attrs = bf_attrs,
+};
+
+/* Check if scratch regs are usable */
+static int bf_scratch_test(struct ptx1kbf_core *bf)
+{
+	u8 i, ii;
+
+	for (i = 0; i < 0xff; i++) {
+		iowrite8(i, bf->base + BOOT_FPGA_SCRATCH1);
+		ii = ioread8(bf->base + BOOT_FPGA_SCRATCH1);
+		if (ii != i) {
+			dev_err(bf->dev, "Scratch(1) write failed: %02x->%02x",
+				i, ii);
+			return -EIO;
+		}
+	}
+
+	for (i = 0; i < 0xff; i++) {
+		iowrite8(i, bf->base + BOOT_FPGA_SCRATCH2);
+		ii = ioread8(bf->base + BOOT_FPGA_SCRATCH2);
+		if (ii != i) {
+			dev_err(bf->dev, "Scratch(2) write failed: %02x->%02x",
+				i, ii);
+			return -EIO;
+		}
+	}
+
+	iowrite8(0, bf->base + BOOT_FPGA_SCRATCH1);
+	iowrite8(0, bf->base + BOOT_FPGA_SCRATCH2);
+
+	return 0;
+}
+
+static int ptx1kbf_probe(struct platform_device *pdev)
+{
+	static struct ptx1kbf_core *bf;
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	int err, ncells = 0;
+	u8 pcb_version, fpga_version;
+
+	bf = devm_kzalloc(dev, sizeof(struct ptx1kbf_core), GFP_KERNEL);
+	if (!bf)
+		return -ENOMEM;
+
+	bf->dev = dev;
+	dev_set_drvdata(dev, bf);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	bf->base = devm_ioremap_nocache(dev, res->start, resource_size(res));
+	if (IS_ERR(bf->base))
+		return -EADDRNOTAVAIL;
+
+	/* Get the FPGA & PCB versions to filter supported features */
+	fpga_version = ioread8(bf->base + BOOT_FPGA_VERSION),
+	pcb_version = ioread8(bf->base + BOOT_FPGA_PCB_VERSION);
+
+	dev_info(dev, "FPGA version: 0x%02X, PCB version: 0x%02X\n",
+		 fpga_version, pcb_version);
+
+	/* Exit if scratch loop fails */
+	err = bf_scratch_test(bf);
+	if (err)
+		return err;
+
+	/*
+	 * Support matrix.
+	 * PCB version #0 (ETCH1) = Spartan XC3S400AN
+	 * PCB version #1 (ETCH2) = Spartan XC3S700AN
+	 *
+	 * PCB version #0 supported devices
+	 *	- watchdog (FPGA version >= 0x0E)
+	 *	- hwmon & mtd unsupported due to FPGA limitations
+	 *
+	 * PCB version #1 supported devices
+	 *	- watchdog (FPGA version >= 0x0E)
+	 *	- mtd devices (FPGA version > 0x0E)
+	 *	- hwmon (FPGA version > 0x0F ?)
+	 *
+	 * FPGA version 0xEE is "engineering release", warn on usage.
+	 * FPGA version 0xC0 and < 0x0E are unsupported.
+	 */
+
+	/* Engineering release - allow it to run for testing/debug */
+	if (fpga_version == 0xEE) {
+		dev_warn(dev,
+			"0x%02X is engineering release, consider FPGA update",
+			fpga_version);
+	}
+
+	if (fpga_version != 0xC0 && fpga_version >= 0x0E) {
+		/* wdt - any pcb, fpga >= 0x0E && !0xC0 */
+		ncells = 1;
+
+		/* mtd - pcb > 0, fpga >= 0x0F
+		 * Versions bellow 0x0F may cause damage of the flash (!)
+		 */
+		if (pcb_version > 0 && fpga_version > 0x0E)
+			ncells = 2;
+
+		/* hwmon - pcb > 0, fpga > 0x0F (assumption) */
+		if (pcb_version > 0 && fpga_version > 0x0F)
+			ncells = 3;
+
+		err = mfd_add_devices(dev, pdev->id, ptx1kbf_cells,
+				      ncells, res, 0, NULL);
+		if (err)
+			return err;
+	} else {
+		/* Unsupported - known to cause problems: 0xC0, < 0x0E */
+		dev_err(dev,
+			"0x%02X is unsupported version, consider FPGA update",
+			fpga_version);
+	}
+
+	err = sysfs_create_group(&dev->kobj, &bf_attr_group);
+	if (err) {
+		sysfs_remove_group(&dev->kobj, &bf_attr_group);
+		goto err_mfd;
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	bf_debugfs_init(bf);
+#endif
+
+	return 0;
+
+err_mfd:
+	mfd_remove_devices(&pdev->dev);
+
+	return err;
+}
+
+static int ptx1kbf_remove(struct platform_device *pdev)
+{
+#ifdef CONFIG_DEBUG_FS
+	struct ptx1kbf_core *bf = dev_get_drvdata(&pdev->dev);
+
+	bf_debugfs_remove(bf);
+#endif
+	sysfs_remove_group(&pdev->dev.kobj, &bf_attr_group);
+	mfd_remove_devices(&pdev->dev);
+	return 0;
+}
+
+static const struct of_device_id ptx1kbf_of_ids[] = {
+	{ .compatible = "jnx,ptx1k-bootfpga" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ptx1kbf_of_ids);
+
+static struct platform_driver ptx1kbf_driver = {
+	.driver		= {
+		.name	= "ptx1k-bootfpga",
+		.of_match_table = ptx1kbf_of_ids,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ptx1kbf_probe,
+	.remove		= ptx1kbf_remove,
+};
+
+module_platform_driver(ptx1kbf_driver);
+
+MODULE_DESCRIPTION("Juniper Networks PTX1K RCB I2CS Boot FPGA Driver");
+MODULE_AUTHOR("Georgi Vlaev <gvlaev at juniper.net>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ptx1k-bootfpga");
diff --git a/include/linux/mfd/ptx1k-bootfpga.h b/include/linux/mfd/ptx1k-bootfpga.h
new file mode 100644
index 0000000..6a40c95
--- /dev/null
+++ b/include/linux/mfd/ptx1k-bootfpga.h
@@ -0,0 +1,93 @@
+/*
+ * PTX1K I2CS Boot FPGA registers
+ *
+ * Copyright (C) 2014 Juniper Networks. All rights reserved.
+ * Author: Georgi Vlaev <gvlaev at juniper.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __PTX1K_BOOTFPGA_H__
+#define __PTX1K_BOOTFPGA_H__
+
+#include <linux/bitops.h>
+
+#define BOOT_FPGA_SCRATCH1			0x00
+#define BOOT_FPGA_SCRATCH2			0x01
+#define BOOT_FPGA_VERSION			0x02
+#define BOOT_FPGA_JSPEC_VERSION			0x03
+#define BOOT_FPGA_PCB_VERSION			0x04
+#define BOOT_FPGA_BOARD_ID			0x05
+#define BOOT_FPGA_RESET_REASON1			0x06
+#define BOOT_FPGA_RESET_REASON2			0x07
+#define BOOT_FPGA_RESET_CONTROL_AND_STATUS1	0x08
+#define BOOT_FPGA_RESET_CONTROL_AND_STATUS2	0x09
+#define BOOT_FPGA_RESET_CONTROL_AND_STATUS3	0x0a
+#define BOOT_FPGA_BOOT_CONTROL			0x0b
+#define BOOT_FPGA_WATCHDOG_TIMER_THRESHOLD	0x0c
+#define BOOT_FPGA_ERROR_STATUS1			0x0d
+#define BOOT_FPGA_ERROR_STATUS2			0x0e
+#define BOOT_FPGA_ERROR_STATUS3			0x0f
+#define BOOT_FPGA_IRQ_ENABLE1			0x10
+#define BOOT_FPGA_IRQ_STATUS1			0x11
+#define BOOT_FPGA_IRQ_ENABLE2			0x12
+#define BOOT_FPGA_IRQ_STATUS2			0x13
+#define BOOT_FPGA_CHASSIS_TYPE			0x14
+#define BOOT_FPGA_POST_CODE			0x15
+#define BOOT_FPGA_MISC_CONTROL			0x16
+#define BOOT_FPGA_MISC_STATUS			0x17
+#define BOOT_FPGA_CPU_TEMP_MSB			0x18
+#define BOOT_FPGA_CPU_TEMP_LSB			0x19
+#define BOOT_FPGA_PCH_TEMP_MSB			0x1a
+#define BOOT_FPGA_PCH_TEMP_LSB			0x1b
+#define BOOT_FPGA_DIMM1_TEMP_MSB		0x1c
+#define BOOT_FPGA_DIMM1_TEMP_LSB		0x1d
+#define BOOT_FPGA_DIMM2_TEMP_MSB		0x1e
+#define BOOT_FPGA_DIMM2_TEMP_LSB		0x1f
+
+#define BOOT_FPGA_SFPP_USB_SSD_PWR_CONTROL	0x20
+#define BOOT_FPGA_FPGA_ID			0x21
+#define BOOT_FPGA_SPI_FLASH_CONTROL_AND_STATUS	0x22
+#define BOOT_FPGA_PCH_NMI_SLEEP_RT_STATUS	0x23
+#define BOOT_FPGA_PCH_NMI_SLEEP_LATCHED_STATUS	0x24
+
+#define BOOT_FPGA_FLASH_IF_ADDR(a)		(0xe0 + (a))
+#define BOOT_FPGA_FLASH_IF_BYTE_COUNT(a)	(0xe4 + (a))
+#define BOOT_FPGA_FLASH_IF_CONTROL(a)		(0xe8 + (a))
+#define BOOT_FPGA_FLASH_IF_STATUS(a)		(0xec + (a))
+#define BOOT_FPGA_FLASH_IF_WRITE_BUF_ADDR_MSB	0xf0
+#define BOOT_FPGA_FLASH_IF_WRITE_BUF_ADDR_LSB	0xf1
+#define BOOT_FPGA_FLASH_IF_WRITE_BUF_DATA	0xf2
+#define BOOT_FPGA_FLASH_IF_READ_BUF_ADDR_MSB	0xf3
+#define BOOT_FPGA_FLASH_IF_READ_BUF_ADDR_LSB	0xf4
+#define BOOT_FPGA_FLASH_IF_READ_BUF_DATA	0xf5
+
+#define BOOT_FPGA_RU_CONFIG_CONTROL_STATUS	0xf6
+#define BOOT_FPGA_RU_CONFIG_STATUS_DATA_MSB	0xf7
+#define BOOT_FPGA_RU_CONFIG_STATUS_DATA_LSB	0xf8
+#define BOOT_FPGA_RU_CONFIG_ADDR_23_DOWNTO_16	0xf9
+#define BOOT_FPGA_RU_CONFIG_ADDR_15_DOWNTO_8	0xfa
+#define BOOT_FPGA_RU_CONFIG_ADDR_7_DOWNTO_0	0xfb
+
+#define RR1_SW		BIT(7)	/* SW initiated reset */
+#define RR1_WDOG	BIT(6)	/* Watchdog induced reset */
+#define RR1_MSTR	BIT(5)	/* System host (Master RE) initiated reset */
+#define RR1_BUTTON	BIT(4)	/* Front panel button reset */
+#define RR1_POWER_CYCLE	BIT(3)	/* Natural power cycle */
+#define RR1_POWER_FAIL	BIT(2)	/* Power fail */
+#define RR1_THERM_TRIP	BIT(1)	/* CPU thermal trip */
+#define RR1_PCH		BIT(0)	/* PCH initiated reset, e.g TCO timer expiry */
+
+#define RR2_MSMI_FATAL		BIT(3)	/* CPU MSMI# fatal reset */
+#define RR2_CATERR_IERR		BIT(2)	/* CPU CATERR_IERR# induced reset */
+#define RR2_XDP			BIT(1)	/* XDP request reset */
+#define RR2_AUTO_POWER_OFF	BIT(0)	/* Auto power off */
+
+#define BC_WDT_ENA		BIT(6)	/* Watchdog timer enable */
+#define BC_FLASH_SELECT		BIT(4)	/* Flash select enable/status */
+#define WTT_THRESHOLD_MASK	0x3f
+
+#endif /*__PTX1K_BOOTFPGA_H__*/
-- 
1.9.1



From pantelis.antoniou at konsulko.com  Fri Oct  7 08:18:35 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Fri,  7 Oct 2016 18:18:35 +0300
Subject: [PATCH 07/10] mtd: Add SAM Flash driver
In-Reply-To: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1475853518-22264-8-git-send-email-pantelis.antoniou@konsulko.com>

From: Guenter Roeck <groeck at juniper.net>

Add driver for the flash block in Juniper's SAM FPGA.

This driver is used for updating the Altera's EPCS(64,256)
configuration flash devices via a Juniper defined hardware
interface.

Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
Signed-off-by: Guenter Roeck <groeck at juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
---
 drivers/mtd/devices/Kconfig     |  11 +
 drivers/mtd/devices/Makefile    |   1 +
 drivers/mtd/devices/sam-flash.c | 642 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 654 insertions(+)
 create mode 100644 drivers/mtd/devices/sam-flash.c

diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index d4255fb..f5a9032 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -144,6 +144,17 @@ config MTD_LART
 	  not need any mapping/chip driver for LART. This one does it all
 	  for you, so go disable all of those if you enabled some of them (:
 
+config MTD_SAM_FLASH
+	tristate "Juniper SAM Flash driver"
+	depends on MFD_JUNIPER_SAM || MFD_JUNIPER_CBC
+	default y if MFD_JUNIPER_SAM
+	help
+	  This enables the flash driver for the SAM FPGA which is present
+	  on relevant Juniper platforms.
+
+	  This driver can also be built as a module. When it is so the name of
+	  the module is flash-sam.
+
 config JNX_PMB_NVRAM
 	tristate "Juniper FPC PMB NVRAM Driver"
 	depends on (PTXPMB_COMMON || JNX_PTX_NGPMB)
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
index b407c5fc..7556311 100644
--- a/drivers/mtd/devices/Makefile
+++ b/drivers/mtd/devices/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_MTD_BCM47XXSFLASH)	+= bcm47xxsflash.o
 obj-$(CONFIG_MTD_ST_SPI_FSM)    += st_spi_fsm.o
 obj-$(CONFIG_MTD_POWERNV_FLASH)	+= powernv_flash.o
 
+obj-$(CONFIG_MTD_SAM_FLASH)	+= sam-flash.o
 obj-$(CONFIG_JNX_PMB_NVRAM)     += jnx_pmb_nvram.o
 
 CFLAGS_docg3.o			+= -I$(src)
diff --git a/drivers/mtd/devices/sam-flash.c b/drivers/mtd/devices/sam-flash.c
new file mode 100644
index 0000000..5f071e6
--- /dev/null
+++ b/drivers/mtd/devices/sam-flash.c
@@ -0,0 +1,642 @@
+/*
+ * Copyright (C) 2012 Juniper networks
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/errno.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+#define SAM_FLASH_DEBUG_ENABLED
+#undef  T5E_MAX_FLASH_READ_WAIT_TIME_FIXED
+#define SAM_FLASH_IF_READ_MAX_SIZE		32	/* 256?! */
+
+#define SAM_FLASH_BASE		0x300
+
+#define ADDR_REG(x)		((x)->membase + SAM_FLASH_BASE + 0x000)
+#define COUNTER_REG(x)		((x)->membase + SAM_FLASH_BASE + 0x004)
+#define CONTROL_REG(x)		((x)->membase + SAM_FLASH_BASE + 0x008)
+#define STATUS_REG(x)		((x)->membase + SAM_FLASH_BASE + 0x00c)
+#define WRITE_DATA_REG(x)	((x)->membase + SAM_FLASH_BASE + 0x100)
+#define READ_DATA_REG(x)	((x)->membase + SAM_FLASH_BASE + 0x200)
+
+static int sam_flash_if_read_max_size = SAM_FLASH_IF_READ_MAX_SIZE;
+module_param(sam_flash_if_read_max_size, int, S_IRUSR | S_IRGRP | S_IWUSR);
+MODULE_PARM_DESC(sam_flash_if_read_max_size,
+		 "maximum read size done by SAM flash IF");
+
+#ifdef SAM_FLASH_DEBUG_ENABLED
+
+static int sam_flash_debug;
+module_param(sam_flash_debug, int, S_IRUSR | S_IRGRP | S_IWUSR);
+MODULE_PARM_DESC(sam_flash_debug, "enable debugging information");
+
+#define SAM_FLASH_DEBUG(dev, fmt, args...)			\
+	do {							\
+		if (sam_flash_debug) {				\
+			dev_info(dev, fmt, ## args);		\
+		}						\
+	} while (0)
+#else /* SAM_FLASH_DEBUG_ENABLED */
+#define SAM_FLASH_DEBUG(dev, fmt, args...)      {}
+#endif /* SAM_FLASH_DEBUG_ENABLED */
+
+/*
+ *  Ref: pfe/common/toolkis/flash/altera_epcs_as.h
+ */
+#define EPCS_EXT_STS_ID(sts)		((u8)((sts >> 8) & 0xff))
+#define EPCS_EXT_STS_RDSTS(sts)		((u8)((sts >> 16) & 0xff))
+#define EPCS_EXT_STS_SID(sts)		((u8)((sts >> 24) & 0xff))
+/* EPCS Device "read status" bits */
+#define EPCS_STS_WIP_BIT		0x01
+#define EPCS_STS_WLE_BIT		0x02
+#define EPCS_STS_BP_BITS(status)	((status >> 2) & 0x7)
+
+/*
+ *  Ref: pfe/common/toolkis/flash/altera_epcs_as.h
+ */
+#define EPCS64_S_ID			0x16
+#define EPCS64_NAME			"Altera EPCS64"
+#define EPCS64_SECT_SZ_SHIFT		16
+#define EPCS64_SECTOR_SIZE		(1 << EPCS64_SECT_SZ_SHIFT)
+#define EPCS64_SECTORS			128
+#define EPCS64_ADDR_TO_SECTOR(_addr)	((_addr) >> EPCS64_SECT_SZ_SHIFT)
+#define EPCS64_PAGE_SIZE		256
+#define EPCS64_PAGES			32768
+#define EPCS64_SIZE			(EPCS64_PAGE_SIZE * EPCS64_PAGES)
+#define EPCS64_MIN_SECT(bp_bits)	(EPCS64_SECTORS - (1 << bp_bits))
+
+/*
+ *  Ref: pfe/common/toolkis/flash/altera_epcs_as.h
+ *  timeout for busy:   t5e-pic/t5e_flash.c
+ */
+#define EPCS_TIMEOUT_BUSY		1
+#define EPCS_TIMEOUT_SINGLE_BYTE_READ	3
+#define EPCS_TIMEOUT_READ_ID		3
+#define EPCS_TIMEOUT_READ_STATUS	3
+
+/*
+ *  Ref: pfe/common/toolkis/flash/altera_epcs_as.h
+ *  timeout for waiting completion:   t5e-pic/t5e_flash.c
+ */
+#define EPCS_RD_TIMEO		20
+#define EPCS_WR_TIMEO		25
+#define EPCS_BLK_WR_TIMEO	25
+#define EPCS_SC_ER_TIMEO	(10 * 1000)
+#define EPCS_SC_PRT_TIMEO	35
+#define EPCS_CH_ER_TIMEO	(200 * 1000)
+/* */
+#define EPCS_STS_BSY_BIT	0x01
+#define EPCS_ILLEGAL_WR_BIT	0x02
+#define EPCS_ILLEGAL_RD_BIT	0x04
+#define EPCS_ILLEGAL		(EPCS_ILLEGAL_WR_BIT | EPCS_ILLEGAL_RD_BIT)
+#define EPCS_STATUS_BUSY(s)	((s) & EPCS_STS_BSY_BIT)
+
+/*
+ *  Ref t5e-pic/t5e_flash.c
+ */
+#define EPCS_BUSY_POLLING_START_DELAY		100	/* us */
+#define EPCS_BUSY_POLLING_START_DELAY_CNT	10
+#define EPCS_BUSY_POLLING_DELAY		(EPCS_BUSY_POLLING_START_DELAY_CNT * \
+					 EPCS_BUSY_POLLING_START_DELAY)
+
+/*
+ * FPGA flash control register: t5e-pic/t5e_fpga.h
+ */
+#define SAM_FLASH_IF_CONTROL_READ_SID		0x00000080
+#define SAM_FLASH_IF_CONTROL_CHIP_ERASE		0x00000040
+#define SAM_FLASH_IF_CONTROL_SECTOR_ERASE	0x00000020
+#define SAM_FLASH_IF_CONTROL_SECTOR_PROTECT	0x00000010
+#define SAM_FLASH_IF_CONTROL_READ_STATUS	0x00000008
+#define SAM_FLASH_IF_CONTROL_READ_ID		0x00000004
+#define SAM_FLASH_IF_CONTROL_WRITE		0x00000002
+#define SAM_FLASH_IF_CONTROL_READ		0x00000001
+#define SAM_FLASH_IF_WRITE_REG_SIZE		sizeof(u32)
+#define SAM_FLASH_IF_READ_REG_SIZE		sizeof(u32)
+
+struct sam_flash_info {
+	const char *name;
+	u8 device_id;
+	size_t flash_size;
+	size_t page_size;
+	size_t nr_pages;
+	size_t nr_sectors;
+	size_t erasesize;
+	size_t writesize;
+	size_t writebufsize;
+};
+
+static struct sam_flash_info sam_flash_info_db[] = {
+	{
+		.name = EPCS64_NAME,
+		.device_id = EPCS64_S_ID,
+		.flash_size = EPCS64_SIZE,
+		.page_size = EPCS64_PAGE_SIZE,
+		.nr_pages = EPCS64_PAGES,
+		.nr_sectors = EPCS64_SECTORS,
+		.erasesize = EPCS64_SECTOR_SIZE,
+		.writesize = 4,
+		.writebufsize = 4,
+	},
+};
+
+#define SAM_FLASH_INFO_DB_SIZE	ARRAY_SIZE(sam_flash_info_db)
+
+/**
+ * struct sam_flash - SAM FLASH private data structure.
+ * @membase:		PCI base address of Memory mapped I/O register.
+ * @reg:		Memory mapped PCH GPIO register list.
+ * @dev:		Pointer to device structure.
+ */
+struct sam_flash {
+	void __iomem *membase;
+	struct mutex lock;
+	struct device *dev;
+	struct sam_flash_info *info;
+	struct mtd_info mtd_info;
+};
+
+#define mtd_to_sam_flash(mtd) container_of(mtd, struct sam_flash, mtd_info)
+
+static bool sam_flash_if_busy(struct sam_flash *sam_flash, int retry)
+{
+	u32 status;
+
+	do {
+		status = ioread32(STATUS_REG(sam_flash));
+		if (!EPCS_STATUS_BUSY(status))
+			return false;
+		if (retry <= 1)
+			return true;
+		usleep_range(50, 100);
+	} while (--retry >= 0);
+
+	return true;
+}
+
+static int
+sam_flash_if_busy_wait(struct sam_flash *sam_flash, unsigned int max_wait_msec)
+{
+	unsigned long timeout;
+	u32 status;
+
+	timeout = jiffies + msecs_to_jiffies(max_wait_msec);
+	udelay(50);
+
+	do {
+		status = ioread32(STATUS_REG(sam_flash));
+		if (!EPCS_STATUS_BUSY(status))
+			return 0;
+
+		if (status & EPCS_ILLEGAL)
+			return -EACCES;
+
+		usleep_range(50, 100);
+	} while (time_before(jiffies, timeout));
+
+	return -ETIMEDOUT;
+}
+
+static int
+sam_flash_mem_read(struct sam_flash *sam_flash, u32 offset,
+		   u8 *data, size_t len)
+{
+	struct sam_flash_info *info = sam_flash->info;
+	void __iomem *io_addr;
+	u32 io_data;
+	int i, cnt;
+
+	if (offset >= info->flash_size || offset + len > info->flash_size)
+		return -EINVAL;
+
+	if (sam_flash_if_busy(sam_flash, EPCS_TIMEOUT_BUSY))
+		return -ETIMEDOUT;
+
+	iowrite32(len - 1, COUNTER_REG(sam_flash));
+	iowrite32(offset, ADDR_REG(sam_flash));
+
+	/* trigger the read */
+	iowrite32(SAM_FLASH_IF_CONTROL_READ, CONTROL_REG(sam_flash));
+	ioread32(CONTROL_REG(sam_flash));
+
+	/*
+	 * Before we start polling the busy bit, wait for some time,
+	 * so that, the busy bit will go high
+	 */
+#ifdef T5E_MAX_FLASH_READ_WAIT_TIME_FIXED
+	udelay(50);
+#else /* T5E_MAX_FLASH_READ_WAIT_TIME_FIXED */
+	udelay(50 * ((len >> 2) + 1));	/* 50 usec every 4 bytes */
+#endif /* T5E_MAX_FLASH_READ_WAIT_TIME_FIXED */
+
+	if (sam_flash_if_busy(sam_flash, EPCS_TIMEOUT_SINGLE_BYTE_READ))
+		return -ETIMEDOUT;
+
+	io_data = ioread32(COUNTER_REG(sam_flash));
+	if (io_data != len - 1)
+		return -EIO;
+
+	SAM_FLASH_DEBUG(sam_flash->dev,
+			"%s BYTE_CNT: len: %u, io_data: %u.\n",
+			__func__, (unsigned int)len, io_data);
+
+	io_addr = READ_DATA_REG(sam_flash);
+	for (cnt = 0; cnt < len; io_addr += sizeof(u32)) {
+		io_data = ioread32(io_addr);
+		for (i = 0; i < sizeof(u32) && cnt < len; i++, cnt++)
+			*(data++) = (io_data >> (i << 3)) & 0xff;
+	}
+
+	return 0;
+}
+
+static int sam_flash_read_sid(struct sam_flash *sam_flash)
+{
+	u32 io_data;
+
+	iowrite32(SAM_FLASH_IF_CONTROL_READ_SID, CONTROL_REG(sam_flash));
+	ioread32(CONTROL_REG(sam_flash));
+
+	/*
+	 * Before we start polling the busy bit, wait for some time
+	 * to ensure that busy bit is high.
+	 */
+	udelay(EPCS_BUSY_POLLING_DELAY);
+	if (sam_flash_if_busy(sam_flash, EPCS_TIMEOUT_READ_ID))
+		return -ETIMEDOUT;
+
+	io_data = ioread32(STATUS_REG(sam_flash));
+
+	return EPCS_EXT_STS_SID(io_data);
+}
+
+static struct sam_flash_info *sam_flash_get_info(struct sam_flash *sam_flash)
+{
+	struct sam_flash_info *info;
+	u8 sid;
+	int idx;
+
+	sid = sam_flash_read_sid(sam_flash);
+	if (sid < 0)
+		return ERR_PTR(sid);
+
+	info = ERR_PTR(-EINVAL);
+	for (idx = 0; idx < SAM_FLASH_INFO_DB_SIZE; idx++) {
+		if (sam_flash_info_db[idx].device_id == sid) {
+			info = &sam_flash_info_db[idx];
+			break;
+		}
+	}
+	return info;
+}
+
+static inline int sam_flash_get_page_num(struct sam_flash *sam_flash,
+					 u32 offset)
+{
+	return offset / sam_flash->info->page_size;
+}
+
+static int sam_flash_mem_write(struct sam_flash *sam_flash, u32 offset,
+			       const u8 *data, size_t len)
+{
+	struct sam_flash_info *info = sam_flash->info;
+	int status, bytes_in_reg, cnt, cnt2;
+	int start_page, end_page;
+	void __iomem *io_addr;
+	u32 io_data;
+	const u8 *buf;
+
+	start_page = sam_flash_get_page_num(sam_flash, offset);
+	end_page = sam_flash_get_page_num(sam_flash, offset + len - 1);
+
+	/*
+	 *  Based on Altera EPCS Device Datasheet,
+	 *  Writing with multiple byte must be in the __SAME__ page.
+	 *  Not sure if SAM FPGA takes that so ...
+	 */
+	if (len > info->page_size ||
+	    start_page != end_page ||
+	    start_page >= info->nr_pages) {
+		dev_err(sam_flash->dev, "Bad write length / offset\n");
+		return -EINVAL;
+	}
+
+	/* check if FPGA is ready to accept new command */
+	if (sam_flash_if_busy(sam_flash, EPCS_TIMEOUT_BUSY)) {
+		dev_err(sam_flash->dev, "chip is busy\n");
+		return -ETIMEDOUT;
+	}
+
+	iowrite32(len - 1, COUNTER_REG(sam_flash));
+
+	/* copy the data to WRITE_DATA register */
+	io_addr = WRITE_DATA_REG(sam_flash);
+	for (buf = data, cnt = 0; cnt < len;) {
+		bytes_in_reg = len - cnt;
+		if (bytes_in_reg > SAM_FLASH_IF_WRITE_REG_SIZE)
+			bytes_in_reg = SAM_FLASH_IF_WRITE_REG_SIZE;
+		io_data = 0;
+		for (cnt2 = 0; cnt2 < bytes_in_reg; cnt2++, buf++)
+			io_data |= *buf << (cnt2 << 3);
+
+		iowrite32(io_data, io_addr);
+		cnt += bytes_in_reg;
+		io_addr += bytes_in_reg;
+	}
+
+	iowrite32(offset, ADDR_REG(sam_flash));
+	/* trigger the write */
+	iowrite32(SAM_FLASH_IF_CONTROL_WRITE, CONTROL_REG(sam_flash));
+	ioread32(CONTROL_REG(sam_flash));
+
+	status = sam_flash_if_busy_wait(sam_flash, EPCS_WR_TIMEO);
+	return status;
+}
+
+static int sam_flash_mem_is_protected(struct sam_flash *sam_flash,
+				      u32 offset, size_t len)
+{
+	struct sam_flash_info *info = sam_flash->info;
+	u32 flash_status;
+	u32 sector;
+	u32 io_data;
+	int status = 0;
+
+	iowrite32(SAM_FLASH_IF_CONTROL_READ_STATUS, CONTROL_REG(sam_flash));
+	if (sam_flash_if_busy(sam_flash, EPCS_TIMEOUT_READ_ID))
+		return -ETIMEDOUT;
+
+	io_data = ioread32(STATUS_REG(sam_flash));
+	flash_status = EPCS_EXT_STS_RDSTS(io_data);
+	sector = EPCS64_ADDR_TO_SECTOR(offset);
+	if (EPCS_STS_BP_BITS(flash_status) &&
+	    sector < info->erasesize &&
+	    sector >= EPCS64_MIN_SECT(EPCS_STS_BP_BITS(flash_status))) {
+		status = -EACCES;
+		SAM_FLASH_DEBUG(sam_flash->dev,
+				"%s offset: 0x%x, len: %u: PROTECTED(0x%x): %d.\n",
+				__func__, offset, (unsigned int)len,
+				flash_status, status);
+	}
+
+	return status;
+}
+
+static int sam_flash_erase_sector(struct sam_flash *sam_flash, u32 offset)
+{
+	iowrite32(offset, ADDR_REG(sam_flash));
+	iowrite32(SAM_FLASH_IF_CONTROL_SECTOR_ERASE, CONTROL_REG(sam_flash));
+
+	return sam_flash_if_busy_wait(sam_flash, EPCS_SC_ER_TIMEO);
+}
+
+static int sam_flash_erase(struct mtd_info *mtd_info,
+			   struct erase_info *erase_info)
+{
+	struct sam_flash *sam_flash = mtd_to_sam_flash(mtd_info);
+	u32 len, start, end, offset;
+	int status = 0;
+
+	len = (u32) erase_info->len;
+	start = (u32) erase_info->addr;
+	end = start + len - 1;
+
+	offset = start;
+	mutex_lock(&sam_flash->lock);
+	erase_info->state = MTD_ERASE_DONE;
+	while (offset < end) {
+		status = sam_flash_erase_sector(sam_flash, offset);
+		if (status) {
+			erase_info->state = MTD_ERASE_FAILED;
+			break;
+		}
+		offset += mtd_info->erasesize;
+	}
+	mutex_unlock(&sam_flash->lock);
+
+	mtd_erase_callback(erase_info);
+
+	return status;
+}
+
+static int sam_flash_read(struct mtd_info *mtd_info, loff_t from, size_t len,
+			  size_t *retlen, unsigned char *buf)
+{
+	struct sam_flash *sam_flash = mtd_to_sam_flash(mtd_info);
+	int cnt, max_cnt;
+	int status = 0;
+
+	*retlen = 0;
+
+	max_cnt = len / sam_flash_if_read_max_size;
+	if (len % sam_flash_if_read_max_size != 0)
+		max_cnt++;
+	mutex_lock(&sam_flash->lock);
+	for (cnt = 0; cnt < max_cnt; cnt++) {
+		u32 from2;
+		size_t len2;
+		u8 *buf2;
+
+		from2 = from + *retlen;
+		buf2 = buf + *retlen;
+		len2 = len - *retlen;
+		if (len2 > sam_flash_if_read_max_size)
+			len2 = sam_flash_if_read_max_size;
+
+		status = sam_flash_mem_read(sam_flash, from2, buf2, len2);
+		if (status != 0) {
+			dev_err(sam_flash->dev,
+				"RD: cnt: %04d(%04d): from: %u(%u), len: %u(%u) failed: %d.\n",
+				cnt, max_cnt, from2, (u32) from,
+				(unsigned int)len2, (unsigned int)len, status);
+			break;
+		}
+		*retlen += len2;
+	}
+	mutex_unlock(&sam_flash->lock);
+
+	return status;
+}
+
+static int sam_flash_write(struct mtd_info *mtd_info, loff_t to,
+			   size_t len, size_t *retlen, const unsigned char *buf)
+{
+	struct sam_flash *sam_flash = mtd_to_sam_flash(mtd_info);
+	int status, done, to_be_done;
+
+	mutex_lock(&sam_flash->lock);
+	status = sam_flash_mem_is_protected(sam_flash, to, len);
+	if (status)
+		goto abort;
+
+	for (done = 0; done < len; done += to_be_done) {
+		to_be_done = to & (sam_flash->info->page_size - 1);
+		if (to_be_done == 0) {
+			/* 'to' is page aligned */
+			to_be_done = len - done;
+			if (to_be_done > sam_flash->info->page_size)
+				to_be_done = sam_flash->info->page_size;
+		} else {
+			to_be_done = sam_flash->info->page_size - to_be_done;
+		}
+
+		SAM_FLASH_DEBUG(sam_flash->dev,
+				"%s to: 0x%x, buf: 0x%p, to_be_done: %d, done: %d, len: %d.\n",
+				__func__,
+				(u32) to, buf, to_be_done,
+				done, (unsigned int)len);
+		status = sam_flash_mem_write(sam_flash, to, buf, to_be_done);
+		if (status) {
+			dev_err(sam_flash->dev,
+				"WR: failed to 0x%x, buf: 0x%p, done: %d(%d), to_be_done: %d: %d.\n",
+				(u32)to, buf, done, (unsigned int)len,
+				to_be_done, status);
+			break;
+		}
+
+		to += to_be_done;
+		buf += to_be_done;
+	}
+
+	if (!status)
+		*retlen = len;
+
+abort:
+	mutex_unlock(&sam_flash->lock);
+	return status;
+}
+
+static int sam_flash_mtd_attach(struct platform_device *pdev,
+				struct sam_flash *sam_flash)
+{
+	struct mtd_part_parser_data ppdata = {};
+	struct sam_flash_info *info;
+	struct device *dev = sam_flash->dev;
+	struct mtd_info *mtd_info;
+	int ret;
+
+	info = sam_flash_get_info(sam_flash);
+	if (IS_ERR(info))
+		return PTR_ERR(info);
+
+	sam_flash->info = info;
+
+	mtd_info = &sam_flash->mtd_info;
+	mtd_info->name = dev_name(dev);
+	mtd_info->type = MTD_NORFLASH;
+	mtd_info->flags = MTD_CAP_NORFLASH;
+	mtd_info->erasesize = info->erasesize;
+	mtd_info->writesize = info->writesize;
+	mtd_info->writebufsize = info->writebufsize;
+	mtd_info->size = info->flash_size;
+	mtd_info->_erase = sam_flash_erase;
+	mtd_info->_read = sam_flash_read;
+	mtd_info->_write = sam_flash_write;
+
+	ret = mtd_device_parse_register(mtd_info, NULL, &ppdata, NULL, 0);
+	if (ret) {
+		dev_err(dev, "mtd_device_parse_register returned %d\n", ret);
+		return ret;
+	}
+
+	dev_info(dev,
+		 "ATTACH: name: \"%s\" type: %d, flags: 0x%x.\n",
+		 mtd_info->name, mtd_info->type, mtd_info->flags);
+	dev_info(dev,
+		 "ATTACH: erasesize: %d, writesize: %d, writebufsize: %d\n",
+		 mtd_info->erasesize, mtd_info->writesize,
+		 mtd_info->writebufsize);
+	dev_info(dev,
+		 "ATTACH: size: %llu.%u(%llu KB).\n",
+		 mtd_info->size,
+		 (unsigned int)info->flash_size,
+		 (long long)mtd_info->size >> 10);
+
+	return 0;
+}
+
+static int sam_flash_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct sam_flash *sam_flash;
+	struct resource *res;
+
+	sam_flash = devm_kzalloc(dev, sizeof(*sam_flash), GFP_KERNEL);
+	if (sam_flash == NULL)
+		return -ENOMEM;
+
+	sam_flash->dev = dev;
+	platform_set_drvdata(pdev, sam_flash);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENOMEM;
+
+	sam_flash->membase = devm_ioremap(dev, res->start, resource_size(res));
+	if (!sam_flash->membase)
+		return -ENOMEM;
+
+	mutex_init(&sam_flash->lock);
+
+	return sam_flash_mtd_attach(pdev, sam_flash);
+}
+
+static int sam_flash_remove(struct platform_device *pdev)
+{
+	struct sam_flash *sam_flash = platform_get_drvdata(pdev);
+
+	mtd_device_unregister(&sam_flash->mtd_info);
+
+	return 0;
+}
+
+static const struct of_device_id sam_flash_ids[] = {
+	{ .compatible = "jnx,flash-sam", },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(of, sam_flash_ids);
+
+static struct platform_driver sam_flash_driver = {
+	.driver = {
+		   .name = "flash-sam",
+		   .owner = THIS_MODULE,
+		   .of_match_table = sam_flash_ids,
+		   },
+	.probe = sam_flash_probe,
+	.remove = sam_flash_remove,
+};
+
+static int __init sam_flash_init(void)
+{
+	return platform_driver_register(&sam_flash_driver);
+}
+
+static void __exit sam_flash_exit(void)
+{
+	platform_driver_unregister(&sam_flash_driver);
+}
+
+module_init(sam_flash_init);
+module_exit(sam_flash_exit);
+
+MODULE_DESCRIPTION("SAM-FPGA FLASH Driver");
+MODULE_LICENSE("GPL");
-- 
1.9.1



From krzk at kernel.org  Fri Oct  7 09:28:10 2016
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 7 Oct 2016 19:28:10 +0300
Subject: [PATCH 3/3] mtd: s3c2410: parse the device configuration from OF
 node
In-Reply-To: <1475711217-974-4-git-send-email-sergio.prado@e-labworks.com>
References: <1475711217-974-1-git-send-email-sergio.prado@e-labworks.com>
 <1475711217-974-4-git-send-email-sergio.prado@e-labworks.com>
Message-ID: <20161007162810.GB4222@kozik-lap>

On Wed, Oct 05, 2016 at 08:46:57PM -0300, Sergio Prado wrote:
> Allows configuring Samsung's s3c2410 memory controller using a
> devicetree.
> 
> Signed-off-by: Sergio Prado <sergio.prado at e-labworks.com>
> ---
>  drivers/mtd/nand/s3c2410.c                     | 171 ++++++++++++++++++++++---
>  include/linux/platform_data/mtd-nand-s3c2410.h |   1 +
>  2 files changed, 156 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
> index 174ac9dc4265..352cf2656bc8 100644
> --- a/drivers/mtd/nand/s3c2410.c
> +++ b/drivers/mtd/nand/s3c2410.c
> @@ -39,6 +39,8 @@
>  #include <linux/slab.h>
>  #include <linux/clk.h>
>  #include <linux/cpufreq.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
>  
>  #include <linux/mtd/mtd.h>
>  #include <linux/mtd/nand.h>
> @@ -185,6 +187,26 @@ struct s3c2410_nand_info {
>  #endif
>  };
>  
> +struct s3c24XX_nand_devtype_data {
> +	enum s3c_cpu_type type;
> +};
> +
> +struct s3c24XX_nand_devtype_data s3c2410_nand_devtype_data = {
> +	.type = TYPE_S3C2410,
> +};
> +
> +struct s3c24XX_nand_devtype_data s3c2412_nand_devtype_data = {
> +	.type = TYPE_S3C2412,
> +};
> +
> +struct s3c24XX_nand_devtype_data s3c2440_nand_devtype_data = {
> +	.type = TYPE_S3C2440,
> +};
> +
> +struct s3c24XX_nand_devtype_data s3c6400_nand_devtype_data = {
> +	.type = TYPE_S3C2412,

All of these look like candidate for static const.

Additionally you are not actually differentiating between s3c2412 and
s3c64xx so I think there is not need of samsung,s3c6400-nand compatible.
Just use existing one.

Best regards,
Krzysztof


From andrew at lunn.ch  Fri Oct  7 14:13:26 2016
From: andrew at lunn.ch (Andrew Lunn)
Date: Fri, 7 Oct 2016 23:13:26 +0200
Subject: [PATCH 09/10] net: phy: Add MDIO driver for Juniper's SAM FPGA
In-Reply-To: <1475853518-22264-10-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
 <1475853518-22264-10-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <20161007211326.GB10197@lunn.ch>

On Fri, Oct 07, 2016 at 06:18:37PM +0300, Pantelis Antoniou wrote:
> From: Georgi Vlaev <gvlaev at juniper.net>
> 
> Add driver for the MDIO IP block present in Juniper's
> SAM FPGA.
> 
> This driver supports only Clause 45 of the 802.3 spec.
> 
> Note that due to the fact that there are no drivers for
> Broadcom/Avago retimers on 10/40Ge path that are controlled
> from the MDIO interface there is a method to have direct
> access to registers via a debugfs interface.

This seems to be the wrong solution. Why not write those drivers?

Controlling stuff from user space is generally frowned up. So i expect
DaveM will NACK this patch. Please remove all the debugfs stuff.

> +static int mdio_sam_stat_wait(struct mii_bus *bus, u32 wait_mask)
> +{
> +	struct mdio_sam_data *data = bus->priv;
> +	unsigned long timeout;
> +	u32 stat;
> +
> +	timeout = jiffies + msecs_to_jiffies(MDIO_RDY_TMO);
> +	do {
> +		stat = ioread32(data->base + MDIO_STATUS);
> +		if (stat & wait_mask)
> +			return 0;
> +
> +		usleep_range(50, 100);
> +	} while (time_before(jiffies, timeout));
> +
> +	return -EBUSY;

I've recently had to fix a loop like this in another
driver. usleep_range(50, 100) can sleep for a lot longer. If it sleeps
for MDIO_RDY_TMO you exit out with -EBUSY after a single iteration,
which is not what you want. It is better to make a fixed number of
iterations rather than a timeout.

> +}
> +
> +static int mdio_sam_read(struct mii_bus *bus, int phy_id, int regnum)
> +{
> +	struct mdio_sam_data *data = bus->priv;
> +	u32 command, res;
> +	int ret;
> +
> +	/* mdiobus_read holds the bus->mdio_lock mutex */
> +
> +	if (!(regnum & MII_ADDR_C45))
> +		return -ENXIO;
> +
> +	ret = mdio_sam_stat_wait(bus, STAT_REG_RDY);
> +	if (ret < 0)
> +		return ret;
> +
> +	command = regnum & 0x1fffff; /* regnum = (dev_id << 16) | reg */
> +	command |= ((phy_id & 0x1f) << 21);
> +
> +	iowrite32(command, data->base + MDIO_CMD1);
> +	ioread32(data->base + MDIO_CMD1);


> +	iowrite32(CMD2_READ | CMD2_ENABLE, data->base + MDIO_CMD2);
> +	ioread32(data->base + MDIO_CMD2);

Why do you need to read the values back? Hardware bug?

> +	iowrite32(TBL_CMD_REG_GO, data->base + MDIO_TBL_CMD);
> +	ioread32(data->base + MDIO_TBL_CMD);

Although not wrong, most drivers use writel().

> +
> +	usleep_range(50, 100);
> +
> +	ret = mdio_sam_stat_wait(bus, (STAT_REG_DONE | STAT_REG_ERR));

Do you really need a wait before calling mdio_sam_stat_wait()? Isn't
that what it is supposed to do, wait...

> +	if (ret < 0)
> +		return ret;
> +
> +	res = ioread32(data->base + MDIO_RESULT);
> +
> +	if (res & RES_ERROR || !(res & RES_SUCCESS))
> +		return -EIO;
> +
> +	return (res & 0xffff);
> +}
> +
> +static int mdio_sam_write(struct mii_bus *bus, int phy_id, int regnum, u16 val)
> +{
> +	struct mdio_sam_data *data = bus->priv;
> +	u32 command;
> +	int ret;
> +
> +	/* mdiobus_write holds the bus->mdio_lock mutex */
> +
> +	if (!(regnum & MII_ADDR_C45))
> +		return -ENXIO;
> +
> +	ret = mdio_sam_stat_wait(bus, STAT_REG_RDY);
> +	if (ret < 0)
> +		return ret;
> +
> +	command = regnum & 0x1fffff; /* regnum = (dev_id << 16) | reg */
> +	command |= ((phy_id & 0x1f) << 21);
> +
> +	iowrite32(command, data->base + MDIO_CMD1);
> +	ioread32(data->base + MDIO_CMD1);
> +	iowrite32(CMD2_ENABLE | val, data->base + MDIO_CMD2);
> +	ioread32(data->base + MDIO_CMD2);
> +	iowrite32(TBL_CMD_REG_GO, data->base + MDIO_TBL_CMD);
> +	ioread32(data->base + MDIO_TBL_CMD);
> +
> +	usleep_range(50, 100);
> +
> +	ret = mdio_sam_stat_wait(bus, (STAT_REG_DONE | STAT_REG_ERR));
> +	if (ret < 0)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int mdio_sam_reset(struct mii_bus *bus)
> +{
> +	struct mdio_sam_data *data = bus->priv;
> +
> +	iowrite32(TBL_CMD_SOFT_RESET, data->base + MDIO_TBL_CMD);
> +	ioread32(data->base + MDIO_TBL_CMD);
> +	mdelay(10);
> +	iowrite32(0, data->base + MDIO_TBL_CMD);
> +	ioread32(data->base + MDIO_TBL_CMD);
> +
> +	/* zero tables */
> +	memset_io(data->base + MDIO_CMD1, 0, 0x1000);
> +	memset_io(data->base + MDIO_PRI_CMD1, 0, 0x1000);

What tables?

> +
> +	return 0;
> +}
> +
> +static int mdio_sam_of_register_bus(struct platform_device *pdev,
> +				    struct device_node *np, void __iomem *base)
> +{
> +	struct mii_bus *bus;
> +	struct mdio_sam_data *data;
> +	u32 reg;
> +	int ret;
> +
> +	bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*data));
> +	if (!bus)
> +		return -ENOMEM;
> +
> +	/* bus offset */
> +	ret = of_property_read_u32(np, "reg", &reg);
> +	if (ret)
> +		return -ENODEV;
> +
> +	data = bus->priv;
> +	data->base = base + reg;
> +
> +	bus->parent = &pdev->dev;
> +	bus->name = "mdio-sam";
> +	bus->read = mdio_sam_read;
> +	bus->write = mdio_sam_write;
> +	bus->reset = mdio_sam_reset;
> +	snprintf(bus->id, MII_BUS_ID_SIZE, "mdiosam-%x-%x", pdev->id, reg);
> +
> +	ret = of_mdiobus_register(bus, np);
> +	if (ret < 0)
> +		return ret;
> +#ifdef CONFIG_DEBUG_FS
> +	ret = mdio_sam_debugfs_init(bus);
> +	if (ret < 0)
> +		goto err_unregister;
> +#endif
> +	ret = device_create_bin_file(&bus->dev, &bin_attr_raw_io);
> +	if (ret)
> +		goto err_debugfs;
> +
> +	return 0;
> +
> +err_debugfs:
> +#ifdef CONFIG_DEBUG_FS
> +	mdio_sam_debugfs_remove(bus);
> +#endif
> +err_unregister:
> +	mdiobus_unregister(bus);
> +
> +	return ret;
> +}
> +
> +static int mdio_sam_of_unregister_bus(struct device_node *np)
> +{
> +	struct mii_bus *bus;
> +
> +	bus = of_mdio_find_bus(np);
> +	if (bus) {
> +		device_remove_bin_file(&bus->dev, &bin_attr_raw_io);
> +#ifdef CONFIG_DEBUG_FS
> +		mdio_sam_debugfs_remove(bus);
> +#endif
> +		mdiobus_unregister(bus);
> +	}
> +	return 0;
> +}
> +
> +static int mdio_sam_probe(struct platform_device *pdev)
> +{
> +	struct device_node *np;
> +	struct resource *res;
> +	void __iomem *base;
> +	int ret;
> +
> +	if (!pdev->dev.of_node)
> +		return -ENODEV;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	base = devm_ioremap_nocache(&pdev->dev, res->start,
> +				    resource_size(res));

Why nocache?

> +	if (IS_ERR(base))
> +		return PTR_ERR(base);
> +
> +	for_each_available_child_of_node(pdev->dev.of_node, np) {
> +		ret = mdio_sam_of_register_bus(pdev, np, base);
> +		if (ret)
> +			goto err;
> +	}

This is odd. There does not seem to be any shared resources. So you
should really have one MDIO bus as one device in the device tree.



       Andrew

> +
> +	return 0;
> +err:
> +	/* roll back everything */
> +	for_each_available_child_of_node(pdev->dev.of_node, np)
> +		mdio_sam_of_unregister_bus(np);
> +
> +	return ret;
> +}
> +
> +static int mdio_sam_remove(struct platform_device *pdev)
> +{
> +	struct device_node *np;
> +
> +	for_each_available_child_of_node(pdev->dev.of_node, np)
> +		mdio_sam_of_unregister_bus(np);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mdio_sam_of_match[] = {
> +	{ .compatible = "jnx,mdio-sam" },
> +	{  }
> +};
> +MODULE_DEVICE_TABLE(of, mdio_sam_of_match);
> +
> +static struct platform_driver mdio_sam_driver = {
> +	.probe = mdio_sam_probe,
> +	.remove = mdio_sam_remove,
> +	.driver = {
> +		.name = "mdio-sam",
> +		.owner = THIS_MODULE,
> +		.of_match_table = mdio_sam_of_match,
> +	},
> +};
> +
> +module_platform_driver(mdio_sam_driver);
> +
> +MODULE_ALIAS("platform:mdio-sam");
> +MODULE_AUTHOR("Georgi Vlaev <gvlaev at juniper.net>");
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Juniper Networks SAM MDIO bus driver");
> -- 
> 1.9.1
> 


From frowand.list at gmail.com  Fri Oct  7 16:39:56 2016
From: frowand.list at gmail.com (Frank Rowand)
Date: Fri, 7 Oct 2016 16:39:56 -0700
Subject: [PATCH 00/10] Introduce Juniper PTXPMB CPLD driver
In-Reply-To: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <57F8324C.2040804@gmail.com>

On 10/07/16 08:17, Pantelis Antoniou wrote:
> Add Juniper's PTXPMB FPGA CPLD driver. Those FPGAs
> are present in Juniper's PTX series of routers.
> 
> The MFD driver provices watchdog/i2c/gpio/mtd devices.
> 
> There are full device tree binding documents for the
> master mfd driver and for all slave drivers.
> 
> This patchset is against mainline as of today: v4.8-9431-g3477d16
> and is dependent on the "Juniper prerequisites" and
> "Juniper infrastructure" patchsets sent earlier.

Pointers to the patchsets please.

< snip >

-Frank



From frowand.list at gmail.com  Fri Oct  7 19:17:08 2016
From: frowand.list at gmail.com (Frank Rowand)
Date: Fri, 7 Oct 2016 19:17:08 -0700
Subject: [PATCH 00/10] Introduce Juniper PTXPMB CPLD driver
In-Reply-To: <57F8324C.2040804@gmail.com>
References: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
 <57F8324C.2040804@gmail.com>
Message-ID: <57F85724.4000706@gmail.com>

On 10/07/16 16:39, Frank Rowand wrote:
> On 10/07/16 08:17, Pantelis Antoniou wrote:
>> Add Juniper's PTXPMB FPGA CPLD driver. Those FPGAs
>> are present in Juniper's PTX series of routers.
>>
>> The MFD driver provices watchdog/i2c/gpio/mtd devices.
>>
>> There are full device tree binding documents for the
>> master mfd driver and for all slave drivers.
>>
>> This patchset is against mainline as of today: v4.8-9431-g3477d16
>> and is dependent on the "Juniper prerequisites" and
>> "Juniper infrastructure" patchsets sent earlier.
> 
> Pointers to the patchsets please.
> 

Nevermind.  Found them.

-Frank



From computersforpeace at gmail.com  Sat Oct  8 21:00:39 2016
From: computersforpeace at gmail.com (Brian Norris)
Date: Sat, 8 Oct 2016 21:00:39 -0700
Subject: [PATCH v3] mtd: introduce the mtd_pairing_scheme concept
In-Reply-To: <1473951929-416-1-git-send-email-boris.brezillon@free-electrons.com>
References: <1473951929-416-1-git-send-email-boris.brezillon@free-electrons.com>
Message-ID: <20161009040039.GA10199@brian-ubuntu>

On Thu, Sep 15, 2016 at 05:05:29PM +0200, Boris Brezillon wrote:
> MLC and TLC NAND devices are using NAND cells exposing more than one bit,
> but instead of attaching all the bits in a given cell to a single NAND
> page, each bit is usually attached to a different page. This concept is
> called 'page pairing', and has significant impacts on the flash storage
> usage.
> The main problem showed by these devices is that interrupting a page
> program operation may not only corrupt the page we are programming
> but also the page it is paired with, hence the need to expose to MTD
> users the pairing scheme information.
> 
> The pairing APIs allows one to query pairing information attached to a
> given page (here called wunit), or the other way around (the wunit
> pointed by pairing information).
> It also provides several helpers to help the conversion between absolute
> offsets and wunits, and query the number of pairing groups.
> 
> Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
> Reviewed-by: Brian Norris <computersforpeace at gmail.com>
> ---
> Hi Brian,
> 
> Here is a new version addressing your comments.
> If you're okay with this version, you can directly pull the
> 4.9/mtd-pairing-scheme tag [1] into your tree (it's based on 4.8-rc1).

I never found where '[1]' was pointing, but I did pull
4.9/mtd-pairing-scheme from github.com:linux-nand/linux into
linux-mtd.git.

Thanks,
Brian

> Changes since v2:
> - fix documentation
> - make API consistent by returning error codes and adding bounds
>   checking everywhere
> - drop NAND pairing scheme patches (will be resubmitted after
>   this patch has been merged)
> 
> Changes since v1:
> - document the paring scheme concepts and the associate structures and
>   helpers
> - rework the dist3 and dist6 implementation according to George
>   comments
> - introduce the mtd_set_pairing_scheme() helper to avoid directly
>   manipulating the mtd->pairing field
> - drop the patch assigning dist6 pairing scheme to the H27UCG8T2ATR
>   NAND (in the light of George comment I'm not longer sure this scheme
>   is suitable for this NAND, and I can't test it)
> 
>  drivers/mtd/mtdcore.c   | 104 ++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/mtd/mtdpart.c   |   1 +
>  include/linux/mtd/mtd.h | 107 ++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 212 insertions(+)


From computersforpeace at gmail.com  Sat Oct  8 21:47:30 2016
From: computersforpeace at gmail.com (Brian Norris)
Date: Sat, 8 Oct 2016 21:47:30 -0700
Subject: [GIT PULL] MTD updates for 4.9-rc1
Message-ID: <20161009044730.GB10199@brian-ubuntu>

Hi Linus,

I've not been very active this cycle, so these are mostly from Boris,
for the NAND flash subsystem.

The following changes since commit 29b4817d4018df78086157ea3a55c1d9424a7cfc:

  Linux 4.8-rc1 (2016-08-07 18:18:00 -0700)

are available in the git repository at:

  git://git.infradead.org/linux-mtd.git tags/for-linus-20161008

for you to fetch changes up to 69db4aa44fdd8befc2eccd1313d841c5128c385c:

  Merge tag '4.9/mtd-pairing-scheme' of github.com:linux-nand/linux (2016-10-08 20:56:54 -0700)

----------------------------------------------------------------
MTD updates for 4.9-rc1

NAND:

 * Add the infrastructure to automate NAND timings configuration
 * Provide a generic DT property to maximize ECC strength
 * Some refactoring in the core bad block table handling, to help with
   improving some of the logic in error cases.
 * Minor cleanups and fixes

MTD:

 * Add APIs for handling page pairing; this is necessary for reliably
   supporting MLC and TLC NAND flash, where paired-page disturbance affects
   reliability. Upper layers (e.g., UBI) should make use of these in the near
   future.

----------------------------------------------------------------
Andrey Smirnov (4):
      Kconfig: nand: Make MTD_NAND_FSL_ELBC depend on FSL_SOC
      Kconfig: nand: Remove redundant dependency on MTD_NAND
      mtd: nand: Error out if cmd_ctrl() is missing
      mtd: nand: Get rid of needless 'goto'

Boris Brezillon (11):
      mtd: introduce the mtd_pairing_scheme concept
      mtd: nand: timings: Fix tADL_min for ONFI 4.0 chips
      mtd: nand: timings: Reorder tRR_min def in mode 0
      mtd: nand_bbt: Move BBT block selection logic out of write_bbt()
      mtd: nand: automate NAND timings selection
      mtd: nand: Add an option to maximize the ECC strength
      mtd: nand: Support maximizing ECC when using software BCH
      mtd: nand: sunxi: Support ECC maximization
      mtd: nand: Fix nand_command_lp() for 8bits opcodes
      mtd: nand: mxc: Test CONFIG_OF instead of CONFIG_OF_MTD
      mtd: Kill the OF_MTD Kconfig option

Brian Norris (4):
      mtd: nand: sh_flctl: handle dma_submit() errors
      Merge tag 'for-4.9' of github.com:linux-nand/linux
      mtd: nand: fix trivial spelling error
      Merge tag '4.9/mtd-pairing-scheme' of github.com:linux-nand/linux

Han Xu (1):
      mtd: nand: gpmi: get correct free oob space

Harvey Hunt (1):
      MAINTAINERS: Add maintainer entry for Ingenic JZ4780 NAND driver

Karl Beldan (1):
      mtd: nand: davinci: Reinitialize the HW ECC engine in 4bit hwctl

Krzysztof Kozlowski (1):
      mtd: nand: s3c2410: Register cpufreq notifier only on S3C24xx

Kyle Roeschley (1):
      mtd: nand_bbt: scan for next free bbt block if writing bbt fails

Marc Gonzalez (1):
      mtd: nand: import nand_hw_control_init()

Ray Jui (1):
      mtd: brcmnand: iProc big endian and ONFI support

Richard Weinberger (2):
      mtd: nand: Provide nand_cleanup() function to free NAND related resources
      mtdpart: Propagate _get/put_device()

Roger Quadros (2):
      mtd: nand: omap2: Don't call dma_release_channel() if dma_request_chan() failed
      mtd: nand: Allow MTD_NAND_OMAP2 to be usable on Keystone devices

Sascha Hauer (9):
      mtd: nand: remove unnecessary 'extern' from function declarations
      mtd: nand: Create a NAND reset function
      mtd: nand: Introduce nand_data_interface
      mtd: nand: convert ONFI mode into data interface
      mtd: nand: Add function to convert ONFI mode to data_interface
      mtd: nand: Expose data interface for ONFI mode 0
      mtd: nand: sunxi: switch from manual to automated timing config
      mtd: nand: mxc: implement onfi get/set features
      mtd: nand: mxc: Add timing setup for v2 controllers

 Documentation/devicetree/bindings/mtd/nand.txt |   9 +
 MAINTAINERS                                    |   6 +
 drivers/mtd/mtdcore.c                          | 104 ++++++
 drivers/mtd/mtdpart.c                          |  19 +
 drivers/mtd/nand/Kconfig                       |  12 +-
 drivers/mtd/nand/bf5xx_nand.c                  |   3 +-
 drivers/mtd/nand/brcmnand/brcmnand.c           |  15 +-
 drivers/mtd/nand/brcmnand/brcmnand.h           |  13 +-
 drivers/mtd/nand/brcmnand/iproc_nand.c         |  18 +-
 drivers/mtd/nand/davinci_nand.c                |   3 +
 drivers/mtd/nand/docg4.c                       |   3 +-
 drivers/mtd/nand/fsl_elbc_nand.c               |   3 +-
 drivers/mtd/nand/fsl_ifc_nand.c                |   3 +-
 drivers/mtd/nand/gpmi-nand/gpmi-nand.c         |   3 +-
 drivers/mtd/nand/jz4780_nand.c                 |   3 +-
 drivers/mtd/nand/mxc_nand.c                    | 137 ++++++-
 drivers/mtd/nand/nand_base.c                   | 260 ++++++++++++--
 drivers/mtd/nand/nand_bbt.c                    | 161 ++++++---
 drivers/mtd/nand/nand_timings.c                | 470 ++++++++++++++-----------
 drivers/mtd/nand/ndfc.c                        |   3 +-
 drivers/mtd/nand/omap2.c                       |   2 +-
 drivers/mtd/nand/pxa3xx_nand.c                 |   3 +-
 drivers/mtd/nand/qcom_nandc.c                  |   3 +-
 drivers/mtd/nand/s3c2410.c                     |   7 +-
 drivers/mtd/nand/sh_flctl.c                    |   8 +-
 drivers/mtd/nand/sunxi_nand.c                  | 108 +++---
 drivers/mtd/nand/txx9ndfmc.c                   |   3 +-
 drivers/of/Kconfig                             |   4 -
 include/linux/mtd/mtd.h                        | 107 ++++++
 include/linux/mtd/nand.h                       | 234 ++++++++----
 30 files changed, 1267 insertions(+), 460 deletions(-)


From computersforpeace at gmail.com  Sat Oct  8 22:12:48 2016
From: computersforpeace at gmail.com (Brian Norris)
Date: Sat, 8 Oct 2016 22:12:48 -0700
Subject: [PATCH 5/9] mtd: nand: Expose data interface for ONFI mode 0
In-Reply-To: <20160915145625.15e81012@bbrezillon>
References: <1473928373-8680-1-git-send-email-s.hauer@pengutronix.de>
 <1473928373-8680-6-git-send-email-s.hauer@pengutronix.de>
 <20160915145625.15e81012@bbrezillon>
Message-ID: <20161009051248.GC10199@brian-ubuntu>

On Thu, Sep 15, 2016 at 02:56:25PM +0200, Boris Brezillon wrote:
> On Thu, 15 Sep 2016 10:32:49 +0200
> Sascha Hauer <s.hauer at pengutronix.de> wrote:
> 
> > The nand layer will need ONFI mode 0 to use it as timing mode
> > before and right after reset.
> > 
> > Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
> > ---
> >  drivers/mtd/nand/nand_timings.c | 11 +++++++++++
> >  include/linux/mtd/nand.h        |  2 ++
> >  2 files changed, 13 insertions(+)
> > 
> > diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/nand_timings.c
> > index 608d098..9cdbc16 100644
> > --- a/drivers/mtd/nand/nand_timings.c
> > +++ b/drivers/mtd/nand/nand_timings.c
> > @@ -297,3 +297,14 @@ int onfi_init_data_interface(struct nand_chip *chip,
> >  
> >  	return 0;
> >  }
> > +
> > +/**
> > + * nand_get_default_data_interface - [NAND Interface] Retrieve NAND
> > + * data interface for mode 0. This is used as default timing after
> > + * reset.
> > + */
> > +const struct nand_data_interface *nand_get_default_data_interface(void)
> > +{
> > +	return &onfi_sdr_timings[0];
> > +}
> > +EXPORT_SYMBOL(nand_get_default_data_interface);
> 
> You export nand_get_default_data_interface() here, but you don't export
> onfi_init_data_interface().
> None of these functions should be called from NAND controller drivers,
> so they don't need to be exported. ITOH, the prototypes are public
> (defined in nand.h), so nothing prevents a driver from calling these
> functions.

A bit late, but we can still change things for the next cycle of
course...

> I don't know what's the best solution here:
> 1/ Export both nand_get_default_data_interface() and
>    onfi_init_data_interface()

I don't really like this one. We shouldn't export them if we don't want
people to use them in modules. And I'm sure the various compile-test
builders out there would complain eventually if someone did.

> 2/ Do not export them, but keep their prototypes in nand.h with a
>    comment saying that they should not be directly called by NAND
>    controller drivers

Could be OK.

> 3/ Removing the prototypes from nand.h and defining them in nand_base.c
>    (or in a private header).

I like this one. Why not add a drivers/mtd/nand/nand.h that's intended
for the nand.{o,ko} module only?

> Brian, Richard, Sascha, any comments?

Brian


From computersforpeace at gmail.com  Sat Oct  8 22:20:02 2016
From: computersforpeace at gmail.com (Brian Norris)
Date: Sat, 8 Oct 2016 22:20:02 -0700
Subject: [PATCH v2 03/46] mtd: Don't unconditionally unregister reboot
 notifier
In-Reply-To: <f83b7dd1edbee967b352aa3c2dab676bafd63a56.1474450295.git.dwalter@sigma-star.at>
References: <cover.1474450295.git.dwalter@sigma-star.at>
 <f83b7dd1edbee967b352aa3c2dab676bafd63a56.1474450295.git.dwalter@sigma-star.at>
Message-ID: <20161009052002.GD10199@brian-ubuntu>

I realize I didn't comment on the latest copy of this patch, so copying
my questions here:

On Wed, Sep 21, 2016 at 11:45:12AM +0200, Daniel Walter wrote:
> From: Richard Weinberger <richard at nod.at>
> 
> del_mtd_device() is allowed to fail.
> i.e. when the MTD is busy.
> Unregister the reboot notifier only when we're really
> about to delete the MTD.
> 
> Signed-off-by: Richard Weinberger <richard at nod.at>
> ---
>  drivers/mtd/mtdcore.c | 15 ++++++++++-----
>  1 file changed, 10 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
> index e3936b8..36e5fb0 100644
> --- a/drivers/mtd/mtdcore.c
> +++ b/drivers/mtd/mtdcore.c
> @@ -654,17 +654,22 @@ int mtd_device_unregister(struct mtd_info *master)
>  {
>  	int err;
>  
> -	if (master->_reboot)
> -		unregister_reboot_notifier(&master->reboot_notifier);
> -
>  	err = del_mtd_partitions(master);
>  	if (err)
>  		return err;
>  
>  	if (!device_is_registered(&master->dev))
> -		return 0;
> +		goto unregister;
>  
> -	return del_mtd_device(master);
> +	err = del_mtd_device(master);
> +	if (err)
> +		return err;
> +
> +unregister:
> +	if (master->_reboot)
> +		unregister_reboot_notifier(&master->reboot_notifier);

Is there any kind of race issue with unregistering the notifier *after*
we've deleted the device? I had intentionally unregistered first,
because I didn't want any chance of the driver/module and/or data
structures being freed before we call the notifier.

I can't think of any particular issue yet, but I wanted to ask.

Brian

> +	return 0;
>  }
>  EXPORT_SYMBOL_GPL(mtd_device_unregister);
>  
> -- 
> 2.8.3
> 


From computersforpeace at gmail.com  Sat Oct  8 22:34:06 2016
From: computersforpeace at gmail.com (Brian Norris)
Date: Sat, 8 Oct 2016 22:34:06 -0700
Subject: [RFC PATCH 0/7] mtd: nand: Abstract away the NAND interface type
In-Reply-To: <1474539180-5863-1-git-send-email-boris.brezillon@free-electrons.com>
References: <1474539180-5863-1-git-send-email-boris.brezillon@free-electrons.com>
Message-ID: <20161009053406.GE10199@brian-ubuntu>

On Thu, Sep 22, 2016 at 12:12:53PM +0200, Boris Brezillon wrote:
> Hi,
> 
> This series is aiming at providing a generic NAND layer to share code
> between different NAND based devices.
> 
> We currently have 3 different interfaces to interact with NANDs:
> - Raw NANDs
> - OneNANDs
> - SPI NANDs
> 
> Apart from the way these NAND devices are accessed they have a lot
> in common, like the way the memory is organized, or their constraints.
> This is usually a good sign that some work should be done to factorize
> the code.
> 
> This work has been started by Peter who wanted to re-use the BBT
> code for its SPI-NAND driver. But I think we can push it further
> other stuff (the software ECC implementation, or the way offsets are
> converted to block/page number).
> 
> Before I continue in this direction, I'd like to get some feedback
> from Peter and those who reviewed his initial submission (Brian,
> Ezequiel) [1], or anyone who is interested in this topic.

My eyes are bleeding for two reasons:

(1) You haven't used any of git's nice rename detection for your patches
(2) The 'rawnand' naming seems a bit much for me. If we really need to
    reorganize everything, keeping the name shorter, like just 'raw'
    might be fine -- at least wherever we're already namespaces as
    "nand". e.g., 'drivers/mtd/nand/raw/' and 'mtd: nand: raw:
    commit subject', but you might still keep 'rawnand.h' (unless you
    want to move things into an include/linux/mtd/nand/ subdirectory).

You'll also need to update MAINTAINERS for the header pattern.

Haven't looked too closely at the code yet.

Brian


From boris.brezillon at free-electrons.com  Sun Oct  9 04:52:48 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Sun, 9 Oct 2016 13:52:48 +0200
Subject: [RFC PATCH 0/7] mtd: nand: Abstract away the NAND interface type
In-Reply-To: <20161009053406.GE10199@brian-ubuntu>
References: <1474539180-5863-1-git-send-email-boris.brezillon@free-electrons.com>
 <20161009053406.GE10199@brian-ubuntu>
Message-ID: <20161009135248.6a9a9185@bbrezillon>

Hi Brian,

On Sat, 8 Oct 2016 22:34:06 -0700
Brian Norris <computersforpeace at gmail.com> wrote:

> On Thu, Sep 22, 2016 at 12:12:53PM +0200, Boris Brezillon wrote:
> > Hi,
> > 
> > This series is aiming at providing a generic NAND layer to share code
> > between different NAND based devices.
> > 
> > We currently have 3 different interfaces to interact with NANDs:
> > - Raw NANDs
> > - OneNANDs
> > - SPI NANDs
> > 
> > Apart from the way these NAND devices are accessed they have a lot
> > in common, like the way the memory is organized, or their constraints.
> > This is usually a good sign that some work should be done to factorize
> > the code.
> > 
> > This work has been started by Peter who wanted to re-use the BBT
> > code for its SPI-NAND driver. But I think we can push it further
> > other stuff (the software ECC implementation, or the way offsets are
> > converted to block/page number).
> > 
> > Before I continue in this direction, I'd like to get some feedback
> > from Peter and those who reviewed his initial submission (Brian,
> > Ezequiel) [1], or anyone who is interested in this topic.  
> 
> My eyes are bleeding for two reasons:

Sorry for your eyes :-).

> 
> (1) You haven't used any of git's nice rename detection for your patches

Yep, as already answered to Ezequiel on IRC, I forgot to pass -M when
generating patches with git format-patch. Will be addressed in v2.

> (2) The 'rawnand' naming seems a bit much for me. If we really need to
>     reorganize everything, keeping the name shorter, like just 'raw'
>     might be fine -- at least wherever we're already namespaces as
>     "nand". e.g., 'drivers/mtd/nand/raw/' and 'mtd: nand: raw:
>     commit subject', but you might still keep 'rawnand.h' (unless you
>     want to move things into an include/linux/mtd/nand/ subdirectory).

That's also something Ezequiel complained about. I'm perfectly fine
dropping the nand suffix when it's unneeded (will be fixed in v2).

> 
> You'll also need to update MAINTAINERS for the header pattern.

Sure, I'll patch MAINTAINERS to describe the new patterns.

> 
> Haven't looked too closely at the code yet.

Thanks for this preliminary review, but I was actually looking for a
more general review:

- Is the general approach OK (the fact that we now have a generic NAND
  layer to share code between different NAND based devices, no matter
  the interface they use)?
- Is the API defined at the generic NAND level (the interface-agnostic
  API) acceptable?

Thanks,

Boris



From boris.brezillon at free-electrons.com  Sun Oct  9 04:58:21 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Sun, 9 Oct 2016 13:58:21 +0200
Subject: [PATCH 5/9] mtd: nand: Expose data interface for ONFI mode 0
In-Reply-To: <20161009051248.GC10199@brian-ubuntu>
References: <1473928373-8680-1-git-send-email-s.hauer@pengutronix.de>
 <1473928373-8680-6-git-send-email-s.hauer@pengutronix.de>
 <20160915145625.15e81012@bbrezillon>
 <20161009051248.GC10199@brian-ubuntu>
Message-ID: <20161009135821.02ec6636@bbrezillon>

Hi Brian,

On Sat, 8 Oct 2016 22:12:48 -0700
Brian Norris <computersforpeace at gmail.com> wrote:

> On Thu, Sep 15, 2016 at 02:56:25PM +0200, Boris Brezillon wrote:
> > On Thu, 15 Sep 2016 10:32:49 +0200
> > Sascha Hauer <s.hauer at pengutronix.de> wrote:
> >   
> > > The nand layer will need ONFI mode 0 to use it as timing mode
> > > before and right after reset.
> > > 
> > > Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
> > > ---
> > >  drivers/mtd/nand/nand_timings.c | 11 +++++++++++
> > >  include/linux/mtd/nand.h        |  2 ++
> > >  2 files changed, 13 insertions(+)
> > > 
> > > diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/nand_timings.c
> > > index 608d098..9cdbc16 100644
> > > --- a/drivers/mtd/nand/nand_timings.c
> > > +++ b/drivers/mtd/nand/nand_timings.c
> > > @@ -297,3 +297,14 @@ int onfi_init_data_interface(struct nand_chip *chip,
> > >  
> > >  	return 0;
> > >  }
> > > +
> > > +/**
> > > + * nand_get_default_data_interface - [NAND Interface] Retrieve NAND
> > > + * data interface for mode 0. This is used as default timing after
> > > + * reset.
> > > + */
> > > +const struct nand_data_interface *nand_get_default_data_interface(void)
> > > +{
> > > +	return &onfi_sdr_timings[0];
> > > +}
> > > +EXPORT_SYMBOL(nand_get_default_data_interface);  
> > 
> > You export nand_get_default_data_interface() here, but you don't export
> > onfi_init_data_interface().
> > None of these functions should be called from NAND controller drivers,
> > so they don't need to be exported. ITOH, the prototypes are public
> > (defined in nand.h), so nothing prevents a driver from calling these
> > functions.  
> 
> A bit late, but we can still change things for the next cycle of
> course...
> 
> > I don't know what's the best solution here:
> > 1/ Export both nand_get_default_data_interface() and
> >    onfi_init_data_interface()  
> 
> I don't really like this one. We shouldn't export them if we don't want
> people to use them in modules. And I'm sure the various compile-test
> builders out there would complain eventually if someone did.

Yes, I had the feeling it was the wrong choice, but it was also the
less invasive one ;-).

> 
> > 2/ Do not export them, but keep their prototypes in nand.h with a
> >    comment saying that they should not be directly called by NAND
> >    controller drivers  
> 
> Could be OK.

I don't like that one. It just bloats nand.h with things that are not
supposed to be exported to NAND controller drivers, which just adds
more confusion (the NAND framework is already hard to
follow/understand, let's try not to make it worse).

> 
> > 3/ Removing the prototypes from nand.h and defining them in nand_base.c
> >    (or in a private header).  
> 
> I like this one. Why not add a drivers/mtd/nand/nand.h that's intended
> for the nand.{o,ko} module only?

I like this one too. I'll try to come up with something (maybe with a
different name, like core.h, to prevent developers from including this
file in their NAND controller drivers).

Thanks,

Boris



From akurz at blala.de  Sun Oct  9 06:45:27 2016
From: akurz at blala.de (Alexander Kurz)
Date: Sun,  9 Oct 2016 15:45:27 +0200
Subject: [PATCH] drivers mtd: spi-nor: add new variants
Message-ID: <1476020727-17299-1-git-send-email-akurz@blala.de>

Add spi-nor variants found in ebook readers.

Signed-off-by: Alexander Kurz <akurz at blala.de>
---
 drivers/mtd/spi-nor/spi-nor.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index d0fc165..649f54e 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -868,6 +868,8 @@ static const struct flash_info spi_nor_ids[] = {
 	{ "mx25l3205d",  INFO(0xc22016, 0, 64 * 1024,  64, SECT_4K) },
 	{ "mx25l3255e",  INFO(0xc29e16, 0, 64 * 1024,  64, SECT_4K) },
 	{ "mx25l6405d",  INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) },
+	{ "mx25u4035",   INFO(0xc22533, 0, 64 * 1024,   8, SECT_4K) },
+	{ "mx25u8035",   INFO(0xc22534, 0, 64 * 1024,  16, SECT_4K) },
 	{ "mx25u6435f",  INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
 	{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
 	{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
@@ -980,6 +982,9 @@ static const struct flash_info spi_nor_ids[] = {
 	{ "w25x80", INFO(0xef3014, 0, 64 * 1024,  16, SECT_4K) },
 	{ "w25x16", INFO(0xef3015, 0, 64 * 1024,  32, SECT_4K) },
 	{ "w25x32", INFO(0xef3016, 0, 64 * 1024,  64, SECT_4K) },
+	{ "w25q20cl", INFO(0xef4012, 0, 64 * 1024,  4, SECT_4K) },
+	{ "w25q20bw", INFO(0xef5012, 0, 64 * 1024,  4, SECT_4K) },
+	{ "w25q20ew", INFO(0xef6012, 0, 64 * 1024,  4, SECT_4K) },
 	{ "w25q32", INFO(0xef4016, 0, 64 * 1024,  64, SECT_4K) },
 	{
 		"w25q32dw", INFO(0xef6016, 0, 64 * 1024,  64,
-- 
2.1.4



From pascal.eberhard at gmail.com  Sun Oct  9 13:53:02 2016
From: pascal.eberhard at gmail.com (Pascal Eberhard)
Date: Sun,  9 Oct 2016 22:53:02 +0200
Subject: [PATCH] ubifs: implement POSIX Access Control Lists (ACLs)
Message-ID: <1476046382-19185-1-git-send-email-pascal.eberhard@gmail.com>

This patch implements POSIX Access Control Lists (ACLs) in UBIFS.
It uses posix_acl_(access|default)_xattr_handler ACL generic handlers
as xattr handlers are now used in UBIFS.

Signed-off-by: Pascal Eberhard <pascal.eberhard at gmail.com>
---
 fs/ubifs/Kconfig  |  13 +++++
 fs/ubifs/Makefile |   1 +
 fs/ubifs/acl.c    | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/ubifs/dir.c    |  22 +++++++++
 fs/ubifs/file.c   |   9 ++++
 fs/ubifs/super.c  |  15 ++++++
 fs/ubifs/ubifs.h  |  18 +++++++
 fs/ubifs/xattr.c  |  11 +++--
 8 files changed, 229 insertions(+), 3 deletions(-)
 create mode 100644 fs/ubifs/acl.c

diff --git a/fs/ubifs/Kconfig b/fs/ubifs/Kconfig
index 7ff7712..39119e5 100644
--- a/fs/ubifs/Kconfig
+++ b/fs/ubifs/Kconfig
@@ -50,3 +50,16 @@ config UBIFS_ATIME_SUPPORT
 	  strictatime is the "heavy", relatime is "lighter", etc.
 
 	  If unsure, say 'N'
+
+config UBIFS_FS_POSIX_ACL
+	bool "UBIFS POSIX Access Control Lists"
+	depends on UBIFS_FS
+	select FS_POSIX_ACL
+	help
+	  POSIX Access Control Lists (ACLs) support permissions for users and
+	  groups beyond the owner/group/world scheme.
+
+	  To learn more about Access Control Lists, visit the POSIX ACLs for
+	  Linux website <http://acl.bestbits.at/>.
+
+	  If you don't know what Access Control Lists are, say N
diff --git a/fs/ubifs/Makefile b/fs/ubifs/Makefile
index c54a243..af7a83f 100644
--- a/fs/ubifs/Makefile
+++ b/fs/ubifs/Makefile
@@ -5,3 +5,4 @@ ubifs-y += tnc.o master.o scan.o replay.o log.o commit.o gc.o orphan.o
 ubifs-y += budget.o find.o tnc_commit.o compress.o lpt.o lprops.o
 ubifs-y += recovery.o ioctl.o lpt_commit.o tnc_misc.o xattr.o debug.o
 ubifs-y += misc.o
+ubifs-$(CONFIG_UBIFS_FS_POSIX_ACL) += acl.o
\ No newline at end of file
diff --git a/fs/ubifs/acl.c b/fs/ubifs/acl.c
new file mode 100644
index 0000000..a4d4734
--- /dev/null
+++ b/fs/ubifs/acl.c
@@ -0,0 +1,143 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/xattr.h>
+#include <linux/posix_acl_xattr.h>
+
+#include "ubifs.h"
+
+struct posix_acl *ubifs_get_acl(struct inode *inode, int type)
+{
+	int size;
+	const char *name;
+	char *value = NULL;
+	struct posix_acl *acl;
+
+	switch (type) {
+	case ACL_TYPE_ACCESS:
+		name = XATTR_NAME_POSIX_ACL_ACCESS;
+		break;
+	case ACL_TYPE_DEFAULT:
+		name = XATTR_NAME_POSIX_ACL_DEFAULT;
+		break;
+	default:
+		return ERR_PTR(-EINVAL);
+	}
+
+	size = __ubifs_getxattr(inode, name, NULL, 0);
+	if (size > 0) {
+		value = kzalloc(size, GFP_KERNEL);
+		if (!value)
+			return ERR_PTR(-ENOMEM);
+		size = __ubifs_getxattr(inode, name, value, size);
+	}
+	if (size > 0)
+		acl = posix_acl_from_xattr(&init_user_ns, value, size);
+	else if (size == -ERANGE || size == -ENODATA || size == 0)
+		acl = NULL;
+	else
+		acl = ERR_PTR(size);
+
+	kfree(value);
+	if (!IS_ERR(acl))
+		set_cached_acl(inode, type, acl);
+
+	return acl;
+}
+
+int ubifs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+{
+	int ret;
+	int size = 0;
+	const char *name;
+	char *value = NULL;
+	int flags = 0;
+
+	switch (type) {
+	case ACL_TYPE_ACCESS:
+		name = XATTR_NAME_POSIX_ACL_ACCESS;
+		if (acl) {
+			ret = posix_acl_equiv_mode(acl, &inode->i_mode);
+			if (ret < 0)
+				return ret;
+			if (ret == 0)
+				acl = NULL;
+		}
+		ret = 0;
+		break;
+	case ACL_TYPE_DEFAULT:
+		if (!S_ISDIR(inode->i_mode))
+			return acl ? -EINVAL : 0;
+		name = XATTR_NAME_POSIX_ACL_DEFAULT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (acl) {
+		size = posix_acl_xattr_size(acl->a_count);
+		value = kmalloc(size, GFP_KERNEL);
+		if (!value)
+			return -ENOMEM;
+
+		ret = posix_acl_to_xattr(&init_user_ns, acl, value, size);
+		if (ret < 0)
+			goto out;
+	}
+
+	if (size == 0)
+		flags = XATTR_REPLACE;
+	ret = __ubifs_setxattr(inode, name, value, size, flags);
+
+out:
+	kfree(value);
+	if (!ret)
+		set_cached_acl(inode, type, acl);
+
+	return ret;
+}
+
+/*
+ * Initialize the ACLs of a new inode.
+ */
+int ubifs_init_acl(struct inode *dir, struct inode *inode)
+{
+	struct posix_acl *default_acl, *acl;
+	int ret = 0;
+
+	ret = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
+	if (ret)
+		return ret;
+
+	if (default_acl) {
+		inode_lock(inode);
+		ret = ubifs_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
+		inode_unlock(inode);
+		posix_acl_release(default_acl);
+	}
+
+	if (acl) {
+		if (!ret) {
+			inode_lock(inode);
+			ret = ubifs_set_acl(inode, acl, ACL_TYPE_ACCESS);
+			inode_unlock(inode);
+		}
+		posix_acl_release(acl);
+	}
+
+	if (!default_acl && !acl)
+		cache_no_acl(inode);
+	return ret;
+}
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index ccd9128..a2e5609 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -270,6 +270,10 @@ static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
 		goto out_budg;
 	}
 
+	err = ubifs_init_acl(dir, inode);
+	if (err)
+		goto out_inode;
+
 	err = ubifs_init_security(dir, inode, &dentry->d_name);
 	if (err)
 		goto out_inode;
@@ -341,6 +345,10 @@ static int do_tmpfile(struct inode *dir, struct dentry *dentry,
 		ubifs_assert(inode->i_op == &ubifs_file_inode_operations);
 	}
 
+	err = ubifs_init_acl(dir, inode);
+	if (err)
+		goto out_inode;
+
 	err = ubifs_init_security(dir, inode, &dentry->d_name);
 	if (err)
 		goto out_inode;
@@ -821,6 +829,10 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 		goto out_budg;
 	}
 
+	err = ubifs_init_acl(dir, inode);
+	if (err)
+		goto out_inode;
+
 	err = ubifs_init_security(dir, inode, &dentry->d_name);
 	if (err)
 		goto out_inode;
@@ -903,6 +915,10 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
 	ui->data = dev;
 	ui->data_len = devlen;
 
+	err = ubifs_init_acl(dir, inode);
+	if (err)
+		goto out_inode;
+
 	err = ubifs_init_security(dir, inode, &dentry->d_name);
 	if (err)
 		goto out_inode;
@@ -985,6 +1001,10 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
 	ui->data_len = len;
 	inode->i_size = ubifs_inode(inode)->ui_size = len;
 
+	err = ubifs_init_acl(dir, inode);
+	if (err)
+		goto out_inode;
+
 	err = ubifs_init_security(dir, inode, &dentry->d_name);
 	if (err)
 		goto out_inode;
@@ -1395,6 +1415,8 @@ const struct inode_operations ubifs_dir_inode_operations = {
 	.update_time = ubifs_update_time,
 #endif
 	.tmpfile     = ubifs_tmpfile,
+	.get_acl     = ubifs_get_acl,
+	.set_acl     = ubifs_set_acl,
 };
 
 const struct file_operations ubifs_dir_operations = {
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index 4ed270b..17f6098 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -53,6 +53,7 @@
 #include <linux/mount.h>
 #include <linux/slab.h>
 #include <linux/migrate.h>
+#include <linux/posix_acl.h>
 
 static int read_block(struct inode *inode, void *addr, unsigned int block,
 		      struct ubifs_data_node *dn)
@@ -1251,6 +1252,10 @@ static int do_setattr(struct ubifs_info *c, struct inode *inode,
 		ubifs_release_budget(c, &req);
 	if (IS_SYNC(inode))
 		err = inode->i_sb->s_op->write_inode(inode, NULL);
+
+	if (!err && (attr->ia_valid & ATTR_MODE))
+		err = posix_acl_chmod(inode, inode->i_mode);
+
 	return err;
 }
 
@@ -1628,6 +1633,8 @@ const struct inode_operations ubifs_file_inode_operations = {
 #ifdef CONFIG_UBIFS_ATIME_SUPPORT
 	.update_time = ubifs_update_time,
 #endif
+	.get_acl     = ubifs_get_acl,
+	.set_acl     = ubifs_set_acl,
 };
 
 const struct inode_operations ubifs_symlink_inode_operations = {
@@ -1642,6 +1649,8 @@ const struct inode_operations ubifs_symlink_inode_operations = {
 #ifdef CONFIG_UBIFS_ATIME_SUPPORT
 	.update_time = ubifs_update_time,
 #endif
+	.get_acl     = ubifs_get_acl,
+	.set_acl     = ubifs_set_acl,
 };
 
 const struct file_operations ubifs_file_operations = {
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 4ec0510..8239dfd 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -444,6 +444,9 @@ static int ubifs_show_options(struct seq_file *s, struct dentry *root)
 			   ubifs_compr_name(c->mount_opts.compr_type));
 	}
 
+	if (c->vfs_sb->s_flags & MS_POSIXACL)
+		seq_puts(s, ",acl");
+
 	return 0;
 }
 
@@ -929,6 +932,8 @@ enum {
 	Opt_chk_data_crc,
 	Opt_no_chk_data_crc,
 	Opt_override_compr,
+	Opt_acl,
+	Opt_noacl,
 	Opt_err,
 };
 
@@ -940,6 +945,8 @@ static const match_table_t tokens = {
 	{Opt_chk_data_crc, "chk_data_crc"},
 	{Opt_no_chk_data_crc, "no_chk_data_crc"},
 	{Opt_override_compr, "compr=%s"},
+	{Opt_acl, "acl"},
+	{Opt_noacl, "noacl"},
 	{Opt_err, NULL},
 };
 
@@ -1040,6 +1047,14 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options,
 			c->default_compr = c->mount_opts.compr_type;
 			break;
 		}
+#ifdef CONFIG_UBIFS_FS_POSIX_ACL
+		case Opt_acl:
+			c->vfs_sb->s_flags |= MS_POSIXACL;
+			break;
+		case Opt_noacl:
+			c->vfs_sb->s_flags &= ~MS_POSIXACL;
+			break;
+#endif
 		default:
 		{
 			unsigned long flag;
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 096035e..7935449 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -1743,6 +1743,24 @@ extern const struct xattr_handler *ubifs_xattr_handlers[];
 ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size);
 int ubifs_init_security(struct inode *dentry, struct inode *inode,
 			const struct qstr *qstr);
+ssize_t __ubifs_getxattr(struct inode *host, const char *name,
+				void *buf, size_t size);
+int __ubifs_setxattr(struct inode *host, const char *name,
+			    const void *value, size_t size, int flags);
+
+/* acl.c */
+#ifdef CONFIG_UBIFS_FS_POSIX_ACL
+int ubifs_init_acl(struct inode *dir, struct inode *inode);
+int ubifs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
+struct posix_acl *ubifs_get_acl(struct inode *inode, int type);
+#else
+static inline int ubifs_init_acl(struct inode *inode, struct inode *dir)
+{
+	return 0;
+}
+#define ubifs_get_acl NULL
+#define ubifs_set_acl NULL
+#endif
 
 /* super.c */
 struct inode *ubifs_iget(struct super_block *sb, unsigned long inum);
diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c
index 6c2f4d4..0a596a1 100644
--- a/fs/ubifs/xattr.c
+++ b/fs/ubifs/xattr.c
@@ -52,13 +52,14 @@
  * in the VFS inode cache. The xentries are cached in the LNC cache (see
  * tnc.c).
  *
- * ACL support is not implemented.
+ * ACL support is now implemented.
  */
 
 #include "ubifs.h"
 #include <linux/fs.h>
 #include <linux/slab.h>
 #include <linux/xattr.h>
+#include <linux/posix_acl_xattr.h>
 
 /*
  * Limit the number of extended attributes per inode so that the total size
@@ -268,7 +269,7 @@ static struct inode *iget_xattr(struct ubifs_info *c, ino_t inum)
 	return ERR_PTR(-EINVAL);
 }
 
-static int __ubifs_setxattr(struct inode *host, const char *name,
+int __ubifs_setxattr(struct inode *host, const char *name,
 			    const void *value, size_t size, int flags)
 {
 	struct inode *inode;
@@ -328,7 +329,7 @@ out_free:
 	return err;
 }
 
-static ssize_t __ubifs_getxattr(struct inode *host, const char *name,
+ssize_t __ubifs_getxattr(struct inode *host, const char *name,
 				void *buf, size_t size)
 {
 	struct inode *inode;
@@ -619,5 +620,9 @@ const struct xattr_handler *ubifs_xattr_handlers[] = {
 	&ubifs_user_xattr_handler,
 	&ubifs_trusted_xattr_handler,
 	&ubifs_security_xattr_handler,
+#ifdef CONFIG_UBIFS_FS_POSIX_ACL
+	&posix_acl_access_xattr_handler,
+	&posix_acl_default_xattr_handler,
+#endif
 	NULL
 };
-- 
2.7.4



From pascal.eberhard at gmail.com  Sun Oct  9 14:03:02 2016
From: pascal.eberhard at gmail.com (Pascal Eberhard)
Date: Sun, 09 Oct 2016 23:03:02 +0200
Subject: [PATCH] ubifs: implement POSIX Access Control Lists (ACLs)
In-Reply-To: <1476046382-19185-1-git-send-email-pascal.eberhard@gmail.com>
References: <1476046382-19185-1-git-send-email-pascal.eberhard@gmail.com>
Message-ID: <c891c3af247c497863916319233be933@38plumes.fr>

Hi,


On 2016-10-09 22:53, Pascal Eberhard wrote:
> This patch implements POSIX Access Control Lists (ACLs) in UBIFS.

The history of this patch might be of interest:
- I am running UBIFS with ACL for 2 years with kernel 3.2. The goal
   now is to -finally- get in sync with mainline.
   APIs evolved a lot since 3.2, so porting this initial code to
   mainline did not really make sense as 80% of the code is now
   implemented in a generic manner.
- As well, I was pleased to see Sheng Yong patch proposal in 2015 in
   ML archives, but it seems it has not been finalized.

So this work is based on actual btrfs implementation and 'inspired'
from Sheng Yong proposal, related discussions, as well as my 3.2
initial code.

This patch has been tested with:
- LTP fs/acl/tacl_xattr.sh (modified version),
- LTP fs/acls/acl_test01 (modified version),
- an ACL test suite made during initial 3.2 development.


Best regards,

Pascal


From robh at kernel.org  Sun Oct  9 17:55:38 2016
From: robh at kernel.org (Rob Herring)
Date: Sun, 9 Oct 2016 19:55:38 -0500
Subject: [PATCH 1/2] mfd: Add HiSilicon Flash Memory Controller(FMC) driver
In-Reply-To: <1475225971-30152-2-git-send-email-linshunquan1@hisilicon.com>
References: <1475225971-30152-1-git-send-email-linshunquan1@hisilicon.com>
 <1475225971-30152-2-git-send-email-linshunquan1@hisilicon.com>
Message-ID: <20161010005538.GA32227@rob-hp-laptop>

On Fri, Sep 30, 2016 at 04:59:30PM +0800, linshunquan 00354166 wrote:
> From: Shunquan Lin <linshunquan1 at hisilicon.com>
> 
> This patch adds driver support for HiSilicon Flash Memory
> Controller(FMC). HiSilicon FMC is a multi-functions device which
> supports SPI Nor flash controller, SPI nand Flash controller and
> parallel nand flash controller.

I still have unanswered questions from the last version.

> 
> Signed-off-by: Shunquan Lin <linshunquan1 at hisilicon.com>
> ---
>  .../devicetree/bindings/mfd/hisilicon,hisi-fmc.txt |  62 ++++++++++++
>  drivers/mfd/Kconfig                                |  10 ++
>  drivers/mfd/Makefile                               |   1 +
>  drivers/mfd/hisi_fmc.c                             | 109 +++++++++++++++++++++
>  include/linux/mfd/hisi_fmc.h                       |  92 +++++++++++++++++
>  5 files changed, 274 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mfd/hisilicon,hisi-fmc.txt
>  create mode 100644 drivers/mfd/hisi_fmc.c
>  create mode 100644 include/linux/mfd/hisi_fmc.h


From lee.jones at linaro.org  Mon Oct 10 00:14:40 2016
From: lee.jones at linaro.org (Lee Jones)
Date: Mon, 10 Oct 2016 08:14:40 +0100
Subject: [PATCH 1/2] mfd: Add HiSilicon Flash Memory Controller(FMC) driver
In-Reply-To: <1475225971-30152-2-git-send-email-linshunquan1@hisilicon.com>
References: <1475225971-30152-1-git-send-email-linshunquan1@hisilicon.com>
 <1475225971-30152-2-git-send-email-linshunquan1@hisilicon.com>
Message-ID: <20161010071439.GC13133@dell>

On Fri, 30 Sep 2016, linshunquan 00354166 wrote:

> From: Shunquan Lin <linshunquan1 at hisilicon.com>
> 
> This patch adds driver support for HiSilicon Flash Memory
> Controller(FMC). HiSilicon FMC is a multi-functions device which
> supports SPI Nor flash controller, SPI nand Flash controller and
> parallel nand flash controller.

This is not an MFD.  MFDs span multiple subsystems, where as these are
all Memory Technology Devices (MTDs).  Please find a way to support
this in the MTD subsystem.

> Signed-off-by: Shunquan Lin <linshunquan1 at hisilicon.com>
> ---
>  .../devicetree/bindings/mfd/hisilicon,hisi-fmc.txt |  62 ++++++++++++
>  drivers/mfd/Kconfig                                |  10 ++
>  drivers/mfd/Makefile                               |   1 +
>  drivers/mfd/hisi_fmc.c                             | 109 +++++++++++++++++++++
>  include/linux/mfd/hisi_fmc.h                       |  92 +++++++++++++++++
>  5 files changed, 274 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mfd/hisilicon,hisi-fmc.txt
>  create mode 100644 drivers/mfd/hisi_fmc.c
>  create mode 100644 include/linux/mfd/hisi_fmc.h

[...]

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog


From f.fainelli at gmail.com  Mon Oct 10 01:04:08 2016
From: f.fainelli at gmail.com (Florian Fainelli)
Date: Mon, 10 Oct 2016 01:04:08 -0700
Subject: [PATCH v6, 5/8] mtd: m25p80: Let m25p80_read() fallback to spi
 transfer
In-Reply-To: <1472076269-4731-6-git-send-email-kdasu.kdev@gmail.com>
References: <1472076269-4731-1-git-send-email-kdasu.kdev@gmail.com>
 <1472076269-4731-6-git-send-email-kdasu.kdev@gmail.com>
Message-ID: <4b3b3d3e-b3f8-1d5b-65e3-0c37b6a29096@gmail.com>

On 08/24/2016 03:04 PM, Kamal Dasu wrote:
> In m25p80_read() even though spi_flash_read() is supported
> by some drivers, under certain circumstances like unaligned
> buffer, address or address range limitations on certain SoCs
> let it fallback to core spi reads. Such drivers are expected
> to return -EAGAIN so that the m25p80_read() uses standard
> spi transfer.
> 
> Signed-off-by: Kamal Dasu <kdasu.kdev at gmail.com>

MTD folks, any comments on this?

> ---
>  drivers/mtd/devices/m25p80.c | 11 +++++++++--
>  1 file changed, 9 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
> index 9cf7fcd..77c2d2c 100644
> --- a/drivers/mtd/devices/m25p80.c
> +++ b/drivers/mtd/devices/m25p80.c
> @@ -155,9 +155,16 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
>  		msg.data_nbits = m25p80_rx_nbits(nor);
>  
>  		ret = spi_flash_read(spi, &msg);
> -		if (ret < 0)
> +
> +		if (ret >= 0)
> +			return msg.retlen;
> +
> +		/*
> +		 * some spi master drivers might need to fallback to
> +		 * normal spi transfer
> +		 */
> +		if (ret != -EAGAIN)
>  			return ret;
> -		return msg.retlen;
>  	}
>  
>  	spi_message_init(&m);
> 

-- 
Florian


From cyrille.pitchen at atmel.com  Mon Oct 10 01:29:49 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Mon, 10 Oct 2016 10:29:49 +0200
Subject: [PATCH v6, 5/8] mtd: m25p80: Let m25p80_read() fallback to spi
 transfer
In-Reply-To: <4b3b3d3e-b3f8-1d5b-65e3-0c37b6a29096@gmail.com>
References: <1472076269-4731-1-git-send-email-kdasu.kdev@gmail.com>
 <1472076269-4731-6-git-send-email-kdasu.kdev@gmail.com>
 <4b3b3d3e-b3f8-1d5b-65e3-0c37b6a29096@gmail.com>
Message-ID: <8309370e-f99f-ed51-4789-c1d97d9d8191@atmel.com>

Hi all,


Le 10/10/2016 ? 10:04, Florian Fainelli a ?crit :
> On 08/24/2016 03:04 PM, Kamal Dasu wrote:
>> In m25p80_read() even though spi_flash_read() is supported
>> by some drivers, under certain circumstances like unaligned
>> buffer, address or address range limitations on certain SoCs
>> let it fallback to core spi reads. Such drivers are expected
>> to return -EAGAIN so that the m25p80_read() uses standard
>> spi transfer.
>>
>> Signed-off-by: Kamal Dasu <kdasu.kdev at gmail.com>
> 
> MTD folks, any comments on this?
> 
>> ---
>>  drivers/mtd/devices/m25p80.c | 11 +++++++++--
>>  1 file changed, 9 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
>> index 9cf7fcd..77c2d2c 100644
>> --- a/drivers/mtd/devices/m25p80.c
>> +++ b/drivers/mtd/devices/m25p80.c
>> @@ -155,9 +155,16 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
>>  		msg.data_nbits = m25p80_rx_nbits(nor);
>>  
>>  		ret = spi_flash_read(spi, &msg);
>> -		if (ret < 0)
>> +
>> +		if (ret >= 0)
>> +			return msg.retlen;
>> +
>> +		/*
>> +		 * some spi master drivers might need to fallback to
>> +		 * normal spi transfer
>> +		 */
>> +		if (ret != -EAGAIN)
I just wonder whether EINVAL would be a better choice.
>>  			return ret;
>> -		return msg.retlen;
>>  	}
>>  
>>  	spi_message_init(&m);
>>
> 

Best regards,

Cyrille


From f.fainelli at gmail.com  Mon Oct 10 01:50:07 2016
From: f.fainelli at gmail.com (Florian Fainelli)
Date: Mon, 10 Oct 2016 01:50:07 -0700
Subject: [PATCH 10/10] net: mdio-sam: Add device tree documentation for
 SAM MDIO
In-Reply-To: <1475853518-22264-11-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
 <1475853518-22264-11-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <1b764238-1094-dcbc-1176-fdc845781c31@gmail.com>



On 10/07/2016 08:18 AM, Pantelis Antoniou wrote:
> From: Georgi Vlaev <gvlaev at juniper.net>
> 
> Add device tree bindings document for the SAM MDIO block
> present in Juniper's SAM FPGA.
> 
> Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
> [Ported from Juniper kernel]
> Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
> ---
>  Documentation/devicetree/bindings/net/mdio-sam.txt | 48 ++++++++++++++++++++++
>  1 file changed, 48 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/net/mdio-sam.txt
> 
> diff --git a/Documentation/devicetree/bindings/net/mdio-sam.txt b/Documentation/devicetree/bindings/net/mdio-sam.txt
> new file mode 100644
> index 0000000..7d354e0
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/net/mdio-sam.txt
> @@ -0,0 +1,48 @@
> +Juniper SAM FPGA MFD MDIO bus properties.
> +
> +Required properties:
> +- compatible : "jnx,mdio-sam"
> +- reg : The start offset of the MDIO bus range
> +- #address-cells = <1>;
> +- #size-cells = <0>;
> +
> +Optional properties:
> +
> +Required properties for child nodes:
> +- #address-cells = <1>;
> +- #size-cells = <0>;
> +- reg : The MDIO bus offset within the MDIO range.

I would just refer to Documentation/devicetree/bindings/net/phy.txt for
the child node properties.

Other than that:

Reviewed-by: Florian Fainelli <f.fainelli at gmail.com>
-- 
Florian


From robh at kernel.org  Mon Oct 10 06:16:14 2016
From: robh at kernel.org (Rob Herring)
Date: Mon, 10 Oct 2016 08:16:14 -0500
Subject: [PATCH 2/3] dt-bindings: mtd: add DT binding for s3c2410 flash
 controller
In-Reply-To: <1475711217-974-3-git-send-email-sergio.prado@e-labworks.com>
References: <1475711217-974-1-git-send-email-sergio.prado@e-labworks.com>
 <1475711217-974-3-git-send-email-sergio.prado@e-labworks.com>
Message-ID: <20161010131614.GA7855@rob-hp-laptop>

On Wed, Oct 05, 2016 at 08:46:56PM -0300, Sergio Prado wrote:
> Adds the device tree bindings description for Samsung S3C2410 and
> compatible NAND flash controller.
> 
> Signed-off-by: Sergio Prado <sergio.prado at e-labworks.com>
> ---
>  .../devicetree/bindings/mtd/samsung-s3c2410.txt    | 57 ++++++++++++++++++++++
>  1 file changed, 57 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt

Acked-by: Rob Herring <robh at kernel.org>


From peda at axentia.se  Mon Oct 10 07:53:09 2016
From: peda at axentia.se (Peter Rosin)
Date: Mon, 10 Oct 2016 16:53:09 +0200
Subject: [PATCH 10/10] net: mdio-sam: Add device tree documentation for
 SAM MDIO
In-Reply-To: <1475853518-22264-11-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
 <1475853518-22264-11-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <aad9e8eb-2c15-3c83-067a-e76e0bc73e44@axentia.se>

On 2016-10-07 17:18, Pantelis Antoniou wrote:
> From: Georgi Vlaev <gvlaev at juniper.net>
> 
> Add device tree bindings document for the SAM MDIO block
> present in Juniper's SAM FPGA.
> 
> Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
> [Ported from Juniper kernel]
> Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
> ---
>  Documentation/devicetree/bindings/net/mdio-sam.txt | 48 ++++++++++++++++++++++
>  1 file changed, 48 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/net/mdio-sam.txt
> 
> diff --git a/Documentation/devicetree/bindings/net/mdio-sam.txt b/Documentation/devicetree/bindings/net/mdio-sam.txt
> new file mode 100644
> index 0000000..7d354e0
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/net/mdio-sam.txt
> @@ -0,0 +1,48 @@
> +Juniper SAM FPGA MFD MDIO bus properties.
> +
> +Required properties:
> +- compatible : "jnx,mdio-sam"
> +- reg : The start offset of the MDIO bus range
> +- #address-cells = <1>;
> +- #size-cells = <0>;
> +
> +Optional properties:
> +
> +Required properties for child nodes:
> +- #address-cells = <1>;
> +- #size-cells = <0>;
> +- reg : The MDIO bus offset within the MDIO range.
> +
> +
> +Example :
> +
> +	sam at 10 {
> +		compatible = "jnx,sam";
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		mdio-sam at 10 {

This should be mdio-sam at 40000, OR ...

> +			compatible = "jnx,mdio-sam";
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <0x40000>;

... this should be reg = <0x10>. AFAIK.

Cheers,
Peter

> +
> +			mdio0: mdio-sam at 0 {
> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +				reg = <0x0>;
> +			};
> +
> +			mdio1: mdio-sam at 4000 {
> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +				reg = <0x4000>;
> +			};
> +
> +			mdio2: mdio-sam at 8000 {
> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +				reg = <0x8000>;
> +			};
> +		};
> +	};
> 



From robh at kernel.org  Mon Oct 10 10:38:24 2016
From: robh at kernel.org (Rob Herring)
Date: Mon, 10 Oct 2016 12:38:24 -0500
Subject: [PATCH 02/10] mfd: ptxpmb-cpld: Add documentation for PTXPMB CPLD
In-Reply-To: <1475853451-22121-3-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
 <1475853451-22121-3-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <20161010173824.GA3245@rob-hp-laptop>

On Fri, Oct 07, 2016 at 06:17:23PM +0300, Pantelis Antoniou wrote:
> From: Georgi Vlaev <gvlaev at juniper.net>
> 
> Add DT bindings document for the PTXPMB CPLD MFD device.
> 
> Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
> [Ported from Juniper kernel]
> Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
> ---
>  .../devicetree/bindings/mfd/jnx-ptxpmb-cpld.txt    | 76 ++++++++++++++++++++++
>  1 file changed, 76 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mfd/jnx-ptxpmb-cpld.txt
> 
> diff --git a/Documentation/devicetree/bindings/mfd/jnx-ptxpmb-cpld.txt b/Documentation/devicetree/bindings/mfd/jnx-ptxpmb-cpld.txt
> new file mode 100644
> index 0000000..cc3cbb9
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mfd/jnx-ptxpmb-cpld.txt
> @@ -0,0 +1,76 @@
> +* Device tree bindings for Juniper's PTXPMB CPLD FPGA MFD driver
> +
> +The device supports a number I2C muxes, hardware watchdog and a gpio block.
> +Those devices bindings are described in the jnx-i2c-mux-ptxpmb-cpld,
> +jnx-ptxpmb-wdt and jnx-gpio-ptxpmb-cpld documents.
> +
> +Required properties:
> +
> +- compatible:		"jnx,ptxpmb-cpld", "jnx,ngpmb-bcpld". They differ

bcpld? looks like a typo?

> +			in the i2c-mux blocks.
> +
> +- reg:			contains offset/length value for device state control
> +			registers space.
> +
> +Optional properties:
> +
> +- interrupts:		The interrupt line(s) the /IRQ signal(s) for the device is
> +			connected to.
> +
> +- interrupt-parent:	The parent interrupt controller.
> +
> +Example:
> +
> +cpld at 0,0 {

What bus is this on? If just simple-bus, then just '... at 0'

> +	compatible = "jnx,ptxpmb-cpld";
> +	reg = <0x0 0 0x10000>;


From robh at kernel.org  Mon Oct 10 10:41:18 2016
From: robh at kernel.org (Rob Herring)
Date: Mon, 10 Oct 2016 12:41:18 -0500
Subject: [PATCH 04/10] watchdog: ptxpmb-wdt: Add ptxpmb-wdt device tree
 bindings
In-Reply-To: <1475853451-22121-5-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
 <1475853451-22121-5-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <20161010174117.GA16611@rob-hp-laptop>

On Fri, Oct 07, 2016 at 06:17:25PM +0300, Pantelis Antoniou wrote:
> From: Georgi Vlaev <gvlaev at juniper.net>
> 
> Add binding document for the watchdog driver of PTXPMB CPLD.
> 
> Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
> [Ported from Juniper kernel]
> Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
> ---
>  .../devicetree/bindings/watchdog/jnx-ptxpmb-wdt.txt     | 17 +++++++++++++++++
>  1 file changed, 17 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/watchdog/jnx-ptxpmb-wdt.txt
> 
> diff --git a/Documentation/devicetree/bindings/watchdog/jnx-ptxpmb-wdt.txt b/Documentation/devicetree/bindings/watchdog/jnx-ptxpmb-wdt.txt
> new file mode 100644
> index 0000000..34b64f6
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/watchdog/jnx-ptxpmb-wdt.txt
> @@ -0,0 +1,17 @@
> +Juniper's PTXPMB FPGA watchdog driver
> +
> +Required properties:
> +
> +- compatible:	Should be "jnx,ptxpmb-wdt"
> +
> +Optional properties:
> +
> +- reg : Specifies base physical address and size of the registers. It is
> +  optional since the MFD parent driver supplies it, but can be overridden.

What the driver does is irrelevant. It should be required or there's no 
point to have the node. If the parent knows the address, then it knows 
the type of device too and DT is not needed.

> +
> +Example:
> +
> +wdt {

s/wdt/watchdog/

> +	compatible = "jnx,ptxpmb-wdt";
> +	/* no properties defined */
> +};
> -- 
> 1.9.1
> 


From robh at kernel.org  Mon Oct 10 10:45:17 2016
From: robh at kernel.org (Rob Herring)
Date: Mon, 10 Oct 2016 12:45:17 -0500
Subject: [PATCH 06/10] i2c: i2c-mux-ptxpmb-cpld: Add device tree bindings
In-Reply-To: <1475853451-22121-7-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
 <1475853451-22121-7-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <20161010174517.GA18097@rob-hp-laptop>

On Fri, Oct 07, 2016 at 06:17:27PM +0300, Pantelis Antoniou wrote:
> From: Georgi Vlaev <gvlaev at juniper.net>
> 
> Add binding document for the i2c driver of PTXPMB CPLD.
> 
> Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
> [Ported from Juniper kernel]
> Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
> ---
>  .../bindings/i2c/jnx,i2c-mux-ptxpmb-cpld.txt       | 50 ++++++++++++++++++++++
>  1 file changed, 50 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/i2c/jnx,i2c-mux-ptxpmb-cpld.txt
> 
> diff --git a/Documentation/devicetree/bindings/i2c/jnx,i2c-mux-ptxpmb-cpld.txt b/Documentation/devicetree/bindings/i2c/jnx,i2c-mux-ptxpmb-cpld.txt
> new file mode 100644
> index 0000000..3b201f7
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/i2c/jnx,i2c-mux-ptxpmb-cpld.txt
> @@ -0,0 +1,50 @@
> +* Juniper PTXPMB CPLD I2C Mux
> +
> +I2C mux on the PTXPMB CPLD on Juniper series of routers.
> +
> +Required properties:
> +
> +  - compatible: Must contain one of the following.
> +    "jnx,i2c-mux-ptxpmb-cpld", "jnx,i2c-mux-ngpmb-bcpld"
> +  - num-enable: Number of muxes to enable.

No. Use status property.

> +
> +  The following required properties are defined externally:
> +
> +  - Standard I2C mux properties. See i2c-mux.txt in this directory.
> +  - I2C child bus nodes. See i2c-mux.txt in this directory.
> +
> +Optional Properties:
> +
> +  - num-channels: Number of channels. If not present the default is 8.

What's a channel?

> +  - base-bus-num: Base bus number. If not present it is 0.

No. Linuxism and why do you care?

> +  - use-force: Use the force method of the controller.
> +
> +
> +Example:
> +
> +cpld-i2c-mux {

mux {

> +	compatible = "jnx,i2c-mux-ptxpmb-cpld";
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +
> +	i2c-parent = <&i2c1>;
> +
> +	num-enable = <1>;
> +
> +	i2c at 0 {
> +		reg = <0>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		/* PMB devices are accessed through FPC */
> +
> +		temp-sensor at 1a { /* FPC */
> +			compatible = "maxim,max6697";
> +			reg = <0x1a>;
> +			smbus-timeout-disable;
> +			resistance-cancellation;
> +			alert-mask = <0xff>;
> +			over-temperature-mask = <0xff>;
> +		};
> +	};
> +};
> -- 
> 1.9.1
> 


From robh at kernel.org  Mon Oct 10 11:08:31 2016
From: robh at kernel.org (Rob Herring)
Date: Mon, 10 Oct 2016 13:08:31 -0500
Subject: [PATCH 08/10] gpio: ptxpmb-cpld: Document bindings of PTXPMB's
 CPLD GPIO
In-Reply-To: <1475853451-22121-9-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
 <1475853451-22121-9-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <20161010180831.GA20179@rob-hp-laptop>

On Fri, Oct 07, 2016 at 06:17:29PM +0300, Pantelis Antoniou wrote:
> From: Georgi Vlaev <gvlaev at juniper.net>
> 
> Add device tree bindings document for the GPIO driver of
> Juniper's PTXPMB/NGPMB CPLD.
> 
> Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
> [Ported from Juniper kernel]
> Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
> ---
>  .../bindings/gpio/jnx,gpio-ptxpmb-cpld.txt         | 30 ++++++++++++++++++++++
>  1 file changed, 30 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/gpio/jnx,gpio-ptxpmb-cpld.txt
> 
> diff --git a/Documentation/devicetree/bindings/gpio/jnx,gpio-ptxpmb-cpld.txt b/Documentation/devicetree/bindings/gpio/jnx,gpio-ptxpmb-cpld.txt
> new file mode 100644
> index 0000000..1122021
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/gpio/jnx,gpio-ptxpmb-cpld.txt
> @@ -0,0 +1,30 @@
> +Juniper PTXPMB CPLD GPIO block
> +
> +Required properties:
> +
> +- compatible:
> +    Must be "jnx,gpio-ptxpmb-cpld"
> +
> +- #gpio-cells:
> +    Should be <2>.  The first cell is the pin number (within the controller's
> +    pin space), and the second is used for the following flags:
> +	bit[0]: direction (0 = out, 1 = in)
> +	bit[1]: init high
> +	bit[2]: active low

Use and/or add standard flags.

> +
> +- gpio-controller:
> +    Specifies that the node is a GPIO controller.
> +
> +Optional properties:
> +
> +- reg:
> +    Address and length of the register set for the device. Usually supplied by
> +    the parent MFD driver

Make this mandatory.

> +
> +Example:
> +
> +gpio_cpld: cpld_gpio {
> +	compatible = "jnx,gpio-ptxpmb-cpld";
> +	#gpio-cells = <2>;
> +	gpio-controller;
> +};
> -- 
> 1.9.1
> 


From robh at kernel.org  Mon Oct 10 11:18:46 2016
From: robh at kernel.org (Rob Herring)
Date: Mon, 10 Oct 2016 13:18:46 -0500
Subject: [PATCH 10/10] mtd: ngpmb_nvram: Add bindings for Juniper's ngpmb
 NVRAM
In-Reply-To: <1475853451-22121-11-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
 <1475853451-22121-11-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <20161010181846.GA32705@rob-hp-laptop>

On Fri, Oct 07, 2016 at 06:17:31PM +0300, Pantelis Antoniou wrote:
> From: Georgi Vlaev <gvlaev at juniper.net>
> 
> Add device tree binging document for the ngpmb NVRAM device.
> 
> Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
> [Ported from Juniper kernel]
> Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
> ---
>  .../devicetree/bindings/mtd/ngpmb-nvram.txt        | 22 ++++++++++++++++++++++
>  1 file changed, 22 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mtd/ngpmb-nvram.txt
> 
> diff --git a/Documentation/devicetree/bindings/mtd/ngpmb-nvram.txt b/Documentation/devicetree/bindings/mtd/ngpmb-nvram.txt
> new file mode 100644
> index 0000000..297ad0e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mtd/ngpmb-nvram.txt

mtd is really flash. sram/ or nvmem/ are probably better choices.

> @@ -0,0 +1,22 @@
> +Non Volatile RAM device on a Juniper NG PMB FPGA
> +
> +These devices are found in the PTX series of Juniper routers.
> +
> +Required properties:
> +- compatible : must be "jnx,ngpmb-nvram"

Compatible with mmio-sram?

> +
> +Optional properties:
> +- reg : memory address for the RAM, note that this is not
> +required since usually the device is a subdevice of the SAM MFD
> +driver which fills in the register fields.
> +
> +For the rest of the properties, see mtd-physmap.txt.
> +
> +The device tree may optionally contain sub-nodes describing partitions of the
> +address space. See partition.txt for more detail.

sram or nvmem style partitioning is probably more appropriate.

> +
> +Example:
> +
> +ngpmb_nvram {
> +	compatible = "jnx,ngpmb-nvram";
> +};
> -- 
> 1.9.1
> 


From robh at kernel.org  Mon Oct 10 12:47:55 2016
From: robh at kernel.org (Rob Herring)
Date: Mon, 10 Oct 2016 14:47:55 -0500
Subject: [PATCH 02/10] mfd: sam: Add documentation for the SAM FPGA
In-Reply-To: <1475853518-22264-3-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
 <1475853518-22264-3-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <20161010194755.GA16910@rob-hp-laptop>

On Fri, Oct 07, 2016 at 06:18:30PM +0300, Pantelis Antoniou wrote:
> From: Georgi Vlaev <gvlaev at juniper.net>
> 
> Add DT bindings document for the SAM MFD device.
> 
> Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
> [Ported from Juniper kernel]
> Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
> ---
>  Documentation/devicetree/bindings/mfd/jnx-sam.txt | 94 +++++++++++++++++++++++
>  1 file changed, 94 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mfd/jnx-sam.txt
> 
> diff --git a/Documentation/devicetree/bindings/mfd/jnx-sam.txt b/Documentation/devicetree/bindings/mfd/jnx-sam.txt
> new file mode 100644
> index 0000000..b4af7ea
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mfd/jnx-sam.txt
> @@ -0,0 +1,94 @@
> +Device-Tree bindings for Juniper Networks SAM MFD
> +
> +Required properties:
> +
> +- compatible - Must be: "jnx,sam"

Kind of generic. Only 1 FPGA version or some other way to tell the 
version?

> +
> +Optional properties:
> +
> +- pma-coefficients: A set of tupples containing the configuration of the PMA.

What's a PMA? What type of configuration? How many entries?

> +Device                   Description
> +------                   -----------
> +jnx,i2c-sam		: I2C mux driver
> +jnx,gpio-sam		: GPIO block
> +jnx,flash-sam		: MTD Flash
> +jnx,mdio-sam		: MDIO interfaces
> +
> +All these optional nodes are described in their respective binding
> +documents.
> +
> +Example node:
> +
> +pci-0000-10-00.0 {

What are the numbers?

> +	compatible = "jnx,sam";

If this is a PCI device, then it should use PCI compatible string 
syntax.

> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +	pma-coefficients = <4 0x0>;
> +
> +	i2c-sam at 10 {
> +		compatible = "jnx,i2c-sam";
> +		mux-channels = <2>;
> +		master-offset = <0x10000>;
> +	};
> +
> +	gpiogpqam0: gpio-sam at 10 {

gpio at ...

Where does 10 come from?

> +		compatible = "jnx,gpio-sam";
> +		gpio-controller;
> +		#gpio-cells = <2>;
> +		gpio-count = <297>;
> +		interrupt-controller;
> +		/*
> +		* 1st cell: gpio interrupt status bit
> +		* 2nd cell: 1st pin
> +		* 3rd cell: # of pins
> +		*/
> +		gpio-interrupts =
> +			<0 0 12>,   /* phy_int_monitor_en [16] */
> +			<1 235 24>, /* qsfpp_fpga_int_monitor [17] */
> +			<2 259 24>, /* qsfpp_fpga_modprs_monitor [18] */
> +			<3 295 1>,  /* si5345_fpga_monitor [19] */
> +			<4 294 1>;  /* fpc_pic_int_monitor [20] */
> +	};
> +
> +	flash-sam at 10 {
> +		compatible = "jnx,flash-sam";
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +		partition at 0 {
> +		reg = <0x0 0x400000>;
> +			label = "pic0-golden";
> +			read-only;
> +		};
> +		partition at 400000 {
> +			reg = <0x400000 0x400000>;
> +			label = "pic0-user";
> +		};
> +	};
> +
> +	mdio-sam at 10 {
> +		compatible = "jnx,mdio-sam";
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		reg = <0x40000>;
> +
> +		/* mii_bus types */
> +		mdio0: mdio-sam at 0 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <0x0>;
> +		};
> +
> +		mdio1: mdio-sam at 4000 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <0x4000>;
> +		};
> +
> +		mdio2: mdio-sam at 8000 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <0x8000>;
> +		};
> +	};
> +};
> -- 
> 1.9.1
> 


From robh at kernel.org  Mon Oct 10 12:54:58 2016
From: robh at kernel.org (Rob Herring)
Date: Mon, 10 Oct 2016 14:54:58 -0500
Subject: [PATCH 04/10] i2c: i2c-sam: Add device tree bindings
In-Reply-To: <1475853518-22264-5-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
 <1475853518-22264-5-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <20161010195458.GA20134@rob-hp-laptop>

On Fri, Oct 07, 2016 at 06:18:32PM +0300, Pantelis Antoniou wrote:
> From: Georgi Vlaev <gvlaev at juniper.net>
> 
> Add binding document for the i2c driver of SAM FPGA.
> 
> Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
> [Ported from Juniper kernel]
> Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
> ---
>  .../devicetree/bindings/i2c/i2c-sam-mux.txt        | 20 ++++++++++
>  Documentation/devicetree/bindings/i2c/i2c-sam.txt  | 44 ++++++++++++++++++++++
>  2 files changed, 64 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/i2c/i2c-sam-mux.txt
>  create mode 100644 Documentation/devicetree/bindings/i2c/i2c-sam.txt
> 
> diff --git a/Documentation/devicetree/bindings/i2c/i2c-sam-mux.txt b/Documentation/devicetree/bindings/i2c/i2c-sam-mux.txt
> new file mode 100644
> index 0000000..10ddffa
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/i2c/i2c-sam-mux.txt
> @@ -0,0 +1,20 @@
> +Juniper's SAM FPGA I2C accelerator mux
> +
> +The SAM FPGA I2C mux is present only on Juniper SAM FPGA PTX series
> +of routers.
> +
> +The definition of the i2c sam bus is located in the i2c-sam.txt document.
> +
> +Required properties:
> +- compatible: should be "jnx,i2c-sam-mux".
> +- reg: master number and mux number.

This is not how i2c muxes are done.

> +
> +Optional properties:
> +- speed: If present must be either 100000 or 400000. No other values supported.
> +
> +Examples:
> +
> +pe1i2c: i2c-sam-mux at 1,0 {

i2c-mux at ...

> +	compatible = "jnx,i2c-sam-mux";
> +	reg = <1 0>;
> +};
> diff --git a/Documentation/devicetree/bindings/i2c/i2c-sam.txt b/Documentation/devicetree/bindings/i2c/i2c-sam.txt
> new file mode 100644
> index 0000000..4830b48
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/i2c/i2c-sam.txt
> @@ -0,0 +1,44 @@
> +Juniper's SAM FPGA I2C accelerator
> +
> +The SAM FPGA accelerator is used to connect the large number of
> +I2C muxes that are present on Juniper PTX series of routers.
> +While it's an i2c bus, no other devices are located besides
> +i2c-sam-mux devices.
> +
> +The definition of the i2c sam mux is located in the i2c-sam-mux.txt document.
> +
> +Required properties:
> +- compatible: should be "jnx,i2c-sam".
> +- #address-cells: should be 2.
> +- #size-cells: should be 0.
> +- mux-channels: number of mux channels present

What is this needed for?

> +
> +Optional properties:
> +- reg: offset and length of the register set for the device are optional since
> +  typically the register range is provided by the parent SAM MFD device.
> +- master-offset: Offset of where the master register memory starts.
> +  Default value is 0x8000.

Make this required.

> +- reverse-fill: Fill the start entries of transactions in reverse order

Needs a better explanation.

> +- priority-tables: Use the pre-programmed priority tables in the FPGA

What does not present mean?

> +- i2c-options: list of options to be written to the option field in the
> +  FPGA controlling things like SCL push-pull drives, hold-times, etc.

> +- bus-range: start of bus master range and number of masters.

Needs a better explanation.

> +
> +Examples:
> +
> +i2c-sam {
> +	compatible = "jnx,i2c-sam";
> +	mux-channels = <2>;
> +	#size-cells = <0>;
> +	#address-cells = <2>;
> +
> +	/* PE0 */ pe0i2c: i2c-sam-mux at 0,0 {

i2c-mux at ...

> +		compatible = "jnx,i2c-sam-mux";
> +		reg = <0 0>;
> +	};
> +
> +	/* PE1 */ pe1i2c: i2c-sam-mux at 1,0 {
> +		compatible = "jnx,i2c-sam-mux";
> +		reg = <1 0>;
> +	};
> +};
> -- 
> 1.9.1
> 


From robh at kernel.org  Mon Oct 10 13:03:46 2016
From: robh at kernel.org (Rob Herring)
Date: Mon, 10 Oct 2016 15:03:46 -0500
Subject: [PATCH 06/10] gpio: sam: Document bindings of SAM FPGA GPIO block
In-Reply-To: <1475853518-22264-7-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
 <1475853518-22264-7-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <20161010200346.GA24239@rob-hp-laptop>

On Fri, Oct 07, 2016 at 06:18:34PM +0300, Pantelis Antoniou wrote:
> From: Georgi Vlaev <gvlaev at juniper.net>
> 
> Add device tree bindings document for the GPIO driver of
> Juniper's SAM FPGA.
> 
> Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
> [Ported from Juniper kernel]
> Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
> ---
>  .../devicetree/bindings/gpio/jnx,gpio-sam.txt      | 110 +++++++++++++++++++++
>  1 file changed, 110 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/gpio/jnx,gpio-sam.txt
> 
> diff --git a/Documentation/devicetree/bindings/gpio/jnx,gpio-sam.txt b/Documentation/devicetree/bindings/gpio/jnx,gpio-sam.txt
> new file mode 100644
> index 0000000..514c350
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/gpio/jnx,gpio-sam.txt
> @@ -0,0 +1,110 @@
> +Juniper SAM FPGA GPIO block
> +
> +The controller's registers are organized as sets of eight 32-bit
> +registers with each set controlling a bank of up to 32 pins.  A single
> +interrupt is shared for all of the banks handled by the controller.
> +
> +Required properties:
> +
> +- compatible:
> +    Must be "jnx,gpio-sam"
> +
> +- #gpio-cells:
> +    Should be <2>.  The first cell is the pin number (within the controller's
> +    pin space), and the second is used for the following flags:
> +	bit[0]: direction (0 = out, 1 = in)
> +	bit[1]: init high
> +	bit[2]: active low
> +	bit[3]: open drain
> +	bit[4]: open drain

Use and/or add to standard flags.

> +
> +- gpio-controller:
> +    Specifies that the node is a GPIO controller.
> +
> +Optional properties:
> +
> +- reg:
> +    This driver is part of the SAM FPGA MFD driver, so the
> +    address range is supplied by that driver. However you can
> +    override using this property.
> +
> +- gpio-base:
> +    Base of the GPIO pins of this instance. If not present use system allocated.

This probably needs to go.

> +
> +- gpio-count:

ngpios instead.

> +    Number of GPIO pins of this instance. If not present read the number from
> +    the one configured in the FPGA data. Maximum number is 512.
> +
> +- #interrupt-cells:
> +    Should be <2>.  The first cell is the GPIO number, the second should specify
> +    flags.  The following subset of flags is supported:
> +    - bits[16,4:0] trigger type and level flags
> +	bit  0: rising edge interrupt
> +	bit  1: falling edge interrupt
> +	bit  2: active high interrupt
> +	bit  3: active low interrupt
> +	bit  4: enable debounce
> +	bit 16: signal is active low

What does this mean?

> +    See also Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
> +
> +- gpio-interrupts:
> +    A number of triples that define the mapping of interrupt groupsb to a range of
> +    pins. The first cell defines the interrupt group, the second is the start of
> +    the pin range and the third the number of pins in the range.

Needs a vendor prefix.

> +
> +- gpio-exports:
> +    A subnode containing the list of pins that will be exported to user-space.

DT doesn't know about userspace. Drop this.

> +    Each subnode contains:
> +    Required properties:
> +	- pin: The gpio to be exported and the relevant flags.
> +    Optional properties:
> +        - label: The label to use for export; if not supplied use the node name.
> +
> +Example:
> +
> +gpio20: gpio-sam {
> +	compatible = "jnx,gpio-sam";
> +	gpio-controller;
> +	interrupt-controller;
> +	/* 1st cell: gpio pin
> +	 * 2nd cell: flags (bit mask)
> +	 * bit  0: rising edge interrupt
> +	 * bit  1: falling edge interrupt
> +	 * bit  2: active high interrupt
> +	 * bit  3: active low interrupt
> +	 * bit  4: enable debounce
> +	 * bit 16: signal is active low
> +	 */
> +	#interrupt-cells = <2>;
> +	#gpio-cells = <2>;
> +	gpio-count = <340>;
> +	/* 1st cell: gpio interrupt status bit
> +	 * 2nd cell: 1st pin
> +	 * 3rd cell: # of pins
> +	 */
> +	gpio-interrupts =
> +		<0 0 32>,	/* TL / TQ */
> +		<1 32 32>,	/* PIC 1 */
> +		<2 32 32>,	/* PIC 1 spare */
> +		<7 148 32>,	/* PIC 0 */
> +		<8 170 32>,	/* PIC 0 spare */
> +		<16 318 22>;	/* FPC */
> +
> +	gpio-exports {
> +		/*
> +		 * flags:
> +		 * GPIOF_DIR_IN			bit 0=1
> +		 * GPIOF_DIR_OUT		bit 0=0
> +		 * GPIOF_INIT_HIGH		bit 1=1
> +		 *   GPIOF_INIT_HIGH is raw, not translated
> +		 * GPIOF_ACTIVE_LOW		bit 2=1
> +		 * GPIOF_OPEN_DRAIN		bit 3=1
> +		 * GPIOF_OPEN_SOURCE		bit 4=1
> +		 * GPIOF_EXPORT			bit 5=1
> +		 * GPIOF_EXPORT_CHANGEABLE      bit 6=1
> +		 */
> +		tl0-rst {
> +			pin = < 8 0x24 >;
> +		};
> +	};
> +};
> -- 
> 1.9.1
> 


From robh at kernel.org  Mon Oct 10 13:07:04 2016
From: robh at kernel.org (Rob Herring)
Date: Mon, 10 Oct 2016 15:07:04 -0500
Subject: [PATCH 08/10] mtd: flash-sam: Bindings for Juniper's SAM FPGA
 flash
In-Reply-To: <1475853518-22264-9-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
 <1475853518-22264-9-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <20161010200704.GA28870@rob-hp-laptop>

gOn Fri, Oct 07, 2016 at 06:18:36PM +0300, Pantelis Antoniou wrote:
> From: Georgi Vlaev <gvlaev at juniper.net>
> 
> Add binding document for Junipers Flash IP block present
> in the SAM FPGA on PTX series of routers.
> 
> Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
> [Ported from Juniper kernel]
> Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
> ---
>  .../devicetree/bindings/mtd/flash-sam.txt          | 31 ++++++++++++++++++++++
>  1 file changed, 31 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mtd/flash-sam.txt
> 
> diff --git a/Documentation/devicetree/bindings/mtd/flash-sam.txt b/Documentation/devicetree/bindings/mtd/flash-sam.txt
> new file mode 100644
> index 0000000..bdf1d78
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mtd/flash-sam.txt
> @@ -0,0 +1,31 @@
> +Flash device on a Juniper SAM FPGA
> +
> +These flash chips are found in the PTX series of Juniper routers.
> +
> +They are regular CFI compatible (Intel or AMD extended) flash chips with
> +some special write protect/VPP bits that can be controlled by the machine's
> +system controller.

And where's the description of the sys ctrlr?

> +
> +Required properties:
> +- compatible : must be "jnx,flash-sam"
> +
> +Optional properties:
> +- reg : memory address for the flash chip, note that this is not
> +required since usually the device is a subdevice of the SAM MFD
> +driver which fills in the register fields.
> +
> +For the rest of the properties, see mtd-physmap.txt.
> +
> +The device tree may optionally contain sub-nodes describing partitions of the
> +address space. See partition.txt for more detail.
> +
> +Example:
> +
> +flash_sam {
> +	compatible = "jnx,flash-sam";
> +	partition at 0 {

This should have a heirarchy of a controller node, a flash child node, 
partitions child node, and partition child nodes.

> +		reg = <0x0 0x400000>;
> +		label = "pic0-golden";
> +		read-only;
> +	};
> +};
> -- 
> 1.9.1
> 


From robh at kernel.org  Mon Oct 10 13:10:31 2016
From: robh at kernel.org (Rob Herring)
Date: Mon, 10 Oct 2016 15:10:31 -0500
Subject: [PATCH 2/4] mfd: ptxpmb-ext-cpld: Add documentation for PTXPMB
 extended CPLD
In-Reply-To: <1475853574-22339-3-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853574-22339-1-git-send-email-pantelis.antoniou@konsulko.com>
 <1475853574-22339-3-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <20161010201031.GA31318@rob-hp-laptop>

On Fri, Oct 07, 2016 at 06:19:32PM +0300, Pantelis Antoniou wrote:
> From: Georgi Vlaev <gvlaev at juniper.net>
> 
> Add DT bindings document for the PTXPMB extended CPLD device.
> 
> Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
> [Ported from Juniper kernel]
> Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
> ---
>  .../bindings/mfd/jnx-ptxpmb-ext-cpld.txt           | 35 ++++++++++++++++++++++
>  1 file changed, 35 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mfd/jnx-ptxpmb-ext-cpld.txt
> 
> diff --git a/Documentation/devicetree/bindings/mfd/jnx-ptxpmb-ext-cpld.txt b/Documentation/devicetree/bindings/mfd/jnx-ptxpmb-ext-cpld.txt
> new file mode 100644
> index 0000000..098a548a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mfd/jnx-ptxpmb-ext-cpld.txt
> @@ -0,0 +1,35 @@
> +* Device tree bindings for Juniper's PTXPMB Extended CPLD FPGA MFD driver
> +
> +The device supports a gpio block which is described in the
> +jnx-gpio-ptxpmb-ext-cpld document.
> +
> +Required properties:
> +
> +- compatible:		"jnx,ptxpmb-ext-cpld"
> +
> +- reg:			contains offset/length value for device state control
> +			registers space.
> +
> +Optional properties:
> +
> +- interrupts:		The interrupt line(s) the /IRQ signal(s) for the device is
> +			connected to.
> +
> +- interrupt-parent:	The parent interrupt controller.
> +
> +Example:
> +
> +ext-cpld at 1,0 {
> +	compatible = "jnx,ptxpmb-ext-cpld";
> +	reg = <0x1 0 0x1000>;

What's the bus type here? Unit address is probably wrong.

> +	interrupt-parent = <&mpic>;
> +	interrupts = <7 2>, <8 2>;
> +
> +	gpio_ext_cpld: cpld-ext-gpio {
> +		compatible = "jnx,gpio-ptxpmb-ext-cpld";
> +		#gpio-cells = <2>;
> +		#interrupt-cells = <2>;
> +		gpio-controller;
> +		interrupt-controller;
> +	};
> +};
> -- 
> 1.9.1
> 


From robh at kernel.org  Mon Oct 10 13:19:36 2016
From: robh at kernel.org (Rob Herring)
Date: Mon, 10 Oct 2016 15:19:36 -0500
Subject: [PATCH 4/4] gpio: ptxpmb-ext-cpld: Document bindings of PTXPMB
 extended CPLD
In-Reply-To: <1475853574-22339-5-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853574-22339-1-git-send-email-pantelis.antoniou@konsulko.com>
 <1475853574-22339-5-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <20161010201936.GB32418@rob-hp-laptop>

On Fri, Oct 07, 2016 at 06:19:34PM +0300, Pantelis Antoniou wrote:
> From: Georgi Vlaev <gvlaev at juniper.net>
> 
> Add device tree bindings document for the GPIO driver of
> Juniper's PTXPMB extended CPLD.
> 
> Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
> [Ported from Juniper kernel]
> Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
> ---
>  .../bindings/gpio/jnx,gpio-ptxpmb-ext-cpld.txt     | 36 ++++++++++++++++++++++
>  1 file changed, 36 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/gpio/jnx,gpio-ptxpmb-ext-cpld.txt
> 
> diff --git a/Documentation/devicetree/bindings/gpio/jnx,gpio-ptxpmb-ext-cpld.txt b/Documentation/devicetree/bindings/gpio/jnx,gpio-ptxpmb-ext-cpld.txt
> new file mode 100644
> index 0000000..87f01b9
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/gpio/jnx,gpio-ptxpmb-ext-cpld.txt
> @@ -0,0 +1,36 @@
> +Juniper PTXPMB extended CPLD GPIO block
> +
> +Required properties:
> +
> +- compatible:
> +    Must be "jnx,gpio-ptxpmb-ext-cpld"

Generally, '-gpio' would be last.

> +
> +- #gpio-cells:
> +    Should be <2>.  The first cell is the pin number (within the controller's
> +    pin space), and the second is used for the following flags:
> +	bit[0]: direction (0 = out, 1 = in)
> +	bit[1]: init high
> +	bit[2]: active low

Same comment as all the other gpio bindings...

> +
> +- gpio-controller:
> +    Specifies that the node is a GPIO controller.
> +
> +- interrupt-controller:
> +    Specifies that the node is an interrupt controller.
> +
> +Optional properties:
> +
> +- reg:
> +    Address and length of the register set for the device. Usually supplied
> +    by the parent MFD device.

Make it required.

> +
> +
> +Example:
> +
> +gpio_ext_cpld: cpld-ext-gpio {
> +	compatible = "jnx,gpio-ptxpmb-ext-cpld";
> +	#gpio-cells = <2>;
> +	#interrupt-cells = <2>;
> +	gpio-controller;
> +	interrupt-controller;
> +};
> -- 
> 1.9.1
> 


From robh at kernel.org  Mon Oct 10 13:32:12 2016
From: robh at kernel.org (Rob Herring)
Date: Mon, 10 Oct 2016 15:32:12 -0500
Subject: [PATCH 0/7] Introduce PTX1K Boot FPGA driver
In-Reply-To: <1475853724-22557-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853724-22557-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <20161010203212.GA10128@rob-hp-laptop>

On Fri, Oct 07, 2016 at 06:21:57PM +0300, Pantelis Antoniou wrote:
> Add Juniper's PTX1K Boot FPGA driver. Those FPGAs
> are present in Juniper's PTX series of routers.
> 
> The MFD driver provices watchdog/mtd/hwmon devices.
> 
> There are full device tree binding documents for the
> master mfd driver and for the slave driver.
> 
> This patchset is against mainline as of today: v4.8-9431-g3477d16
> and is dependent on the "Juniper prerequisites" and
> "Juniper infrastructure" patchsets sent earlier.

You've exceeded the number of patches I'm willing to review at once for 
one person and I'm tired of making the same comments. So fix anything 
I've already mentioned elsewhere and send this series again.

Rob


From nawafdiab206 at gmail.com  Mon Oct 10 17:58:59 2016
From: nawafdiab206 at gmail.com (Nawaf Diab)
Date: Mon, 10 Oct 2016 17:58:59 -0700
Subject: Proposal
Message-ID: <mailman.51.1476148311.1636.linux-mtd@lists.infradead.org>

Hello Dear, 

I am Nawaf Diab. I sent you a proposal a few days ago and since I did not receive any reply from you, I assume you did not receive it so I am now resending it to you in this email. Please review the proposal included with this message and let me know if you are interested in working with us on this project. if for any reason, you are unable to open the attachment, please let me know so that I can send as a plain text. I await your immediate response.

Regards,

Nawaf.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Proposal.pdf
Type: application/octet-stream
Size: 798712 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20161010/3c4cbcb1/attachment.obj>

From sergio.prado at e-labworks.com  Mon Oct 10 18:31:04 2016
From: sergio.prado at e-labworks.com (Sergio Prado)
Date: Mon, 10 Oct 2016 22:31:04 -0300
Subject: [PATCH 3/3] mtd: s3c2410: parse the device configuration from OF
 node
In-Reply-To: <20161007162810.GB4222@kozik-lap>
References: <1475711217-974-1-git-send-email-sergio.prado@e-labworks.com>
 <1475711217-974-4-git-send-email-sergio.prado@e-labworks.com>
 <20161007162810.GB4222@kozik-lap>
Message-ID: <20161011013104.GA10064@sprado-desktop>

On Fri, Oct 07, 2016 at 07:28:10PM +0300, Krzysztof Kozlowski wrote:

> > +struct s3c24XX_nand_devtype_data {
> > +	enum s3c_cpu_type type;
> > +};
> > +
> > +struct s3c24XX_nand_devtype_data s3c2410_nand_devtype_data = {
> > +	.type = TYPE_S3C2410,
> > +};
> > +
> > +struct s3c24XX_nand_devtype_data s3c2412_nand_devtype_data = {
> > +	.type = TYPE_S3C2412,
> > +};
> > +
> > +struct s3c24XX_nand_devtype_data s3c2440_nand_devtype_data = {
> > +	.type = TYPE_S3C2440,
> > +};
> > +
> > +struct s3c24XX_nand_devtype_data s3c6400_nand_devtype_data = {
> > +	.type = TYPE_S3C2412,
> 
> All of these look like candidate for static const.
> 
> Additionally you are not actually differentiating between s3c2412 and
> s3c64xx so I think there is not need of samsung,s3c6400-nand compatible.
> Just use existing one.
> 
> Best regards,
> Krzysztof

You are right. I'll review and send V2.

Best regards,

Sergio Prado


From yuxiuming at dblab.chungbuk.ac.kr  Mon Oct 10 17:25:39 2016
From: yuxiuming at dblab.chungbuk.ac.kr (Google Incorporation®)
Date: Mon, 10 Oct 2016 17:25:39 -0700
Subject: Notification
Message-ID: <mailman.52.1476158298.1636.linux-mtd@lists.infradead.org>

Dear Google User,

You have been selected as a winner for using Google services. Find attached
email with more details.

Congratulations,

Matt Brittin.
CEO Google UK.

?2016 Google - Terms & Privacy
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Google.jpg
Type: image/jpeg
Size: 761578 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20161010/1001e99c/attachment.jpg>

From peda at axentia.se  Tue Oct 11 00:13:42 2016
From: peda at axentia.se (Peter Rosin)
Date: Tue, 11 Oct 2016 09:13:42 +0200
Subject: [PATCH 04/10] i2c: i2c-sam: Add device tree bindings
In-Reply-To: <20161010195458.GA20134@rob-hp-laptop>
References: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
 <1475853518-22264-5-git-send-email-pantelis.antoniou@konsulko.com>
 <20161010195458.GA20134@rob-hp-laptop>
Message-ID: <1f5afc57-6b12-4096-587f-5a0f4ebee673@axentia.se>

On 2016-10-10 21:54, Rob Herring wrote:
> On Fri, Oct 07, 2016 at 06:18:32PM +0300, Pantelis Antoniou wrote:
>> From: Georgi Vlaev <gvlaev at juniper.net>
>>
>> Add binding document for the i2c driver of SAM FPGA.
>>
>> Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
>> [Ported from Juniper kernel]
>> Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
>> ---
>>  .../devicetree/bindings/i2c/i2c-sam-mux.txt        | 20 ++++++++++
>>  Documentation/devicetree/bindings/i2c/i2c-sam.txt  | 44 ++++++++++++++++++++++
>>  2 files changed, 64 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/i2c/i2c-sam-mux.txt
>>  create mode 100644 Documentation/devicetree/bindings/i2c/i2c-sam.txt
>>
>> diff --git a/Documentation/devicetree/bindings/i2c/i2c-sam-mux.txt b/Documentation/devicetree/bindings/i2c/i2c-sam-mux.txt
>> new file mode 100644
>> index 0000000..10ddffa
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/i2c/i2c-sam-mux.txt
>> @@ -0,0 +1,20 @@
>> +Juniper's SAM FPGA I2C accelerator mux
>> +
>> +The SAM FPGA I2C mux is present only on Juniper SAM FPGA PTX series
>> +of routers.
>> +
>> +The definition of the i2c sam bus is located in the i2c-sam.txt document.
>> +
>> +Required properties:
>> +- compatible: should be "jnx,i2c-sam-mux".
>> +- reg: master number and mux number.
> 
> This is not how i2c muxes are done.
> 
>> +
>> +Optional properties:
>> +- speed: If present must be either 100000 or 400000. No other values supported.
>> +
>> +Examples:
>> +
>> +pe1i2c: i2c-sam-mux at 1,0 {
> 
> i2c-mux at ...
> 
>> +	compatible = "jnx,i2c-sam-mux";
>> +	reg = <1 0>;
>> +};
>> diff --git a/Documentation/devicetree/bindings/i2c/i2c-sam.txt b/Documentation/devicetree/bindings/i2c/i2c-sam.txt
>> new file mode 100644
>> index 0000000..4830b48
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/i2c/i2c-sam.txt
>> @@ -0,0 +1,44 @@
>> +Juniper's SAM FPGA I2C accelerator
>> +
>> +The SAM FPGA accelerator is used to connect the large number of
>> +I2C muxes that are present on Juniper PTX series of routers.
>> +While it's an i2c bus, no other devices are located besides
>> +i2c-sam-mux devices.
>> +
>> +The definition of the i2c sam mux is located in the i2c-sam-mux.txt document.
>> +
>> +Required properties:
>> +- compatible: should be "jnx,i2c-sam".
>> +- #address-cells: should be 2.
>> +- #size-cells: should be 0.
>> +- mux-channels: number of mux channels present
> 
> What is this needed for?
> 
>> +
>> +Optional properties:
>> +- reg: offset and length of the register set for the device are optional since
>> +  typically the register range is provided by the parent SAM MFD device.
>> +- master-offset: Offset of where the master register memory starts.
>> +  Default value is 0x8000.
> 
> Make this required.
> 
>> +- reverse-fill: Fill the start entries of transactions in reverse order
> 
> Needs a better explanation.
> 
>> +- priority-tables: Use the pre-programmed priority tables in the FPGA
> 
> What does not present mean?
> 
>> +- i2c-options: list of options to be written to the option field in the
>> +  FPGA controlling things like SCL push-pull drives, hold-times, etc.
> 
>> +- bus-range: start of bus master range and number of masters.
> 
> Needs a better explanation.
> 
>> +
>> +Examples:
>> +
>> +i2c-sam {
>> +	compatible = "jnx,i2c-sam";
>> +	mux-channels = <2>;
>> +	#size-cells = <0>;
>> +	#address-cells = <2>;
>> +
>> +	/* PE0 */ pe0i2c: i2c-sam-mux at 0,0 {
> 
> i2c-mux at ...

Hmm, I actually think i2c at ... is the usual naming for i2c-mux children.

Cheers,
Peter

>> +		compatible = "jnx,i2c-sam-mux";
>> +		reg = <0 0>;
>> +	};
>> +
>> +	/* PE1 */ pe1i2c: i2c-sam-mux at 1,0 {
>> +		compatible = "jnx,i2c-sam-mux";
>> +		reg = <1 0>;
>> +	};
>> +};
>> -- 
>> 1.9.1
>>



From peda at axentia.se  Tue Oct 11 00:36:55 2016
From: peda at axentia.se (Peter Rosin)
Date: Tue, 11 Oct 2016 09:36:55 +0200
Subject: [PATCH 06/10] i2c: i2c-mux-ptxpmb-cpld: Add device tree bindings
In-Reply-To: <20161010174517.GA18097@rob-hp-laptop>
References: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
 <1475853451-22121-7-git-send-email-pantelis.antoniou@konsulko.com>
 <20161010174517.GA18097@rob-hp-laptop>
Message-ID: <8a2c459d-0ead-86f1-8633-eb483fe33281@axentia.se>

On 2016-10-10 19:45, Rob Herring wrote:
> On Fri, Oct 07, 2016 at 06:17:27PM +0300, Pantelis Antoniou wrote:
>> From: Georgi Vlaev <gvlaev at juniper.net>
>>
>> Add binding document for the i2c driver of PTXPMB CPLD.
>>
>> Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
>> [Ported from Juniper kernel]
>> Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
>> ---
>>  .../bindings/i2c/jnx,i2c-mux-ptxpmb-cpld.txt       | 50 ++++++++++++++++++++++
>>  1 file changed, 50 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/i2c/jnx,i2c-mux-ptxpmb-cpld.txt
>>
>> diff --git a/Documentation/devicetree/bindings/i2c/jnx,i2c-mux-ptxpmb-cpld.txt b/Documentation/devicetree/bindings/i2c/jnx,i2c-mux-ptxpmb-cpld.txt
>> new file mode 100644
>> index 0000000..3b201f7
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/i2c/jnx,i2c-mux-ptxpmb-cpld.txt
>> @@ -0,0 +1,50 @@
>> +* Juniper PTXPMB CPLD I2C Mux
>> +
>> +I2C mux on the PTXPMB CPLD on Juniper series of routers.
>> +
>> +Required properties:
>> +
>> +  - compatible: Must contain one of the following.
>> +    "jnx,i2c-mux-ptxpmb-cpld", "jnx,i2c-mux-ngpmb-bcpld"
>> +  - num-enable: Number of muxes to enable.
> 
> No. Use status property.

Reading the code, I understand this mux to be like a combination of
i2c switches (like pca9548) where the slave i2c busses can be
enabled individually using an "enable" bitmask in one register, and
"regular" i2c muxes (like pca9547) where you can only select one
slave i2c bus at a time using an enumeration.

num-enable would be the number of switches and num-channels would be
the number of muxes per switch channel. Or the other way around? This
is a real problem. The bindings are too tightly coupled to the way
Linux currently handles i2c switches (i.e. not very well, you can only
select one slave bus on an i2c switch, thus reducing the more
flexible switch hardware to a regular mux). The bindings should not
describe what the driver does, they should describe the hardware.

Basically, you need to describe the i2c topology of the hardware in
the bindings, because I'm just guessing all this, and I shouldn't
have to.

Cheers,
Peter

>> +
>> +  The following required properties are defined externally:
>> +
>> +  - Standard I2C mux properties. See i2c-mux.txt in this directory.
>> +  - I2C child bus nodes. See i2c-mux.txt in this directory.
>> +
>> +Optional Properties:
>> +
>> +  - num-channels: Number of channels. If not present the default is 8.
> 
> What's a channel?
> 
>> +  - base-bus-num: Base bus number. If not present it is 0.
> 
> No. Linuxism and why do you care?
> 
>> +  - use-force: Use the force method of the controller.
>> +
>> +
>> +Example:
>> +
>> +cpld-i2c-mux {
> 
> mux {
> 
>> +	compatible = "jnx,i2c-mux-ptxpmb-cpld";
>> +	#address-cells = <1>;
>> +	#size-cells = <0>;
>> +
>> +	i2c-parent = <&i2c1>;
>> +
>> +	num-enable = <1>;
>> +
>> +	i2c at 0 {
>> +		reg = <0>;
>> +		#address-cells = <1>;
>> +		#size-cells = <0>;
>> +
>> +		/* PMB devices are accessed through FPC */
>> +
>> +		temp-sensor at 1a { /* FPC */
>> +			compatible = "maxim,max6697";
>> +			reg = <0x1a>;
>> +			smbus-timeout-disable;
>> +			resistance-cancellation;
>> +			alert-mask = <0xff>;
>> +			over-temperature-mask = <0xff>;
>> +		};
>> +	};
>> +};
>> -- 
>> 1.9.1
>>



From Danesh.Daroui at ascom.com  Tue Oct 11 04:11:26 2016
From: Danesh.Daroui at ascom.com (Danesh Daroui)
Date: Tue, 11 Oct 2016 11:11:26 +0000
Subject: Failure on MTD sub-page test
Message-ID: <39BC08CB3FF4C84CB6397533D4FC7909015DDE3F@SEGOTEXCH02.ascom-Resource.ads>

Hello,

We are using UBIFS which is shipped with the Kernel 2.6.39.4 on a NAND Flash memory. When I run "mtd_debug info /dev/mtd0" following info are shown:

mtd.type = MTD_NANDFLASH
mtd.flags = MTD_CAP_NANDFLASH
mtd.size = 1073741824 (1G)
mtd.erasesize = 524288 (512K)
mtd.writesize = 4096 (4K)
mtd.oobsize = 128
regions = 0

Now the problem is that when I run mtd tests, only read and NAND ECC tests are passed. Then all other tests fail on exactly page 21. For instance this is the output when I run page test:

=================================================
mtd_subpagetest: MTD device: 0
mtd_subpagetest: MTD device size 1073741824, eraseblock size 524288, page size 4096, subpage size 1024, count of eraseblocks 2048, pages per eraseblock 128, OOB size 128
mtd_subpagetest: scanning for bad eraseblocks
mtd_subpagetest: scanned 2048 eraseblocks, 0 are bad
mtd_subpagetest: erasing whole device
mtd_subpagetest: erased 2048 eraseblocks
mtd_subpagetest: writing whole device
mtd_subpagetest: written up to eraseblock 0
mtd_subpagetest: written up to eraseblock 256
mtd_subpagetest: written up to eraseblock 512
mtd_subpagetest: written up to eraseblock 768
mtd_subpagetest: written up to eraseblock 1024
mtd_subpagetest: written up to eraseblock 1280
mtd_subpagetest: written up to eraseblock 1536
mtd_subpagetest: written up to eraseblock 1792
mtd_subpagetest: written 2048 eraseblocks
mtd_subpagetest: verifying all eraseblocks
mtd_subpagetest: verified up to eraseblock 0
mtd_subpagetest: verified up to eraseblock 256
mtd_subpagetest: verified up to eraseblock 512
mtd_subpagetest: verified up to eraseblock 768
mtd_subpagetest: verified up to eraseblock 1024
mtd_subpagetest: verified up to eraseblock 1280
mtd_subpagetest: verified up to eraseblock 1536
mtd_subpagetest: verified up to eraseblock 1792
mtd_subpagetest: verified 2048 eraseblocks
mtd_subpagetest: erasing whole device
mtd_subpagetest: erased 2048 eraseblocks
mtd_subpagetest: verifying all eraseblocks for 0xff
mtd_subpagetest: verified up to eraseblock 0
mtd_subpagetest: verified up to eraseblock 256
mtd_subpagetest: verified up to eraseblock 512
mtd_subpagetest: verified up to eraseblock 768
mtd_subpagetest: verified up to eraseblock 1024
mtd_subpagetest: verified up to eraseblock 1280
mtd_subpagetest: verified up to eraseblock 1536
mtd_subpagetest: verified up to eraseblock 1792
UBIFS error (pid 4243): ubifs_read_node: bad node type (255 but expected 1)
UBIFS error (pid 4243): ubifs_read_node: bad node at LEB 30:98088, LEB mapping status 1
UBIFS error (pid 4243): do_readpage: cannot read page 21 of inode 791, error -22


Signal 7 (BUS) caught by ps (procps version 3.2.8).
Please send bug reports to <feedback at lists.sf.net> or <albert at users.sf.net>
UBIFS error (pid 4245): ubifs_read_node: bad node type (255 but expected 9)
UBIFS error (pid 4245): ubifs_read_node: bad node at LEB 12:458808, LEB mapping status 1
UBIFS error (pid 4245): ubifs_iget: failed to read inode 1470, error -22
UBIFS error (pid 4245): ubifs_lookup: dead directory entry 'free', error -22
UBIFS error (pid 4246): ubifs_read_node: bad node type (255 but expected 9)
UBIFS error (pid 4246): ubifs_read_node: bad node at LEB 12:458808, LEB mapping status 1
UBIFS error (pid 4246): ubifs_iget: failed to read inode 1470, error -22
UBIFS error (pid 4246): ubifs_lookup: dead directory entry 'free', error -22
sh: free: Invalid argument
mtd_subpagetest: verified 2048 eraseblocks
mtd_subpagetest: writing whole device
mtd_subpagetest: written up to eraseblock 0
mtd_subpagetest: written up to eraseblock 256
mtd_subpagetest: written up to eraseblock 512
mtd_subpagetest: written up to eraseblock 768
mtd_subpagetest: written up to eraseblock 1024
mtd_subpagetest: written up to eraseblock 1280
mtd_subpagetest: written up to eraseblock 1536
mtd_subpagetest: written up to eraseblock 1792
mtd_subpagetest: written 2048 eraseblocks
mtd_subpagetest: verifying all eraseblocks
mtd_subpagetest: verified up to eraseblock 0
mtd_subpagetest: ECC correction at 0x300400
mtd_subpagetest: ECC correction at 0x3d80400
mtd_subpagetest: verified up to eraseblock 256
mtd_subpagetest: verified up to eraseblock 512
mtd_subpagetest: ECC correction at 0x13500000
mtd_subpagetest: verified up to eraseblock 768
mtd_subpagetest: verified up to eraseblock 1024
mtd_subpagetest: verified up to eraseblock 1280
mtd_subpagetest: verified up to eraseblock 1536
mtd_subpagetest: verified up to eraseblock 1792
mtd_subpagetest: ECC correction at 0x3ba00400
mtd_subpagetest: verified 2048 eraseblocks
mtd_subpagetest: erasing whole device
mtd_subpagetest: erased 2048 eraseblocks
mtd_subpagetest: verifying all eraseblocks for 0xff
mtd_subpagetest: verified up to eraseblock 0
mtd_subpagetest: verified up to eraseblock 256
mtd_subpagetest: verified up to eraseblock 512
mtd_subpagetest: verified up to eraseblock 768
UBIFS error (pid 4572): ubifs_read_node: bad node type (255 but expected 1)
UBIFS error (pid 4572): ubifs_read_node: bad node at LEB 30:98088, LEB mapping status 1
UBIFS error (pid 4572): do_readpage: cannot read page 21 of inode 791, error -22


Signal 7 (BUS) caught by ps (procps version 3.2.8).
Please send bug reports to <feedback at lists.sf.net> or <albert at users.sf.net>
UBIFS error (pid 4576): ubifs_read_node: bad node type (255 but expected 9)
UBIFS error (pid 4576): ubifs_read_node: bad node at LEB 12:458808, LEB mapping status 1
UBIFS error (pid 4576): ubifs_iget: failed to read inode 1470, error -22
UBIFS error (pid 4576): ubifs_lookup: dead directory entry 'free', error -22
UBIFS error (pid 4581): ubifs_read_node: bad node type (255 but expected 9)
UBIFS error (pid 4581): ubifs_read_node: bad node at LEB 12:458808, LEB mapping status 1
UBIFS error (pid 4581): ubifs_iget: failed to read inode 1470, error -22
UBIFS error (pid 4581): ubifs_lookup: dead directory entry 'free', error -22
sh: free: Invalid argument

mtd_subpagetest: verified up to eraseblock 1024
mtd_subpagetest: verified up to eraseblock 1280
mtd_subpagetest: verified up to eraseblock 1536
mtd_subpagetest: verified up to eraseblock 1792
mtd_subpagetest: verified 2048 eraseblocks
mtd_subpagetest: finished with 0 errors
=================================================

Despite 0 errors reported at the end of the test, UBIFS error has happened at least twice during the test exactly at page 21. This even worse when I run page test where the test is interrupted with device boot in the middle of the test which prevents the test to be done, as the log shows:

=================================================
mtd_pagetest: MTD device: 0
mtd_pagetest: MTD device size 1073741824, eraseblock size 524288, page size 4096, count of eraseblocks 2048, pages per eraseblock 128, OOB size 128
mtd_pagetest: scanning for bad eraseblocks
mtd_pagetest: scanned 2048 eraseblocks, 0 are bad
mtd_pagetest: erasing whole device
mtd_pagetest: erased 2048 eraseblocks
mtd_pagetest: writing whole device
mtd_pagetest: written up to eraseblock 0
mtd_pagetest: written up to eraseblock 256
mtd_pagetest: written up to eraseblock 512
UBIFS error (pid 2404): ubifs_read_node: bad node type (255 but expected 1)
UBIFS error (pid 2404): ubifs_read_node: bad node at LEB 30:98088, LEB mapping status 1
UBIFS error (pid 2404): do_readpage: cannot read page 21 of inode 791, error -22
UBIFS error (pid 2404): ubifs_read_node: bad node type (255 but expected 1)
UBIFS error (pid 2404): ubifs_read_node: bad node at LEB 30:98088, LEB mapping status 1
UBIFS error (pid 2404): do_readpage: cannot read page 21 of inode 791, error -22


Signal 7 (BUS) caught by ps (procps version 3.2.8).
Please send bug reports to <feedback at lists.sf.net> or <albert at users.sf.net>
UBIFS error (pid 2406): ubifs_read_node: bad node type (255 but expected 9)
UBIFS error (pid 2406): ubifs_read_node: bad node at LEB 12:463712, LEB mapping status 1
UBIFS error (pid 2406): ubifs_iget: failed to read inode 1470, error -22
UBIFS error (pid 2406): ubifs_lookup: dead directory entry 'free', error -22
UBIFS warning (pid 2406): ubifs_ro_mode: switched to read-only mode, error -22
UBIFS error (pid 2407): ubifs_read_node: bad node type (255 but expected 9)
UBIFS error (pid 2407): ubifs_read_node: bad node at LEB 12:463712, LEB mapping status 1
UBIFS error (pid 2407): ubifs_iget: failed to read inode 1470, error -22
UBIFS error (pid 2407): ubifs_lookup: dead directory entry 'free', error -22
sh: free: Invalid argument
mtd_pagetest: written up to eraseblock 768
mtd_pagetest: written up to eraseblock 1024
mtd_pagetest: written up to eraseblock 1280
mtd_pagetest: written up to eraseblock 1536
mtd_pagetest: written up to eraseblock 1792
mtd_pagetest: written 2048 eraseblocks
mtd_pagetest: verifying all eraseblocks
mtd_pagetest: verified up to eraseblock 0
RomBOOT

Since we are using a quite old and outdated kernel version i.e. 2.6.39.4, I am wondering whether a kernel update would fix this problem or not. Because kernel update is a quite big task due to incompatibilities that might happen, then we would prefer to know if the source of the problem is detectable and if there is any patch that we can use to pass all the tests with the current kernel or if we can use the latest version of UIFS without updating the kernel.

Sincerely,

Danesh Daroui



From richard at nod.at  Tue Oct 11 08:33:36 2016
From: richard at nod.at (Richard Weinberger)
Date: Tue, 11 Oct 2016 17:33:36 +0200
Subject: [GIT PULL] UBI/UBIFS updates for 4.9-rc1
Message-ID: <3aa0f87a-ae67-5701-3fa7-4e91f0ea24ea@nod.at>

Linus,

The following changes since commit 3be7988674ab33565700a37b210f502563d932e6:

  Linux 4.8-rc7 (2016-09-18 17:27:41 -0700)

are available in the git repository at:

  git://git.infradead.org/linux-ubifs.git tags/upstream-4.9-rc1

for you to fetch changes up to ec037dfcc064f5f81982c78e95bab783568ae35f:

  UBIFS: improve function-level documentation (2016-10-02 22:55:02 +0200)

Please note that there is a small merge conflict with the vfs tree.
http://marc.info/?l=linux-kernel&m=147605883013879&w=2

----------------------------------------------------------------
This pull request contains:
* Fixes for both UBI and UBIFS
* overlayfs support (O_TMPFILE, RENAME_WHITEOUT/EXCHANGE)
* Code refactoring for the upcoming MLC support

----------------------------------------------------------------
Boris Brezillon (18):
      UBI: fastmap: use ubi_find_volume() instead of open coding it
      UBI: fix add_fastmap() to use the vid_hdr passed in argument
      UBI: fastmap: avoid multiple be32_to_cpu() when unneccesary
      UBI: fastmap: scrub PEB when bitflips are detected in a free PEB EC header
      UBI: use vol->usable_leb_size instead of (ubi->leb_size - vol->data_pad)
      UBI: factorize code used to manipulate volumes at attach time
      UBI: factorize destroy_av() and ubi_remove_av() code
      UBI: fastmap: use ubi_rb_for_each_entry() in unmap_peb()
      UBI: fastmap: use ubi_io_{read, write}_data() instead of ubi_io_{read, write}()
      UBI: provide helpers to allocate and free aeb elements
      UBI: move the global ech and vidh variables into struct ubi_attach_info
      UBI: simplify recover_peb() code
      UBI: simplify LEB write and atomic LEB change code
      UBI: add an helper to check lnum validity
      UBI: provide an helper to check whether a LEB is mapped or not
      UBI: provide an helper to query LEB information
      UBI: hide EBA internals
      UBI: introduce the VID buffer concept

Julia Lawall (1):
      UBIFS: improve function-level documentation

Pascal Eberhard (1):
      ubifs: fix host xattr_len when changing xattr

Richard Weinberger (7):
      ubi: Deal with interrupted erasures in WL
      ubi: Fix races around ubi_refill_pools()
      ubi: Fix Fastmap's update_vol()
      ubifs: Implement O_TMPFILE
      ubifs: Implement RENAME_WHITEOUT
      ubifs: Implement RENAME_EXCHANGE
      ubifs: Use move variable in ubifs_rename()

 drivers/mtd/ubi/attach.c     | 304 +++++++++++++-------
 drivers/mtd/ubi/build.c      |   2 +-
 drivers/mtd/ubi/cdev.c       |   6 +-
 drivers/mtd/ubi/eba.c        | 649 ++++++++++++++++++++++++++-----------------
 drivers/mtd/ubi/fastmap-wl.c |   6 +-
 drivers/mtd/ubi/fastmap.c    | 203 ++++++--------
 drivers/mtd/ubi/io.c         |  39 +--
 drivers/mtd/ubi/kapi.c       |  16 +-
 drivers/mtd/ubi/ubi.h        | 132 +++++++--
 drivers/mtd/ubi/vmt.c        |  40 ++-
 drivers/mtd/ubi/vtbl.c       |  17 +-
 drivers/mtd/ubi/wl.c         |  60 ++--
 fs/ubifs/dir.c               | 242 ++++++++++++++--
 fs/ubifs/file.c              |   2 +-
 fs/ubifs/gc.c                |   2 +-
 fs/ubifs/journal.c           | 188 ++++++++++++-
 fs/ubifs/lprops.c            |   2 +-
 fs/ubifs/lpt_commit.c        |   4 +-
 fs/ubifs/replay.c            |   2 +-
 fs/ubifs/ubifs.h             |   8 +-
 fs/ubifs/xattr.c             |   6 +-
 21 files changed, 1302 insertions(+), 628 deletions(-)


From torvalds at linux-foundation.org  Tue Oct 11 10:57:34 2016
From: torvalds at linux-foundation.org (Linus Torvalds)
Date: Tue, 11 Oct 2016 10:57:34 -0700
Subject: [GIT PULL] UBI/UBIFS updates for 4.9-rc1
In-Reply-To: <3aa0f87a-ae67-5701-3fa7-4e91f0ea24ea@nod.at>
References: <3aa0f87a-ae67-5701-3fa7-4e91f0ea24ea@nod.at>
Message-ID: <CA+55aFx72t6kqrZ0m-tbXzR4UHaq2zti3ZcTeo9PJQzRGa8Syg@mail.gmail.com>

On Tue, Oct 11, 2016 at 8:33 AM, Richard Weinberger <richard at nod.at> wrote:
>
> This pull request contains:
> * Fixes for both UBI and UBIFS
> * overlayfs support (O_TMPFILE, RENAME_WHITEOUT/EXCHANGE)
> * Code refactoring for the upcoming MLC support

In the meantime, on a VFS level, we got rid of the "rename2" naming,
and now the plain regular rename is the extended version.

There's a few other filesystems using "rename2" as a name for the now
no longer true historical reasons, but I noticed it particularly in
this pull request because I fixed up a trivial conflict around that
area.

You might consider renaming it, or just put the "rename2" logic into
the regular rename function, but whatever. It doesn't really _matter_,
it's just an odd naming artifact.

(I've not pushed out my merge yet, it's still going through the build
tests etc, but I thought I'd mention this detail).

               Linus


From zajec5 at gmail.com  Tue Oct 11 14:48:46 2016
From: zajec5 at gmail.com (=?UTF-8?B?UmFmYcWCIE1pxYJlY2tp?=)
Date: Tue, 11 Oct 2016 23:48:46 +0200
Subject: [PATCH V2 1/2] ubifs: drop softlimit and delta fields from struct
 ubifs_wbuf
In-Reply-To: <20160920083615.31099-1-zajec5@gmail.com>
References: <20160914102151.21722-1-zajec5@gmail.com>
 <20160920083615.31099-1-zajec5@gmail.com>
Message-ID: <CACna6rwMLWZ-MDVJ=j-hwb4CPE2197rORVU7Ozr-LxfsvYAWGQ@mail.gmail.com>

On 20 September 2016 at 10:36, Rafa? Mi?ecki <zajec5 at gmail.com> wrote:
> From: Rafa? Mi?ecki <rafal at milecki.pl>
>
> Values of these fields are set during init and never modified. They are
> used (read) in a single function only. There isn't really any reason to
> keep them in a struct. It only makes struct just a bit bigger without
> any visible gain.
>
> Signed-off-by: Rafa? Mi?ecki <rafal at milecki.pl>
> Reviewed-by: Boris Brezillon <boris.brezillon at free-electrons.com>

Hi Richard, could you pick this small patchset, please?


From info at satechsafety.com  Tue Oct 11 22:01:04 2016
From: info at satechsafety.com (PO)
Date: Wed, 12 Oct 2016 15:01:04 +1000
Subject: Fwd:Check PO
Message-ID: <20161012050039.BC7F0141071@zproxy3.mail3d.it>


Dear

Kindly help to check for me status delivery for attached file.

Material is supposed to be delivered on 4th October but no DO issue.

Thank you.

Best Regards,

Haza Izzrinda
Sales Coordinator
-------------- next part --------------
A non-text attachment was scrubbed...
Name: PO.zip
Type: application/zip
Size: 235547 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20161012/0c6907a9/attachment-0001.zip>

From yegorslists at googlemail.com  Wed Oct 12 01:04:35 2016
From: yegorslists at googlemail.com (yegorslists at googlemail.com)
Date: Wed, 12 Oct 2016 10:04:35 +0200
Subject: [PATCH] ubi: improve spelling
Message-ID: <1476259475-10312-1-git-send-email-yegorslists@googlemail.com>

From: Yegor Yefremov <yegorslists at googlemail.com>

Signed-off-by: Yegor Yefremov <yegorslists at googlemail.com>
---

Patch was made against for-linus-20161008.

 drivers/mtd/ubi/build.c     | 6 +++---
 drivers/mtd/ubi/gluebi.c    | 2 +-
 drivers/mtd/ubi/kapi.c      | 2 +-
 drivers/mtd/ubi/ubi-media.h | 4 ++--
 drivers/mtd/ubi/upd.c       | 2 +-
 drivers/mtd/ubi/vmt.c       | 4 ++--
 drivers/mtd/ubi/vtbl.c      | 2 +-
 drivers/mtd/ubi/wl.c        | 2 +-
 8 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 0680516..7716db3 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -844,13 +844,13 @@ static int autoresize(struct ubi_device *ubi, int vol_id)
  * @vid_hdr_offset: VID header offset
  * @max_beb_per1024: maximum expected number of bad PEB per 1024 PEBs
  *
- * This function attaches MTD device @mtd_dev to UBI and assign @ubi_num number
+ * This function attaches MTD device @mtd_dev to UBI and assigns @ubi_num number
  * to the newly created UBI device, unless @ubi_num is %UBI_DEV_NUM_AUTO, in
  * which case this function finds a vacant device number and assigns it
  * automatically. Returns the new UBI device number in case of success and a
  * negative error code in case of failure.
  *
- * Note, the invocations of this function has to be serialized by the
+ * Note, the invocation of this function has to be serialized by the
  * @ubi_devices_mutex.
  */
 int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
@@ -1073,7 +1073,7 @@ out_free:
  * UBI device is busy and cannot be destroyed, and %-EINVAL if it does not
  * exist.
  *
- * Note, the invocations of this function has to be serialized by the
+ * Note, the invocation of this function has to be serialized by the
  * @ubi_devices_mutex.
  */
 int ubi_detach_mtd_dev(int ubi_num, int anyway)
diff --git a/drivers/mtd/ubi/gluebi.c b/drivers/mtd/ubi/gluebi.c
index 1cb287e..acd2e1c 100644
--- a/drivers/mtd/ubi/gluebi.c
+++ b/drivers/mtd/ubi/gluebi.c
@@ -402,7 +402,7 @@ static int gluebi_remove(struct ubi_volume_info *vi)
  * @vi: volume info structure
  *
  * This function is called every time an UBI volume is updated. It does nothing
- * if te volume @vol is dynamic, and changes MTD device size if the
+ * if the volume @vol is dynamic, and changes MTD device size if the
  * volume is static. This is needed because static volumes cannot be read past
  * data they contain. This function returns zero in case of success and a
  * negative error code in case of error.
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
index a9e2cef..5be0675 100644
--- a/drivers/mtd/ubi/kapi.c
+++ b/drivers/mtd/ubi/kapi.c
@@ -819,7 +819,7 @@ BLOCKING_NOTIFIER_HEAD(ubi_notifiers);
  *                   already existing volumes
  *
  * This function registers a volume notifier, which means that
- * 'nb->notifier_call()' will be invoked when an UBI  volume is created,
+ * 'nb->notifier_call()' will be invoked when an UBI volume is created,
  * removed, re-sized, re-named, or updated. The first argument of the function
  * is the notification type. The second argument is pointer to a
  * &struct ubi_notification object which describes the notification event.
diff --git a/drivers/mtd/ubi/ubi-media.h b/drivers/mtd/ubi/ubi-media.h
index 22ed3f6..319d259 100644
--- a/drivers/mtd/ubi/ubi-media.h
+++ b/drivers/mtd/ubi/ubi-media.h
@@ -81,7 +81,7 @@ enum {
  * exceed certain percent, e.g. 2%. When one creates an UBI image which will be
  * flashed to the end devices in production, he does not know the exact amount
  * of good physical eraseblocks the NAND chip on the device will have, but this
- * number is required to calculate the volume sized and put them to the volume
+ * number is required to calculate the volume size and put them to the volume
  * table of the UBI image. In this case, one of the volumes (e.g., the one
  * which will store the root file system) is marked as "auto-resizable", and
  * UBI will adjust its size on the first boot if needed.
@@ -141,7 +141,7 @@ enum {
  * is changed radically. This field is duplicated in the volume identifier
  * header.
  *
- * The @vid_hdr_offset and @data_offset fields contain the offset of the the
+ * The @vid_hdr_offset and @data_offset fields contain the offset of the
  * volume identifier header and user data, relative to the beginning of the
  * physical eraseblock. These values have to be the same for all physical
  * eraseblocks.
diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c
index 0134ba3..717b905 100644
--- a/drivers/mtd/ubi/upd.c
+++ b/drivers/mtd/ubi/upd.c
@@ -270,7 +270,7 @@ static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
  * @count: how much bytes to write
  *
  * This function writes more data to the volume which is being updated. It may
- * be called arbitrary number of times until all the update data arriveis. This
+ * be called arbitrary number of times until all the update data arrives. This
  * function returns %0 in case of success, number of bytes written during the
  * last call if the whole volume update has been successfully finished, and a
  * negative error code in case of failure.
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c
index 0138f52..dd63c8f 100644
--- a/drivers/mtd/ubi/vmt.c
+++ b/drivers/mtd/ubi/vmt.c
@@ -653,7 +653,7 @@ void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol)
  * @ubi: UBI device description object
  * @vol_id: volume ID
  *
- * Returns zero if volume is all right and a a negative error code if not.
+ * Returns zero if volume is all right and a negative error code if not.
  */
 static int self_check_volume(struct ubi_device *ubi, int vol_id)
 {
@@ -801,7 +801,7 @@ fail:
  * self_check_volumes - check information about all volumes.
  * @ubi: UBI device description object
  *
- * Returns zero if volumes are all right and a a negative error code if not.
+ * Returns zero if volumes are all right and a negative error code if not.
  */
 static int self_check_volumes(struct ubi_device *ubi)
 {
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c
index d85c197..17164b8 100644
--- a/drivers/mtd/ubi/vtbl.c
+++ b/drivers/mtd/ubi/vtbl.c
@@ -70,7 +70,7 @@ static void self_vtbl_check(const struct ubi_device *ubi);
 static struct ubi_vtbl_record empty_vtbl_record;
 
 /**
- * ubi_update_layout_vol - helper for updatting layout volumes on flash
+ * ubi_update_layout_vol - helper for updating layout volumes on flash
  * @ubi: UBI device description object
  */
 static int ubi_update_layout_vol(struct ubi_device *ubi)
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index f453326..e4da7a8 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -977,7 +977,7 @@ static int ensure_wear_leveling(struct ubi_device *ubi, int nested)
 		goto out_unlock;
 
 	/*
-	 * If the ubi->scrub tree is not empty, scrubbing is needed, and the
+	 * If the ubi->scrub tree is not empty, scrubbing is needed, and
 	 * the WL worker has to be scheduled anyway.
 	 */
 	if (!ubi->scrub.rb_node) {
-- 
2.1.4



From boris.brezillon at free-electrons.com  Wed Oct 12 02:01:05 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Wed, 12 Oct 2016 11:01:05 +0200
Subject: [PATCH 3/3] mtd: s3c2410: parse the device configuration from
 OF node
In-Reply-To: <1475711217-974-4-git-send-email-sergio.prado@e-labworks.com>
References: <1475711217-974-1-git-send-email-sergio.prado@e-labworks.com>
 <1475711217-974-4-git-send-email-sergio.prado@e-labworks.com>
Message-ID: <20161012110105.49830f86@bbrezillon>

Hi Sergio,

On Wed,  5 Oct 2016 20:46:57 -0300
Sergio Prado <sergio.prado at e-labworks.com> wrote:

> Allows configuring Samsung's s3c2410 memory controller using a
> devicetree.
> 
> Signed-off-by: Sergio Prado <sergio.prado at e-labworks.com>
> ---
>  drivers/mtd/nand/s3c2410.c                     | 171 ++++++++++++++++++++++---
>  include/linux/platform_data/mtd-nand-s3c2410.h |   1 +
>  2 files changed, 156 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
> index 174ac9dc4265..352cf2656bc8 100644
> --- a/drivers/mtd/nand/s3c2410.c
> +++ b/drivers/mtd/nand/s3c2410.c

[...]

> +
> +static int s3c2410_nand_init_timings(struct s3c2410_nand_info *info,
> +				     struct nand_chip *chip)
> +{
> +	struct s3c2410_platform_nand *pdata = info->platform;
> +	const struct nand_sdr_timings *t;
> +	int tacls, mode;
> +
> +	mode = onfi_get_async_timing_mode(chip);
> +	if (mode == ONFI_TIMING_MODE_UNKNOWN)
> +		mode = chip->onfi_timing_mode_default;
> +
> +	t = onfi_async_timing_mode_to_sdr_timings(mode);
> +	if (IS_ERR(t))
> +		return PTR_ERR(t);

We recently introduced an method to automate timing selection and
configuration [1]. Can you switch to this approach (the changes are in
the nand/next branch [2] and should appear in 4.9-rc1)?

Thanks,

Boris

[1]https://www.spinics.net/lists/arm-kernel/msg532007.html 
[2]https://github.com/linux-nand/linux/tree/nand/next


From mtownsend1973 at gmail.com  Wed Oct 12 06:07:59 2016
From: mtownsend1973 at gmail.com (Martin Townsend)
Date: Wed, 12 Oct 2016 14:07:59 +0100
Subject: UBIFS assert when rebooting a read only ubifs when it's been
 remounted r/w
In-Reply-To: <CABatt_zSUbwETQwD5-yJmzH8JvbdLfBXK9V3XnMZw6HmZ2+=7w@mail.gmail.com>
References: <CABatt_xjhTpaUitXP_az+cOFEVA=eUedayFggrrH=Z7ZdBWUYg@mail.gmail.com>
 <CAFLxGvx9bnh6z1hkMXzdvynBOdDca6HJziEKG5pH95e+Ttaa8Q@mail.gmail.com>
 <CABatt_wMSQd7Tc=gP0rO53UghqjdaTonFFj4R_qu8zFJyfyz3A@mail.gmail.com>
 <573C4033.6010906@nod.at>
 <CABatt_wF4Vb0R=xiQapY4Q1ieBJ7Sjcvg3XXsE6QxWrACwchgw@mail.gmail.com>
 <573EC17D.40809@nod.at>
 <CABatt_wQfDFN4U5SgOLrcxWNiZYVRQ4eGy1LQmdRJJN-qncUHw@mail.gmail.com>
 <CABatt_zj+0Vr9PjM64VMYk-Gx+UGW-Xo6vJFNLJ1DsPNm0LPHQ@mail.gmail.com>
 <574360B5.1040505@nod.at>
 <CABatt_xRU57kp1gWwS+gNbSM7_j=ZWAZnQqZ_gjhSGV-+ytMEA@mail.gmail.com>
 <57441937.9070302@nod.at>
 <CABatt_w4qzj9sqn9gQPMYe7c5y9hPCUws5QJNK_q6Kz+mMuMbw@mail.gmail.com>
 <57444876.7090405@nod.at>
 <CABatt_zXcp59i+6AYo=BuSYYQu-cP==r5V5jFOruUcoHeKGrfg@mail.gmail.com>
 <57445A52.3010704@nod.at>
 <CABatt_xe6SEmsSLfSrbC2LNv6WTK=Ltkj8ZqLja+pHXqMqSv-g@mail.gmail.com>
 <57448675.9010904@nod.at>
 <CABatt_zSUbwETQwD5-yJmzH8JvbdLfBXK9V3XnMZw6HmZ2+=7w@mail.gmail.com>
Message-ID: <CABatt_yZvNUDVsE9PNztv+fgaTq-JfV0SRm224Y3Uq+T=k4zPQ@mail.gmail.com>

Hi Richard,

On Wed, May 25, 2016 at 9:04 AM, Martin Townsend
<mtownsend1973 at gmail.com> wrote:
> On Tue, May 24, 2016 at 5:51 PM, Richard Weinberger <richard at nod.at> wrote:
>> Am 24.05.2016 um 16:12 schrieb Martin Townsend:
>>> aaarrgh, sums my day up so far, try this one, I've just tested and at
>>> least it started downloading the file.
>>> http://tempsend.com/32760A445F
>>
>> That worked.
>> Can you please share your NAND id bytes or the flash geometry?
>>
> This should be the part, it's the 4Gbit device.
> https://www.micron.com/parts/nand-flash/mass-storage/mt29f4g08abadawp
> Page size x8: 2112 bytes (2048 + 64 bytes)
> Block size: 64 pages (128K + 4K bytes)
> Plane size: 2 planes x 2048 blocks per plane
> Device size: 4Gb: 4096 blocks
>
> - Martin.
>> Thanks,
>> //richard

I know many months have passed but I'm looking back into the UBIFS
assert that keeps occurring on our board. We have since moved over to
4.1 LTSI kernel and the problem still occurs. Did you manage to
reproduce this assert with the image I sent or has there has been a
patch submitted recently that may fix this, or if not I'm happy to put
some more printk's in to get some more analysis if the image does show
the problem.

The original assert was

[    4.077496] [<c0013550>] (show_stack) from [<c05f4428>]
(dump_stack+0x20/0x28)
[  OK  ] Started Journal Service.
[    4.099269] [<c05f4408>] (dump_stack) from [<c029ba8c>]
(ubifs_remount_fs+0x558/0x800)
[    4.107743] [<c029b534>] (ubifs_remount_fs) from [<c013dd70>]
(do_remount_sb+0x6c/0x1d8)
[    4.121587]  r9:ee112c40 r8:00000000 r7:00000000 r6:00000000
r5:00000000 r4:ee112c00
[    4.129451] [<c013dd04>] (do_remount_sb) from [<c015d1f8>]
(do_mount+0x810/0xcb0)
[    4.151530]  r8:00000021 r7:ee112c00 r6:ee05c850 r5:00000060 r4:00000000
[    4.158342] [<c015c9e8>] (do_mount) from [<c015da1c>] (SyS_mount+0x9c/0xc8)
[    4.181549]  r10:00000000 r9:ee2ba000 r8:c0ed0021 r7:7f5ed788
r6:00000000 r5:ee2d5480
[    4.189471]  r4:ee2d5440
[    4.208415] [<c015d980>] (SyS_mount) from [<c000f8e0>]
(ret_fast_syscall+0x0/0x3c)
[    4.221613]  r8:c000fa84 r7:00000015 r6:7f5ed778 r5:00000000 r4:00000000

Cheers, Martin.


From moritz.fischer at ettus.com  Thu Oct 13 00:38:07 2016
From: moritz.fischer at ettus.com (Moritz Fischer)
Date: Thu, 13 Oct 2016 09:38:07 +0200
Subject: [PATCH] drivers mtd: spi-nor: add new variants
In-Reply-To: <1476020727-17299-1-git-send-email-akurz@blala.de>
References: <1476020727-17299-1-git-send-email-akurz@blala.de>
Message-ID: <CAAtXAHdVxz-uV7EYWnUsBx9JpATBF8Wjf4Sg=-81xR4c3Xu81w@mail.gmail.com>

Hi Alex,

On Sun, Oct 9, 2016 at 3:45 PM, Alexander Kurz <akurz at blala.de> wrote:
> Add spi-nor variants found in ebook readers.

Would be interesting which ones (i.e. can you edit the commit message?

Thanks,

Moritz


From dan.carpenter at oracle.com  Thu Oct 13 01:06:47 2016
From: dan.carpenter at oracle.com (Dan Carpenter)
Date: Thu, 13 Oct 2016 11:06:47 +0300
Subject: [patch 1/2] mtd: spi-nor: Off by one in cqspi_setup_flash()
Message-ID: <20161013080646.GB3389@mwanda>

There are CQSPI_MAX_CHIPSELECT elements in the ->f_pdata array so the >
should be >=.

Fixes: 140623410536 ('mtd: spi-nor: Add driver for Cadence Quad SPI Flash Controller')
Signed-off-by: Dan Carpenter <dan.carpenter at oracle.com>

diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c
index d403ba7..944863b 100644
--- a/drivers/mtd/spi-nor/cadence-quadspi.c
+++ b/drivers/mtd/spi-nor/cadence-quadspi.c
@@ -1082,7 +1082,7 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
 			goto err;
 		}
 
-		if (cs > CQSPI_MAX_CHIPSELECT) {
+		if (cs >= CQSPI_MAX_CHIPSELECT) {
 			dev_err(dev, "Chip select %d out of range.\n", cs);
 			goto err;
 		}


From dan.carpenter at oracle.com  Thu Oct 13 01:30:39 2016
From: dan.carpenter at oracle.com (Dan Carpenter)
Date: Thu, 13 Oct 2016 11:30:39 +0300
Subject: [patch 2/2] mtd: spi-nor: Fix some error codes in cqspi_setup_flash()
Message-ID: <20161013080857.GC3389@mwanda>

We return success or possibly uninitialized values on these error paths
instead of proper error codes.

Fixes: 140623410536 ("mtd: spi-nor: Add driver for Cadence Quad SPI Flash Controller")
Signed-off-by: Dan Carpenter <dan.carpenter at oracle.com>

diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c
index 944863b..d489fbd 100644
--- a/drivers/mtd/spi-nor/cadence-quadspi.c
+++ b/drivers/mtd/spi-nor/cadence-quadspi.c
@@ -1077,12 +1077,14 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
 
 	/* Get flash device data */
 	for_each_available_child_of_node(dev->of_node, np) {
-		if (of_property_read_u32(np, "reg", &cs)) {
+		ret = of_property_read_u32(np, "reg", &cs);
+		if (ret) {
 			dev_err(dev, "Couldn't determine chip select.\n");
 			goto err;
 		}
 
 		if (cs >= CQSPI_MAX_CHIPSELECT) {
+			ret = -EINVAL;
 			dev_err(dev, "Chip select %d out of range.\n", cs);
 			goto err;
 		}


From akurz at blala.de  Thu Oct 13 02:00:06 2016
From: akurz at blala.de (Alexander Kurz)
Date: Thu, 13 Oct 2016 11:00:06 +0200 (CEST)
Subject: [PATCH] drivers mtd: spi-nor: add new variants
In-Reply-To: <CAAtXAHdVxz-uV7EYWnUsBx9JpATBF8Wjf4Sg=-81xR4c3Xu81w@mail.gmail.com>
References: <1476020727-17299-1-git-send-email-akurz@blala.de>
 <CAAtXAHdVxz-uV7EYWnUsBx9JpATBF8Wjf4Sg=-81xR4c3Xu81w@mail.gmail.com>
Message-ID: <alpine.DEB.2.00.1610131059180.15993@blala.de>

>From 27d3d578dacd2b9cb80338517f73decb169e46ec Mon Sep 17 00:00:00 2001
From: Alexander Kurz <akurz at blala.de>
Date: Fri, 7 Oct 2016 17:06:10 +0200
Subject: [PATCH] drivers mtd: spi-nor: add new variants

Macronix MX25U4035 and Winbond 25Q20BW devices are used in 4/5th
generation Kindle ebook readers. Add those spi-nor variants.
Also add similar devices found in the same datasheets.

Signed-off-by: Alexander Kurz <akurz at blala.de>
---
 drivers/mtd/spi-nor/spi-nor.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index d0fc165..649f54e 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -868,6 +868,8 @@ static const struct flash_info spi_nor_ids[] = {
 	{ "mx25l3205d",  INFO(0xc22016, 0, 64 * 1024,  64, SECT_4K) },
 	{ "mx25l3255e",  INFO(0xc29e16, 0, 64 * 1024,  64, SECT_4K) },
 	{ "mx25l6405d",  INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) },
+	{ "mx25u4035",   INFO(0xc22533, 0, 64 * 1024,   8, SECT_4K) },
+	{ "mx25u8035",   INFO(0xc22534, 0, 64 * 1024,  16, SECT_4K) },
 	{ "mx25u6435f",  INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
 	{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
 	{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
@@ -980,6 +982,9 @@ static const struct flash_info spi_nor_ids[] = {
 	{ "w25x80", INFO(0xef3014, 0, 64 * 1024,  16, SECT_4K) },
 	{ "w25x16", INFO(0xef3015, 0, 64 * 1024,  32, SECT_4K) },
 	{ "w25x32", INFO(0xef3016, 0, 64 * 1024,  64, SECT_4K) },
+	{ "w25q20cl", INFO(0xef4012, 0, 64 * 1024,  4, SECT_4K) },
+	{ "w25q20bw", INFO(0xef5012, 0, 64 * 1024,  4, SECT_4K) },
+	{ "w25q20ew", INFO(0xef6012, 0, 64 * 1024,  4, SECT_4K) },
 	{ "w25q32", INFO(0xef4016, 0, 64 * 1024,  64, SECT_4K) },
 	{
 		"w25q32dw", INFO(0xef6016, 0, 64 * 1024,  64,
-- 
2.1.4


From moritz.fischer at ettus.com  Thu Oct 13 02:35:16 2016
From: moritz.fischer at ettus.com (Moritz Fischer)
Date: Thu, 13 Oct 2016 11:35:16 +0200
Subject: [PATCH] drivers mtd: spi-nor: add new variants
In-Reply-To: <alpine.DEB.2.00.1610131059180.15993@blala.de>
References: <1476020727-17299-1-git-send-email-akurz@blala.de>
 <CAAtXAHdVxz-uV7EYWnUsBx9JpATBF8Wjf4Sg=-81xR4c3Xu81w@mail.gmail.com>
 <alpine.DEB.2.00.1610131059180.15993@blala.de>
Message-ID: <CAAtXAHc4MOH_7vRzq6_7hoLkeZmd=U3WHdCqe+kGiY=F2fLSQg@mail.gmail.com>

Hi Alexander,

On Thu, Oct 13, 2016 at 11:00 AM, Alexander Kurz <akurz at blala.de> wrote:
> From 27d3d578dacd2b9cb80338517f73decb169e46ec Mon Sep 17 00:00:00 2001
> From: Alexander Kurz <akurz at blala.de>
> Date: Fri, 7 Oct 2016 17:06:10 +0200
> Subject: [PATCH] drivers mtd: spi-nor: add new variants

if you change the patch you should prefix it with PATCH vX (e.g. 2 in
this case),
since it's your second revision.

If you use git-format to generate your patch you can just append a -v2
to your command
to automatically do this.

This allows for easier tracking which revision of the patch the people
reviewing your
patch are looking at.

Also it's (for more complicated patches mostly) nice to wait a bit
between sending revisions,
to give people time to comment on it.

Thanks,

Moritz


From vigneshr at ti.com  Thu Oct 13 05:11:48 2016
From: vigneshr at ti.com (Vignesh R)
Date: Thu, 13 Oct 2016 17:41:48 +0530
Subject: [PATCH v2 2/9] mtd: spi-nor: add an alternative method to support
 memory >16MiB
In-Reply-To: <18b156f699e82ff9b36c044df73a2ef769d53c83.1475668319.git.cyrille.pitchen@atmel.com>
References: <cover.1475668319.git.cyrille.pitchen@atmel.com>
 <18b156f699e82ff9b36c044df73a2ef769d53c83.1475668319.git.cyrille.pitchen@atmel.com>
Message-ID: <138da64f-8a3f-6259-0f31-db908aea2824@ti.com>



On Wednesday 05 October 2016 05:30 PM, Cyrille Pitchen wrote:
> This patch provides an alternative mean to support memory above 16MiB
> (128Mib) by replacing 3byte address op codes by their associated 4byte
> address versions.
> 
> Using the dedicated 4byte address op codes doesn't change the internal
> state of the SPI NOR memory as opposed to using other means such as
> updating a Base Address Register (BAR) and sending command to enter/leave
> the 4byte mode.
> 
> Hence when a CPU reset occurs, early bootloaders don't need to be aware
> of BAR value or 4byte mode being enabled: they can still access the first
> 16MiB of the SPI NOR memory using the regular 3byte address op codes.
> 

I am facing a similar issue on my am437x-idk board with mx66l51235l
flash and bootloader failed to access flash due to 4byte mode being
enabled. With SPI_NOR_4B_OPCODES flag set in mx66l51235l flash info and
this series applied, I can see that bootloader can now access flash.
Thanks for the patch!

FWIW, Tested-by: Vignesh R <vigneshr at ti.com>

> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
> ---
>  drivers/mtd/devices/serial_flash_cmds.h |   7 ---
>  drivers/mtd/devices/st_spi_fsm.c        |  28 ++++-----
>  drivers/mtd/spi-nor/spi-nor.c           | 104 +++++++++++++++++++++++++-------
>  include/linux/mtd/spi-nor.h             |  22 +++++--
>  4 files changed, 113 insertions(+), 48 deletions(-)
> 
> diff --git a/drivers/mtd/devices/serial_flash_cmds.h b/drivers/mtd/devices/serial_flash_cmds.h
> index f59a125295d0..8b81e15105dd 100644
> --- a/drivers/mtd/devices/serial_flash_cmds.h
> +++ b/drivers/mtd/devices/serial_flash_cmds.h
> @@ -18,19 +18,12 @@
>  #define SPINOR_OP_RDVCR		0x85
>  
>  /* JEDEC Standard - Serial Flash Discoverable Parmeters (SFDP) Commands */
> -#define SPINOR_OP_READ_1_2_2	0xbb	/* DUAL I/O READ */
> -#define SPINOR_OP_READ_1_4_4	0xeb	/* QUAD I/O READ */
> -
>  #define SPINOR_OP_WRITE		0x02	/* PAGE PROGRAM */
>  #define SPINOR_OP_WRITE_1_1_2	0xa2	/* DUAL INPUT PROGRAM */
>  #define SPINOR_OP_WRITE_1_2_2	0xd2	/* DUAL INPUT EXT PROGRAM */
>  #define SPINOR_OP_WRITE_1_1_4	0x32	/* QUAD INPUT PROGRAM */
>  #define SPINOR_OP_WRITE_1_4_4	0x12	/* QUAD INPUT EXT PROGRAM */
>  
> -/* READ commands with 32-bit addressing */
> -#define SPINOR_OP_READ4_1_2_2	0xbc
> -#define SPINOR_OP_READ4_1_4_4	0xec
> -
>  /* Configuration flags */
>  #define FLASH_FLAG_SINGLE	0x000000ff
>  #define FLASH_FLAG_READ_WRITE	0x00000001
> diff --git a/drivers/mtd/devices/st_spi_fsm.c b/drivers/mtd/devices/st_spi_fsm.c
> index 5454b4113589..804313a33f2b 100644
> --- a/drivers/mtd/devices/st_spi_fsm.c
> +++ b/drivers/mtd/devices/st_spi_fsm.c
> @@ -507,13 +507,13 @@ static struct seq_rw_config n25q_read3_configs[] = {
>   *	- 'FAST' variants configured for 8 dummy cycles (see note above.)
>   */
>  static struct seq_rw_config n25q_read4_configs[] = {
> -	{FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ4_1_4_4,	0, 4, 4, 0x00, 0, 8},
> -	{FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ4_1_1_4,	0, 1, 4, 0x00, 0, 8},
> -	{FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ4_1_2_2,	0, 2, 2, 0x00, 0, 8},
> -	{FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ4_1_1_2,	0, 1, 2, 0x00, 0, 8},
> -	{FLASH_FLAG_READ_FAST,	SPINOR_OP_READ4_FAST,	0, 1, 1, 0x00, 0, 8},
> -	{FLASH_FLAG_READ_WRITE, SPINOR_OP_READ4,	0, 1, 1, 0x00, 0, 0},
> -	{0x00,			0,			0, 0, 0, 0x00, 0, 0},
> +	{FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ_1_4_4_4B, 0, 4, 4, 0x00, 0, 8},
> +	{FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ_1_1_4_4B, 0, 1, 4, 0x00, 0, 8},
> +	{FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ_1_2_2_4B, 0, 2, 2, 0x00, 0, 8},
> +	{FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ_1_1_2_4B, 0, 1, 2, 0x00, 0, 8},
> +	{FLASH_FLAG_READ_FAST,	SPINOR_OP_READ_FAST_4B,  0, 1, 1, 0x00, 0, 8},
> +	{FLASH_FLAG_READ_WRITE, SPINOR_OP_READ_4B,       0, 1, 1, 0x00, 0, 0},
> +	{0x00,			0,                       0, 0, 0, 0x00, 0, 0},
>  };
>  
>  /*
> @@ -553,13 +553,13 @@ static int stfsm_mx25_en_32bit_addr_seq(struct stfsm_seq *seq)
>   * entering a state that is incompatible with the SPIBoot Controller.
>   */
>  static struct seq_rw_config stfsm_s25fl_read4_configs[] = {
> -	{FLASH_FLAG_READ_1_4_4,  SPINOR_OP_READ4_1_4_4,  0, 4, 4, 0x00, 2, 4},
> -	{FLASH_FLAG_READ_1_1_4,  SPINOR_OP_READ4_1_1_4,  0, 1, 4, 0x00, 0, 8},
> -	{FLASH_FLAG_READ_1_2_2,  SPINOR_OP_READ4_1_2_2,  0, 2, 2, 0x00, 4, 0},
> -	{FLASH_FLAG_READ_1_1_2,  SPINOR_OP_READ4_1_1_2,  0, 1, 2, 0x00, 0, 8},
> -	{FLASH_FLAG_READ_FAST,   SPINOR_OP_READ4_FAST,   0, 1, 1, 0x00, 0, 8},
> -	{FLASH_FLAG_READ_WRITE,  SPINOR_OP_READ4,        0, 1, 1, 0x00, 0, 0},
> -	{0x00,                   0,                      0, 0, 0, 0x00, 0, 0},
> +	{FLASH_FLAG_READ_1_4_4,  SPINOR_OP_READ_1_4_4_4B,  0, 4, 4, 0x00, 2, 4},
> +	{FLASH_FLAG_READ_1_1_4,  SPINOR_OP_READ_1_1_4_4B,  0, 1, 4, 0x00, 0, 8},
> +	{FLASH_FLAG_READ_1_2_2,  SPINOR_OP_READ_1_2_2_4B,  0, 2, 2, 0x00, 4, 0},
> +	{FLASH_FLAG_READ_1_1_2,  SPINOR_OP_READ_1_1_2_4B,  0, 1, 2, 0x00, 0, 8},
> +	{FLASH_FLAG_READ_FAST,   SPINOR_OP_READ_FAST_4B,   0, 1, 1, 0x00, 0, 8},
> +	{FLASH_FLAG_READ_WRITE,  SPINOR_OP_READ_4B,        0, 1, 1, 0x00, 0, 0},
> +	{0x00,                   0,                        0, 0, 0, 0x00, 0, 0},
>  };
>  
>  static struct seq_rw_config stfsm_s25fl_write4_configs[] = {
> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
> index 5c87b2d99507..423448c1c7a8 100644
> --- a/drivers/mtd/spi-nor/spi-nor.c
> +++ b/drivers/mtd/spi-nor/spi-nor.c
> @@ -75,6 +75,10 @@ struct flash_info {
>  					 * bit. Must be used with
>  					 * SPI_NOR_HAS_LOCK.
>  					 */
> +#define SPI_NOR_4B_OPCODES	BIT(10)	/*
> +					 * Use dedicated 4byte address op codes
> +					 * to support memory size above 128Mib.
> +					 */
>  };
>  
>  #define JEDEC_MFR(info)	((info)->id[0])
> @@ -188,6 +192,81 @@ static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd)
>  	return mtd->priv;
>  }
>  
> +
> +struct spi_nor_address_entry {
> +	u8	src_opcode;
> +	u8	dst_opcode;
> +};
> +
> +static u8 spi_nor_convert_opcode(u8 opcode,
> +				 const struct spi_nor_address_entry *entries,
> +				 size_t num_entries)
> +{
> +	int min, max;
> +
> +	min = 0;
> +	max = num_entries - 1;
> +	while (min <= max) {
> +		int mid = (min + max) >> 1;
> +		const struct spi_nor_address_entry *entry = &entries[mid];
> +
> +		if (opcode == entry->src_opcode)
> +			return entry->dst_opcode;
> +
> +		if (opcode < entry->src_opcode)
> +			max = mid - 1;
> +		else
> +			min = mid + 1;
> +	}
> +
> +	/* No conversion found */
> +	return opcode;
> +}
> +
> +static u8 spi_nor_3to4_opcode(u8 opcode)
> +{
> +	/* MUST be sorted by 3byte opcode */
> +#define ENTRY_3TO4(_opcode)	{ _opcode, _opcode##_4B }
> +	static const struct spi_nor_address_entry spi_nor_3to4_table[] = {
> +		ENTRY_3TO4(SPINOR_OP_PP),		/* 0x02 */
> +		ENTRY_3TO4(SPINOR_OP_READ),		/* 0x03 */
> +		ENTRY_3TO4(SPINOR_OP_READ_FAST),	/* 0x0b */
> +		ENTRY_3TO4(SPINOR_OP_BE_4K),		/* 0x20 */
> +		ENTRY_3TO4(SPINOR_OP_PP_1_1_4),		/* 0x32 */
> +		ENTRY_3TO4(SPINOR_OP_PP_1_4_4),		/* 0x38 */
> +		ENTRY_3TO4(SPINOR_OP_READ_1_1_2),	/* 0x3b */
> +		ENTRY_3TO4(SPINOR_OP_BE_32K),		/* 0x52 */
> +		ENTRY_3TO4(SPINOR_OP_READ_1_1_4),	/* 0x6b */
> +		ENTRY_3TO4(SPINOR_OP_READ_1_2_2),	/* 0xbb */
> +		ENTRY_3TO4(SPINOR_OP_SE),		/* 0xd8 */
> +		ENTRY_3TO4(SPINOR_OP_READ_1_4_4),	/* 0xeb */
> +	};
> +#undef ENTRY_3TO4
> +
> +	return spi_nor_convert_opcode(opcode, spi_nor_3to4_table,
> +				      ARRAY_SIZE(spi_nor_3to4_table));
> +}
> +
> +static void spi_nor_set_4byte_opcodes(struct spi_nor *nor,
> +				      const struct flash_info *info)
> +{
> +	/* Do some manufacturer fixups first */
> +	switch (JEDEC_MFR(info)) {
> +	case SNOR_MFR_SPANSION:
> +		/* No small sector erase for 4-byte command set */
> +		nor->erase_opcode = SPINOR_OP_SE;
> +		nor->mtd.erasesize = info->sector_size;
> +		break;
> +
> +	default:
> +		break;
> +	}
> +
> +	nor->read_opcode	= spi_nor_3to4_opcode(nor->read_opcode);
> +	nor->program_opcode	= spi_nor_3to4_opcode(nor->program_opcode);
> +	nor->erase_opcode	= spi_nor_3to4_opcode(nor->erase_opcode);
> +}
> +
>  /* Enable/disable 4-byte addressing mode. */
>  static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info,
>  			    int enable)
> @@ -1476,27 +1555,10 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
>  	else if (mtd->size > 0x1000000) {
>  		/* enable 4-byte addressing if the device exceeds 16MiB */
>  		nor->addr_width = 4;
> -		if (JEDEC_MFR(info) == SNOR_MFR_SPANSION) {
> -			/* Dedicated 4-byte command set */
> -			switch (nor->flash_read) {
> -			case SPI_NOR_QUAD:
> -				nor->read_opcode = SPINOR_OP_READ4_1_1_4;
> -				break;
> -			case SPI_NOR_DUAL:
> -				nor->read_opcode = SPINOR_OP_READ4_1_1_2;
> -				break;
> -			case SPI_NOR_FAST:
> -				nor->read_opcode = SPINOR_OP_READ4_FAST;
> -				break;
> -			case SPI_NOR_NORMAL:
> -				nor->read_opcode = SPINOR_OP_READ4;
> -				break;
> -			}
> -			nor->program_opcode = SPINOR_OP_PP_4B;
> -			/* No small sector erase for 4-byte command set */
> -			nor->erase_opcode = SPINOR_OP_SE_4B;
> -			mtd->erasesize = info->sector_size;
> -		} else
> +		if (JEDEC_MFR(info) == SNOR_MFR_SPANSION ||
> +		    info->flags & SPI_NOR_4B_OPCODES)
> +			spi_nor_set_4byte_opcodes(nor, info);
> +		else
>  			set_4byte(nor, info, 1);
>  	} else {
>  		nor->addr_width = 3;
> diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
> index c425c7b4c2a0..8b02fd7864d0 100644
> --- a/include/linux/mtd/spi-nor.h
> +++ b/include/linux/mtd/spi-nor.h
> @@ -43,9 +43,13 @@
>  #define SPINOR_OP_WRSR		0x01	/* Write status register 1 byte */
>  #define SPINOR_OP_READ		0x03	/* Read data bytes (low frequency) */
>  #define SPINOR_OP_READ_FAST	0x0b	/* Read data bytes (high frequency) */
> -#define SPINOR_OP_READ_1_1_2	0x3b	/* Read data bytes (Dual SPI) */
> -#define SPINOR_OP_READ_1_1_4	0x6b	/* Read data bytes (Quad SPI) */
> +#define SPINOR_OP_READ_1_1_2	0x3b	/* Read data bytes (Dual Output SPI) */
> +#define SPINOR_OP_READ_1_2_2	0xbb	/* Read data bytes (Dual I/O SPI) */
> +#define SPINOR_OP_READ_1_1_4	0x6b	/* Read data bytes (Quad Output SPI) */
> +#define SPINOR_OP_READ_1_4_4	0xeb	/* Read data bytes (Quad I/O SPI) */
>  #define SPINOR_OP_PP		0x02	/* Page program (up to 256 bytes) */
> +#define SPINOR_OP_PP_1_1_4	0x32	/* Quad page program */
> +#define SPINOR_OP_PP_1_4_4	0x38	/* Quad page program */
>  #define SPINOR_OP_BE_4K		0x20	/* Erase 4KiB block */
>  #define SPINOR_OP_BE_4K_PMC	0xd7	/* Erase 4KiB block on PMC chips */
>  #define SPINOR_OP_BE_32K	0x52	/* Erase 32KiB block */
> @@ -56,11 +60,17 @@
>  #define SPINOR_OP_RDFSR		0x70	/* Read flag status register */
>  
>  /* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
> -#define SPINOR_OP_READ4		0x13	/* Read data bytes (low frequency) */
> -#define SPINOR_OP_READ4_FAST	0x0c	/* Read data bytes (high frequency) */
> -#define SPINOR_OP_READ4_1_1_2	0x3c	/* Read data bytes (Dual SPI) */
> -#define SPINOR_OP_READ4_1_1_4	0x6c	/* Read data bytes (Quad SPI) */
> +#define SPINOR_OP_READ_4B	0x13	/* Read data bytes (low frequency) */
> +#define SPINOR_OP_READ_FAST_4B	0x0c	/* Read data bytes (high frequency) */
> +#define SPINOR_OP_READ_1_1_2_4B	0x3c	/* Read data bytes (Dual Output SPI) */
> +#define SPINOR_OP_READ_1_2_2_4B	0xbc	/* Read data bytes (Dual I/O SPI) */
> +#define SPINOR_OP_READ_1_1_4_4B	0x6c	/* Read data bytes (Quad Output SPI) */
> +#define SPINOR_OP_READ_1_4_4_4B	0xec	/* Read data bytes (Quad I/O SPI) */
>  #define SPINOR_OP_PP_4B		0x12	/* Page program (up to 256 bytes) */
> +#define SPINOR_OP_PP_1_1_4_4B	0x34	/* Quad page program */
> +#define SPINOR_OP_PP_1_4_4_4B	0x3e	/* Quad page program */
> +#define SPINOR_OP_BE_4K_4B	0x21	/* Erase 4KiB block */
> +#define SPINOR_OP_BE_32K_4B	0x5c	/* Erase 32KiB block */
>  #define SPINOR_OP_SE_4B		0xdc	/* Sector erase (usually 64KiB) */
>  
>  /* Used for SST flashes only. */
> 

-- 
Regards
Vignesh


From boris.brezillon at free-electrons.com  Thu Oct 13 07:24:58 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Thu, 13 Oct 2016 16:24:58 +0200
Subject: [PATCH] UBI: Fix crash in try_recover_peb()
In-Reply-To: <1476367536-24782-1-git-send-email-geert@linux-m68k.org>
References: <1476367536-24782-1-git-send-email-geert@linux-m68k.org>
Message-ID: <20161013162458.0219177b@bbrezillon>

Hi Geert,

On Thu, 13 Oct 2016 16:05:36 +0200
Geert Uytterhoeven <geert at linux-m68k.org> wrote:

>     drivers/mtd/ubi/eba.c: In function ?try_recover_peb?:
>     drivers/mtd/ubi/eba.c:744: warning: ?vid_hdr? is used uninitialized in this function
> 
> The pointer vid_hdr is indeed not initialized, leading to a crash when
> it is dereferenced.
> 
> Fix this by obtaining the pointer from the VID buffer, like is done
> everywhere else.

Indeed, I don't know how I missed that one :-/.

> 
> Fixes: 3291b52f9ff0acc8 ("UBI: introduce the VID buffer concept")
> Signed-off-by: Geert Uytterhoeven <geert at linux-m68k.org>

One minor comment below, otherwise

Reviewed-by: Boris Brezillon <boris.brezillon at free-electrons.com>

> ---
> Completely untested. And I know nothing about UBI ;-)
> ---
>  drivers/mtd/ubi/eba.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
> index 95c4048a371e87b6..388e46be6ad92805 100644
> --- a/drivers/mtd/ubi/eba.c
> +++ b/drivers/mtd/ubi/eba.c
> @@ -741,6 +741,7 @@ static int try_recover_peb(struct ubi_volume *vol, int pnum, int lnum,
>  		goto out_put;
>  	}
>  
> +	vid_hdr = ubi_get_vid_hdr(vidb);

Can you move this assignment at variable declaration time?

>  	ubi_assert(vid_hdr->vol_type == UBI_VID_DYNAMIC);
>  
>  	mutex_lock(&ubi->buf_mutex);



From hkallweit1 at gmail.com  Thu Oct 13 11:50:09 2016
From: hkallweit1 at gmail.com (Heiner Kallweit)
Date: Thu, 13 Oct 2016 20:50:09 +0200
Subject: [PATCH v2 RESEND 2/3] mtd: m25p80: consider max message size in
 m25p80_read
In-Reply-To: <20160816164204.GV9347@sirena.org.uk>
References: <6c95366c-7fcc-ef4c-033a-f9f6e152a669@gmail.com>
 <20160816164204.GV9347@sirena.org.uk>
Message-ID: <e084ae6e-2d89-7d96-0ccf-da23cef00043@gmail.com>

Consider a message size limit when calculating the maximum amount
of data that can be read.

Signed-off-by: Heiner Kallweit <hkallweit1 at gmail.com>
---
v2:
- use the new function spi_max_message_size
---
 drivers/mtd/devices/m25p80.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 9cf7fcd..16a7df2 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -172,7 +172,8 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
 
 	t[1].rx_buf = buf;
 	t[1].rx_nbits = m25p80_rx_nbits(nor);
-	t[1].len = min(len, spi_max_transfer_size(spi));
+	t[1].len = min3(len, spi_max_transfer_size(spi),
+			spi_max_message_size(spi) - t[0].len);
 	spi_message_add_tail(&t[1], &m);
 
 	ret = spi_sync(spi, &m);
-- 
2.9.2




From kamal.dasu at broadcom.com  Thu Oct 13 14:15:08 2016
From: kamal.dasu at broadcom.com (Kamal Dasu)
Date: Thu, 13 Oct 2016 17:15:08 -0400
Subject: [PATCH v6,
 5/8] mtd: m25p80: Let m25p80_read() fallback to spi transfer
In-Reply-To: <8309370e-f99f-ed51-4789-c1d97d9d8191@atmel.com>
References: <1472076269-4731-1-git-send-email-kdasu.kdev@gmail.com>
 <1472076269-4731-6-git-send-email-kdasu.kdev@gmail.com>
 <4b3b3d3e-b3f8-1d5b-65e3-0c37b6a29096@gmail.com>
 <8309370e-f99f-ed51-4789-c1d97d9d8191@atmel.com>
Message-ID: <CAKekbesq1deU_0TCV4STAi=o8jZwoc_u+9zkdZuEhmd+BGwU2A@mail.gmail.com>

On Mon, Oct 10, 2016 at 4:29 AM, Cyrille Pitchen
<cyrille.pitchen at atmel.com> wrote:
> Hi all,
>
>
> Le 10/10/2016 ? 10:04, Florian Fainelli a ?crit :
>> On 08/24/2016 03:04 PM, Kamal Dasu wrote:
>>> In m25p80_read() even though spi_flash_read() is supported
>>> by some drivers, under certain circumstances like unaligned
>>> buffer, address or address range limitations on certain SoCs
>>> let it fallback to core spi reads. Such drivers are expected
>>> to return -EAGAIN so that the m25p80_read() uses standard
>>> spi transfer.
>>>
>>> Signed-off-by: Kamal Dasu <kdasu.kdev at gmail.com>
>>
>> MTD folks, any comments on this?
>>
>>> ---
>>>  drivers/mtd/devices/m25p80.c | 11 +++++++++--
>>>  1 file changed, 9 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
>>> index 9cf7fcd..77c2d2c 100644
>>> --- a/drivers/mtd/devices/m25p80.c
>>> +++ b/drivers/mtd/devices/m25p80.c
>>> @@ -155,9 +155,16 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
>>>              msg.data_nbits = m25p80_rx_nbits(nor);
>>>
>>>              ret = spi_flash_read(spi, &msg);
>>> -            if (ret < 0)
>>> +
>>> +            if (ret >= 0)
>>> +                    return msg.retlen;
>>> +
>>> +            /*
>>> +             * some spi master drivers might need to fallback to
>>> +             * normal spi transfer
>>> +             */
>>> +            if (ret != -EAGAIN)
> I just wonder whether EINVAL would be a better choice.

 spi_flash_read calls the down stream controller driver with all
params addresses however  accelerated transfer is not possible by the
controller due to alignment issues, it needs to indicate to m25p call
to try the normal transfer, hence use of EAGAIN seemed appropriate.


>>>                      return ret;
>>> -            return msg.retlen;
>>>      }
>>>
>>>      spi_message_init(&m);
>>>
>>
>
> Best regards,
>
> Cyrille


From marex at denx.de  Fri Oct 14 00:16:23 2016
From: marex at denx.de (Marek Vasut)
Date: Fri, 14 Oct 2016 09:16:23 +0200
Subject: [patch 2/2] mtd: spi-nor: Fix some error codes in
 cqspi_setup_flash()
In-Reply-To: <20161013080857.GC3389@mwanda>
References: <20161013080857.GC3389@mwanda>
Message-ID: <3ebab16e-ddf8-0a4b-aaaf-d5b424720eb2@denx.de>

On 10/13/2016 10:30 AM, Dan Carpenter wrote:
> We return success or possibly uninitialized values on these error paths
> instead of proper error codes.
> 
> Fixes: 140623410536 ("mtd: spi-nor: Add driver for Cadence Quad SPI Flash Controller")
> Signed-off-by: Dan Carpenter <dan.carpenter at oracle.com>
> 

Nice

Reviewed-by: Marek Vasut <marex at denx.de>

> diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c
> index 944863b..d489fbd 100644
> --- a/drivers/mtd/spi-nor/cadence-quadspi.c
> +++ b/drivers/mtd/spi-nor/cadence-quadspi.c
> @@ -1077,12 +1077,14 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
>  
>  	/* Get flash device data */
>  	for_each_available_child_of_node(dev->of_node, np) {
> -		if (of_property_read_u32(np, "reg", &cs)) {
> +		ret = of_property_read_u32(np, "reg", &cs);
> +		if (ret) {
>  			dev_err(dev, "Couldn't determine chip select.\n");
>  			goto err;
>  		}
>  
>  		if (cs >= CQSPI_MAX_CHIPSELECT) {
> +			ret = -EINVAL;
>  			dev_err(dev, "Chip select %d out of range.\n", cs);
>  			goto err;
>  		}
> 


-- 
Best regards,
Marek Vasut


From marex at denx.de  Fri Oct 14 00:19:05 2016
From: marex at denx.de (Marek Vasut)
Date: Fri, 14 Oct 2016 09:19:05 +0200
Subject: [patch 1/2] mtd: spi-nor: Off by one in cqspi_setup_flash()
In-Reply-To: <20161013080646.GB3389@mwanda>
References: <20161013080646.GB3389@mwanda>
Message-ID: <360bddfc-0495-8836-41ef-4121517011a3@denx.de>

On 10/13/2016 10:06 AM, Dan Carpenter wrote:
> There are CQSPI_MAX_CHIPSELECT elements in the ->f_pdata array so the >
> should be >=.
> 
> Fixes: 140623410536 ('mtd: spi-nor: Add driver for Cadence Quad SPI Flash Controller')
> Signed-off-by: Dan Carpenter <dan.carpenter at oracle.com>

Reviewed-by: Marek Vasut <marex at denx.de>

> diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c
> index d403ba7..944863b 100644
> --- a/drivers/mtd/spi-nor/cadence-quadspi.c
> +++ b/drivers/mtd/spi-nor/cadence-quadspi.c
> @@ -1082,7 +1082,7 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
>  			goto err;
>  		}
>  
> -		if (cs > CQSPI_MAX_CHIPSELECT) {
> +		if (cs >= CQSPI_MAX_CHIPSELECT) {
>  			dev_err(dev, "Chip select %d out of range.\n", cs);
>  			goto err;
>  		}
> 


-- 
Best regards,
Marek Vasut


From boris.brezillon at free-electrons.com  Fri Oct 14 03:49:28 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Fri, 14 Oct 2016 12:49:28 +0200
Subject: [PATCH] UBI: Fix crash in try_recover_peb()
In-Reply-To: <20161013162458.0219177b@bbrezillon>
References: <1476367536-24782-1-git-send-email-geert@linux-m68k.org>
 <20161013162458.0219177b@bbrezillon>
Message-ID: <20161014124928.5a27ed59@bbrezillon>

On Thu, 13 Oct 2016 16:24:58 +0200
Boris Brezillon <boris.brezillon at free-electrons.com> wrote:

> Hi Geert,
> 
> On Thu, 13 Oct 2016 16:05:36 +0200
> Geert Uytterhoeven <geert at linux-m68k.org> wrote:
> 
> >     drivers/mtd/ubi/eba.c: In function ?try_recover_peb?:
> >     drivers/mtd/ubi/eba.c:744: warning: ?vid_hdr? is used uninitialized in this function
> > 
> > The pointer vid_hdr is indeed not initialized, leading to a crash when
> > it is dereferenced.
> > 
> > Fix this by obtaining the pointer from the VID buffer, like is done
> > everywhere else.  
> 
> Indeed, I don't know how I missed that one :-/.

That's really weird. I tried to recompile the kernel on my machine
(before applying your patch), to see if the compiler was complaining,
and it's not :-(.

I also coded simple functions with goto statements, to check that the
detection was working correctly, and it is.

Maybe you have some ideas why my compiler is failing to detect the
problem (I'm currently using the ubuntu cross-toolchain:
'arm-linux-gnueabi-gcc (Ubuntu/Linaro 5.4.0-6ubuntu1~16.04.1) 5.4.0
20160609').

> 
> > 
> > Fixes: 3291b52f9ff0acc8 ("UBI: introduce the VID buffer concept")
> > Signed-off-by: Geert Uytterhoeven <geert at linux-m68k.org>  
> 
> One minor comment below, otherwise
> 
> Reviewed-by: Boris Brezillon <boris.brezillon at free-electrons.com>
> 
> > ---
> > Completely untested. And I know nothing about UBI ;-)
> > ---
> >  drivers/mtd/ubi/eba.c | 1 +
> >  1 file changed, 1 insertion(+)
> > 
> > diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
> > index 95c4048a371e87b6..388e46be6ad92805 100644
> > --- a/drivers/mtd/ubi/eba.c
> > +++ b/drivers/mtd/ubi/eba.c
> > @@ -741,6 +741,7 @@ static int try_recover_peb(struct ubi_volume *vol, int pnum, int lnum,
> >  		goto out_put;
> >  	}
> >  
> > +	vid_hdr = ubi_get_vid_hdr(vidb);  
> 
> Can you move this assignment at variable declaration time?
> 
> >  	ubi_assert(vid_hdr->vol_type == UBI_VID_DYNAMIC);
> >  
> >  	mutex_lock(&ubi->buf_mutex);  
> 



From dedekind1 at gmail.com  Fri Oct 14 05:41:23 2016
From: dedekind1 at gmail.com (Artem Bityutskiy)
Date: Fri, 14 Oct 2016 15:41:23 +0300
Subject: Failure on MTD sub-page test
In-Reply-To: <39BC08CB3FF4C84CB6397533D4FC7909015DDE3F@SEGOTEXCH02.ascom-Resource.ads>
References: <39BC08CB3FF4C84CB6397533D4FC7909015DDE3F@SEGOTEXCH02.ascom-Resource.ads>
Message-ID: <1476448883.2342.924.camel@gmail.com>

On Tue, 2016-10-11 at 11:11 +0000, Danesh Daroui wrote:
> Hello,
> 
> We are using UBIFS which is shipped with the Kernel 2.6.39.4 on a
> NAND Flash memory. When I run "mtd_debug info /dev/mtd0" following
> info are shown:
> 
> mtd.type = MTD_NANDFLASH
> mtd.flags = MTD_CAP_NANDFLASH
> mtd.size = 1073741824 (1G)
> mtd.erasesize = 524288 (512K)
> mtd.writesize = 4096 (4K)
> mtd.oobsize = 128
> regions = 0
> 
> Now the problem is that when I run mtd tests, only read and NAND ECC
> tests are passed. Then all other tests fail on exactly page 21. For
> instance this is the output when I run page test:

If mtd tests do not work, you need to focus on your MTD drivers and fix
them.

> =================================================
> mtd_subpagetest: MTD device: 0
> mtd_subpagetest: MTD device size 1073741824, eraseblock size 524288,
> page size 4096, subpage size 1024, count of eraseblocks 2048, pages 
... snip ...
> mtd_subpagetest: verified up to eraseblock 1280
> mtd_subpagetest: verified up to eraseblock 1536
> mtd_subpagetest: verified up to eraseblock 1792
> UBIFS error (pid 4243): ubifs_read_node: bad node type (255 but
> expected 1)
> UBIFS error (pid 4243): ubifs_read_node: bad node at LEB 30:98088,
> LEB mapping status 1
> UBIFS error (pid 4243): do_readpage: cannot read page 21 of inode
> 791, error -22

This is a bit confusing - why messages go together. Do you run mtd
tests and also have the same mtd device mounted at the same time?

The tests hammer the MTD device directly, they do not go through
UBI/UBIFS. So make sure UBI/UBIFS are not using the MTD device that you
are testing.

Artem.



From cyrille.pitchen at atmel.com  Fri Oct 14 06:17:44 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Fri, 14 Oct 2016 15:17:44 +0200
Subject: [PATCH v6, 5/8] mtd: m25p80: Let m25p80_read() fallback to spi
 transfer
In-Reply-To: <CAKekbesq1deU_0TCV4STAi=o8jZwoc_u+9zkdZuEhmd+BGwU2A@mail.gmail.com>
References: <1472076269-4731-1-git-send-email-kdasu.kdev@gmail.com>
 <1472076269-4731-6-git-send-email-kdasu.kdev@gmail.com>
 <4b3b3d3e-b3f8-1d5b-65e3-0c37b6a29096@gmail.com>
 <8309370e-f99f-ed51-4789-c1d97d9d8191@atmel.com>
 <CAKekbesq1deU_0TCV4STAi=o8jZwoc_u+9zkdZuEhmd+BGwU2A@mail.gmail.com>
Message-ID: <ae2c984e-2bcf-380e-a257-dbe786973af1@atmel.com>

Le 13/10/2016 ? 23:15, Kamal Dasu a ?crit :
> On Mon, Oct 10, 2016 at 4:29 AM, Cyrille Pitchen
> <cyrille.pitchen at atmel.com> wrote:
>> Hi all,
>>
>>
>> Le 10/10/2016 ? 10:04, Florian Fainelli a ?crit :
>>> On 08/24/2016 03:04 PM, Kamal Dasu wrote:
>>>> In m25p80_read() even though spi_flash_read() is supported
>>>> by some drivers, under certain circumstances like unaligned
>>>> buffer, address or address range limitations on certain SoCs
>>>> let it fallback to core spi reads. Such drivers are expected
>>>> to return -EAGAIN so that the m25p80_read() uses standard
>>>> spi transfer.
>>>>
>>>> Signed-off-by: Kamal Dasu <kdasu.kdev at gmail.com>
>>>
>>> MTD folks, any comments on this?
>>>
>>>> ---
>>>>  drivers/mtd/devices/m25p80.c | 11 +++++++++--
>>>>  1 file changed, 9 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
>>>> index 9cf7fcd..77c2d2c 100644
>>>> --- a/drivers/mtd/devices/m25p80.c
>>>> +++ b/drivers/mtd/devices/m25p80.c
>>>> @@ -155,9 +155,16 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
>>>>              msg.data_nbits = m25p80_rx_nbits(nor);
>>>>
>>>>              ret = spi_flash_read(spi, &msg);
>>>> -            if (ret < 0)
>>>> +
>>>> +            if (ret >= 0)
>>>> +                    return msg.retlen;
>>>> +
>>>> +            /*
>>>> +             * some spi master drivers might need to fallback to
>>>> +             * normal spi transfer
>>>> +             */
>>>> +            if (ret != -EAGAIN)
>> I just wonder whether EINVAL would be a better choice.
> 
>  spi_flash_read calls the down stream controller driver with all
> params addresses however  accelerated transfer is not possible by the
> controller due to alignment issues, it needs to indicate to m25p call
> to try the normal transfer, hence use of EAGAIN seemed appropriate.
> 
>

Yes, I think I've understood the purpose of this patch. In the example you
gave, the actual implementation of spi_flash_read() works fine with aligned
addresses but doesn't support unaligned addresses. Hence, such unaligned
addresses are invalid argument for spi_flash_read() and we should fall back
to the legacy implementation of m25p80_read().

My point is just that EINVAL clearly tells that the SPI controller driver
implementation of spi_flash_read() doesn't support the given input
parameters, here an unaligned address, whereas EAGAIN suggests that some
hardware resource is temporarily unavailable and we could call spi_flash_read()
again later. However, in this case, spi_flash_read() would still fail even if
called later.

That's why I've suggested EINVAL might have been a better choice than EAGAIN,
but honestly it's not a big deal, only a detail. So if most people prefer to
keep EAGAIN, I'm perfectly fine with it! :)

I don't want my comment to delay the integration of this patch.

>>>>                      return ret;
>>>> -            return msg.retlen;
>>>>      }
>>>>
>>>>      spi_message_init(&m);
>>>>
>>>
>>
>> Best regards,
>>
>> Cyrille



From Danesh.Daroui at ascom.com  Fri Oct 14 07:13:49 2016
From: Danesh.Daroui at ascom.com (Danesh Daroui)
Date: Fri, 14 Oct 2016 14:13:49 +0000
Subject: Failure on MTD sub-page test
In-Reply-To: <1476448883.2342.924.camel@gmail.com>
References: <39BC08CB3FF4C84CB6397533D4FC7909015DDE3F@SEGOTEXCH02.ascom-Resource.ads>
 <1476448883.2342.924.camel@gmail.com>
Message-ID: <39BC08CB3FF4C84CB6397533D4FC7909015DE2F7@SEGOTEXCH02.ascom-Resource.ads>

Hi Artem,

Thanks for your reply. I can unmount the device and run the tests, but then how can we make sure whether the problem is in UBI/UBIFS layers or only MTD layer? Anyway, if we update the kernel, then both MTD drivers and UBI/UBIFS will be updated, am I right?

Regards,

Danesh Daroui

 
-----Original Message-----
From: Artem Bityutskiy [mailto:dedekind1 at gmail.com] 
Sent: den 14 oktober 2016 14:41
To: Danesh Daroui <Danesh.Daroui at ascom.com>; linux-mtd at lists.infradead.org
Subject: Re: Failure on MTD sub-page test

On Tue, 2016-10-11 at 11:11 +0000, Danesh Daroui wrote:
> Hello,
> 
> We are using UBIFS which is shipped with the Kernel 2.6.39.4 on a NAND 
> Flash memory. When I run "mtd_debug info /dev/mtd0" following info are 
> shown:
> 
> mtd.type = MTD_NANDFLASH
> mtd.flags = MTD_CAP_NANDFLASH
> mtd.size = 1073741824 (1G)
> mtd.erasesize = 524288 (512K)
> mtd.writesize = 4096 (4K)
> mtd.oobsize = 128
> regions = 0
> 
> Now the problem is that when I run mtd tests, only read and NAND ECC 
> tests are passed. Then all other tests fail on exactly page 21. For 
> instance this is the output when I run page test:

If mtd tests do not work, you need to focus on your MTD drivers and fix them.

> =================================================
> mtd_subpagetest: MTD device: 0
> mtd_subpagetest: MTD device size 1073741824, eraseblock size 524288, 
> page size 4096, subpage size 1024, count of eraseblocks 2048, pages
... snip ...
> mtd_subpagetest: verified up to eraseblock 1280
> mtd_subpagetest: verified up to eraseblock 1536
> mtd_subpagetest: verified up to eraseblock 1792 UBIFS error (pid 
> 4243): ubifs_read_node: bad node type (255 but expected 1) UBIFS error 
> (pid 4243): ubifs_read_node: bad node at LEB 30:98088, LEB mapping 
> status 1 UBIFS error (pid 4243): do_readpage: cannot read page 21 of 
> inode 791, error -22

This is a bit confusing - why messages go together. Do you run mtd tests and also have the same mtd device mounted at the same time?

The tests hammer the MTD device directly, they do not go through UBI/UBIFS. So make sure UBI/UBIFS are not using the MTD device that you are testing.

Artem.


From dedekind1 at gmail.com  Fri Oct 14 07:38:39 2016
From: dedekind1 at gmail.com (Artem Bityutskiy)
Date: Fri, 14 Oct 2016 17:38:39 +0300
Subject: Failure on MTD sub-page test
In-Reply-To: <39BC08CB3FF4C84CB6397533D4FC7909015DE2F7@SEGOTEXCH02.ascom-Resource.ads>
References: <39BC08CB3FF4C84CB6397533D4FC7909015DDE3F@SEGOTEXCH02.ascom-Resource.ads>
 <1476448883.2342.924.camel@gmail.com>
 <39BC08CB3FF4C84CB6397533D4FC7909015DE2F7@SEGOTEXCH02.ascom-Resource.ads>
Message-ID: <1476455919.2342.950.camel@gmail.com>

On Fri, 2016-10-14 at 14:13 +0000, Danesh Daroui wrote:
> Hi Artem,
> 
> Thanks for your reply. I can unmount the device and run the tests,
> but then how can we make sure whether the problem is in UBI/UBIFS
> layers or only MTD layer? Anyway, if we update the kernel, then both
> MTD drivers and UBI/UBIFS will be updated, am I right?

You are experiencing some issues with UBIFS, I suppose. Naturally, you
want to fix it.

But the SW you are dealing with is sandwich, and you want to narrow
down the problem to a specific layer, if possible.

The first step we usually recommend to do is to start validating the
low level - MTD. You use MTD tests for that. If they fail, you know
there is something wrong at this layer, and you go and fix that. If
they do not fail, the problem is probably somewhere above MTD.

Artem.


From kamal.dasu at broadcom.com  Fri Oct 14 10:42:55 2016
From: kamal.dasu at broadcom.com (Kamal Dasu)
Date: Fri, 14 Oct 2016 13:42:55 -0400
Subject: [PATCH v2,
 1/1] mtd: devices: m25p80: Add PM suspend resume support
In-Reply-To: <1473710494-4084-1-git-send-email-kdasu.kdev@gmail.com>
References: <1473710494-4084-1-git-send-email-kdasu.kdev@gmail.com>
Message-ID: <CAKekbeuFqEXvhWYuPqER3wFA=0pJrSoBZH+9X5zbjjJ=yTuqxA@mail.gmail.com>

Is everyone Ok with the latest patch ?

Kamal

On Mon, Sep 12, 2016 at 4:01 PM, Kamal Dasu <kdasu.kdev at gmail.com> wrote:
> Adding PM support so as to be able to probe spi-nor flash
> on resume. There are vendor specific commands to setup
> the transfer mode and enable read/write as part of
> spi_nor_scan(), done on initial probe and needed on resume().
> The spi-nor structure is private to the m25p driver and hence
> is the only place this can be done without having to duplicate
> code in controller driver.
>
> Signed-off-by: Kamal Dasu <kdasu.kdev at gmail.com>
> ---
>  drivers/mtd/devices/m25p80.c | 68 +++++++++++++++++++++++++++++++-------------
>  1 file changed, 48 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
> index 9cf7fcd..48c3f64 100644
> --- a/drivers/mtd/devices/m25p80.c
> +++ b/drivers/mtd/devices/m25p80.c
> @@ -186,6 +186,39 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
>  }
>
>  /*
> + * scan for spi nor flash vendor parts and setup
> + * read/write mode
> + */
> +static int m25p_nor_flash_scan(struct device *dev)
> +{
> +       struct m25p *flash = dev_get_drvdata(dev);
> +       struct flash_platform_data      *data;
> +       char *flash_name = NULL;
> +       enum read_mode mode = SPI_NOR_NORMAL;
> +
> +       data = dev_get_platdata(dev);
> +
> +       /* For some (historical?) reason many platforms provide two different
> +        * names in flash_platform_data: "name" and "type". Quite often name is
> +        * set to "m25p80" and then "type" provides a real chip name.
> +        * If that's the case, respect "type" and ignore a "name".
> +        */
> +       if (data && data->type)
> +               flash_name = data->type;
> +       else if (!strcmp(flash->spi->modalias, "spi-nor"))
> +               flash_name = NULL; /* auto-detect */
> +       else
> +               flash_name = flash->spi->modalias;
> +
> +       if (flash->spi->mode & SPI_RX_QUAD)
> +               mode = SPI_NOR_QUAD;
> +       else if (flash->spi->mode & SPI_RX_DUAL)
> +               mode = SPI_NOR_DUAL;
> +
> +       return spi_nor_scan(&flash->spi_nor, flash_name, mode);
> +}
> +
> +/*
>   * board specific setup should have ensured the SPI clock used here
>   * matches what the READ command supports, at least until this driver
>   * understands FAST_READ (for clocks over 25 MHz).
> @@ -195,8 +228,6 @@ static int m25p_probe(struct spi_device *spi)
>         struct flash_platform_data      *data;
>         struct m25p *flash;
>         struct spi_nor *nor;
> -       enum read_mode mode = SPI_NOR_NORMAL;
> -       char *flash_name;
>         int ret;
>
>         data = dev_get_platdata(&spi->dev);
> @@ -220,27 +251,11 @@ static int m25p_probe(struct spi_device *spi)
>         spi_set_drvdata(spi, flash);
>         flash->spi = spi;
>
> -       if (spi->mode & SPI_RX_QUAD)
> -               mode = SPI_NOR_QUAD;
> -       else if (spi->mode & SPI_RX_DUAL)
> -               mode = SPI_NOR_DUAL;
> -
>         if (data && data->name)
>                 nor->mtd.name = data->name;
>
> -       /* For some (historical?) reason many platforms provide two different
> -        * names in flash_platform_data: "name" and "type". Quite often name is
> -        * set to "m25p80" and then "type" provides a real chip name.
> -        * If that's the case, respect "type" and ignore a "name".
> -        */
> -       if (data && data->type)
> -               flash_name = data->type;
> -       else if (!strcmp(spi->modalias, "spi-nor"))
> -               flash_name = NULL; /* auto-detect */
> -       else
> -               flash_name = spi->modalias;
> +       ret = m25p_nor_flash_scan(nor->dev);
>
> -       ret = spi_nor_scan(nor, flash_name, mode);
>         if (ret)
>                 return ret;
>
> @@ -248,7 +263,6 @@ static int m25p_probe(struct spi_device *spi)
>                                    data ? data->nr_parts : 0);
>  }
>
> -
>  static int m25p_remove(struct spi_device *spi)
>  {
>         struct m25p     *flash = spi_get_drvdata(spi);
> @@ -319,10 +333,24 @@ static const struct of_device_id m25p_of_table[] = {
>  };
>  MODULE_DEVICE_TABLE(of, m25p_of_table);
>
> +#ifdef CONFIG_PM_SLEEP
> +static int m25p_suspend(struct device *dev)
> +{
> +       return 0;
> +}
> +
> +static int m25p_resume(struct device *dev)
> +{
> +       return m25p_nor_flash_scan(dev);
> +}
> +#endif
> +static SIMPLE_DEV_PM_OPS(m25p_pm_ops, m25p_suspend, m25p_resume);
> +
>  static struct spi_driver m25p80_driver = {
>         .driver = {
>                 .name   = "m25p80",
>                 .of_match_table = m25p_of_table,
> +               .pm     = &m25p_pm_ops,
>         },
>         .id_table       = m25p_ids,
>         .probe  = m25p_probe,
> --
> 1.9.1
>


From moranpig at 163.com  Fri Oct 14 13:34:26 2016
From: moranpig at 163.com (Massimiliano Tretene)
Date: Fri, 14 Oct 2016 23:34:26 +0300
Subject: =?utf-8?B?b2gsIGNoZSBzb3JwcmVzYSE=?=
Message-ID: <0000dcd8d56f$11a519b8$cf4dd49d$@inwind.it>

Salve amico,

Hai sentito la notizia? ? impressionante, ? stata una  vera  sorpresa  per me, ti prego di dare un'occhiata <http://nicoletta.screwtown.com/qdn>

Ci vediamo in giro, Massimiliano Tretene




From colin.king at canonical.com  Sat Oct 15 08:58:32 2016
From: colin.king at canonical.com (Colin King)
Date: Sat, 15 Oct 2016 16:58:32 +0100
Subject: [PATCH] ubi: fix swapped arguments to call to ubi_alloc_aeb
Message-ID: <20161015155832.27538-1-colin.king@canonical.com>

From: Colin Ian King <colin.king at canonical.com>

Static analysis by CoverityScan detected the ec and pnum
arguments are in the wrong order on a call to ubi_alloc_aeb.
Swap the order to fix this.

Fixes: 91f4285fe389a27 ("UBI: provide helpers to allocate and free aeb elements")
Signed-off-by: Colin Ian King <colin.king at canonical.com>
---
 drivers/mtd/ubi/fastmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c
index d6384d9..4eed546 100644
--- a/drivers/mtd/ubi/fastmap.c
+++ b/drivers/mtd/ubi/fastmap.c
@@ -287,7 +287,7 @@ static int update_vol(struct ubi_device *ubi, struct ubi_attach_info *ai,
 
 		/* new_aeb is newer */
 		if (cmp_res & 1) {
-			victim = ubi_alloc_aeb(ai, aeb->ec, aeb->pnum);
+			victim = ubi_alloc_aeb(ai, aeb->pnum aeb->ec);
 			if (!victim)
 				return -ENOMEM;
 
-- 
2.9.3



From colin.king at canonical.com  Sat Oct 15 09:00:11 2016
From: colin.king at canonical.com (Colin King)
Date: Sat, 15 Oct 2016 17:00:11 +0100
Subject: [PATCH][V2] ubi: fix swapped arguments to call to ubi_alloc_aeb
Message-ID: <20161015160011.27600-1-colin.king@canonical.com>

From: Colin Ian King <colin.king at canonical.com>

Static analysis by CoverityScan detected the ec and pnum
arguments are in the wrong order on a call to ubi_alloc_aeb.
Swap the order to fix this.

Fixes: 91f4285fe389a27 ("UBI: provide helpers to allocate and free aeb elements")
Signed-off-by: Colin Ian King <colin.king at canonical.com>
---
 drivers/mtd/ubi/fastmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c
index d6384d9..4eed546 100644
--- a/drivers/mtd/ubi/fastmap.c
+++ b/drivers/mtd/ubi/fastmap.c
@@ -287,7 +287,7 @@ static int update_vol(struct ubi_device *ubi, struct ubi_attach_info *ai,
 
 		/* new_aeb is newer */
 		if (cmp_res & 1) {
-			victim = ubi_alloc_aeb(ai, aeb->ec, aeb->pnum);
+			victim = ubi_alloc_aeb(ai, aeb->pnum, aeb->ec);
 			if (!victim)
 				return -ENOMEM;
 
-- 
2.9.3



From moritz.fischer at ettus.com  Sat Oct 15 15:09:02 2016
From: moritz.fischer at ettus.com (Moritz Fischer)
Date: Sun, 16 Oct 2016 00:09:02 +0200
Subject: [patch 2/2] mtd: spi-nor: Fix some error codes in
 cqspi_setup_flash()
In-Reply-To: <3ebab16e-ddf8-0a4b-aaaf-d5b424720eb2@denx.de>
References: <20161013080857.GC3389@mwanda>
 <3ebab16e-ddf8-0a4b-aaaf-d5b424720eb2@denx.de>
Message-ID: <CAAtXAHey9fxQJ12=xt8jd4ZYTsYLs8s-TJ=YS=ob8CB03mnXpA@mail.gmail.com>

On Fri, Oct 14, 2016 at 9:16 AM, Marek Vasut <marex at denx.de> wrote:
> On 10/13/2016 10:30 AM, Dan Carpenter wrote:
>> We return success or possibly uninitialized values on these error paths
>> instead of proper error codes.
>>
>> Fixes: 140623410536 ("mtd: spi-nor: Add driver for Cadence Quad SPI Flash Controller")
>> Signed-off-by: Dan Carpenter <dan.carpenter at oracle.com>
>>
>
> Nice
>
> Reviewed-by: Marek Vasut <marex at denx.de>
Reviewed-by: Moritz Fischer <moritz.fischer at ettus.com>

Thanks,

Moritz


From boris.brezillon at free-electrons.com  Sun Oct 16 07:35:14 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Sun, 16 Oct 2016 16:35:14 +0200
Subject: [PATCH v2 3/7] mtd: nand: add a nand.h file to expose basic NAND stuff
In-Reply-To: <1476628518-20450-1-git-send-email-boris.brezillon@free-electrons.com>
References: <1476628518-20450-1-git-send-email-boris.brezillon@free-electrons.com>
Message-ID: <1476628518-20450-4-git-send-email-boris.brezillon@free-electrons.com>

Now that raw NAND header has been moved to rawnand.h, we can add a new
nand.h file and define the common nand stuff in there.

Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 include/linux/mtd/nand.h | 480 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 480 insertions(+)
 create mode 100644 include/linux/mtd/nand.h

diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
new file mode 100644
index 000000000000..b9b5d3c1bdf9
--- /dev/null
+++ b/include/linux/mtd/nand.h
@@ -0,0 +1,480 @@
+/*
+ *  Copyright ? 2016 - Boris Brezillon <boris.brezillon at free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_MTD_NAND_H
+#define __LINUX_MTD_NAND_H
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/bbm.h>
+/**
+ * struct nand_memory_organization - memory organization structure
+ * @pagesize: page size
+ * @oobsize: OOB area size
+ * @eraseblocksize: erase block size
+ * @planesize: plane size
+ * @nplanes: number of planes embedded in a die
+ * @diesize: die size
+ * @ndies: number of dies embedded in the device
+ */
+struct nand_memory_organization {
+	int pagesize;
+	int oobsize;
+	int eraseblocksize;
+	size_t planesize;
+	int nplanes;
+	u64 diesize;
+	int ndies;
+};
+
+/**
+ * struct nand_bbt - bad block table structure
+ * @options: bad block specific options
+ * @td: bad block table descriptor for flash lookup.
+ * @md: bad block table mirror descriptor
+ * @bbp: bad block pattern
+ * @bbt: in memory BBT
+ */
+struct nand_bbt {
+	unsigned int options;
+	/*
+	 * Discourage new custom usages here; suggest usage of the
+	 * relevant NAND_BBT_* options instead
+	 */
+	struct nand_bbt_descr *td;
+	struct nand_bbt_descr *md;
+	struct nand_bbt_descr *bbp;
+	u8 *bbt;
+};
+
+struct nand_device;
+
+/**
+ * struct nand_ops - NAND operations
+ * @erase: erase the blocks covered by the erase_info description
+ */
+struct nand_ops {
+	int (*erase)(struct nand_device *nand, struct erase_info *einfo);
+	int (*markbad)(struct nand_device *mtd, int block);
+};
+
+/**
+ * struct nand_device - NAND device
+ * @mtd: MTD instance attached to the NAND device
+ * @memorg: memory layout
+ * @bbt: bad block table info
+ * @ops: NAND operations attached to the NAND device
+ */
+struct nand_device {
+	struct mtd_info mtd;
+	struct nand_memory_organization memorg;
+	struct nand_bbt bbt;
+
+	const struct nand_ops *ops;
+};
+
+/**
+ * mtd_to_nand - Get the NAND device attached to the MTD instance
+ * @mtd: MTD instance
+ *
+ * Returns the NAND device attached to @mtd.
+ */
+static inline struct nand_device *mtd_to_nand(struct mtd_info *mtd)
+{
+	return container_of(mtd, struct nand_device, mtd);
+}
+
+/**
+ * nand_to_mtd - Get the MTD device attached to a NAND device
+ * @nand: NAND device
+ *
+ * Returns the MTD device attached to @nand.
+ */
+static inline struct mtd_info *nand_to_mtd(struct nand_device *nand)
+{
+	return &nand->mtd;
+}
+
+/**
+ * nand_page_to_offs - Convert a page number to an absolute offset
+ * @nand: NAND device
+ * @page: page number
+ *
+ * Returns the offset pointing to the beginning of @page.
+ */
+static inline loff_t nand_page_to_offs(struct nand_device *nand, int page)
+{
+	return (loff_t)nand->memorg.pagesize * page;
+}
+
+/**
+ * nand_offs_to_page - Convert an absolute offset to a page offset
+ * @nand: NAND device
+ * @offs: absolute offset
+ *
+ * Returns the page number containing @offs.
+ */
+static inline int nand_offs_to_page(struct nand_device *nand, loff_t offs)
+{
+	u64 page = offs;
+
+	do_div(page, nand->memorg.pagesize);
+
+	return page;
+}
+
+/**
+ * nand_len_to_pages - Convert a length into a number of pages
+ * @nand: NAND device
+ * @len: length in bytes
+ *
+ * Returns the number of pages required to store @len bytes.
+ * This functions assumes your storing those data at a page-aligned offset.
+ */
+static inline int nand_len_to_pages(struct nand_device *nand, size_t len)
+{
+	return DIV_ROUND_UP(len, nand->memorg.pagesize);
+}
+
+/**
+ * nand_pages_to_len - Convert a number of pages into a length expressed in
+ *		       bytes
+ * @nand: NAND device
+ * @npages: number of pages
+ *
+ * Returns the size taken by @npages pages.
+ */
+static inline size_t nand_pages_to_len(struct nand_device *nand, int npages)
+{
+	return (size_t)npages * nand->memorg.pagesize;
+}
+
+/**
+ * nand_page_size - Get NAND page size
+ * @nand: NAND device
+ *
+ * Returns the page size.
+ */
+static inline size_t nand_page_size(struct nand_device *nand)
+{
+	return nand->memorg.pagesize;
+}
+
+/**
+ * nand_per_page_oobsize - Get NAND OOB size
+ * @nand: NAND device
+ *
+ * Returns the OOB size.
+ */
+static inline int nand_per_page_oobsize(struct nand_device *nand)
+{
+	return nand->memorg.oobsize;
+}
+
+/**
+ * nand_per_page_oobsize - Get NAND erase block size
+ * @nand: NAND device
+ *
+ * Returns the erase block size.
+ */
+static inline size_t nand_eraseblock_size(struct nand_device *nand)
+{
+	return nand->memorg.eraseblocksize;
+}
+
+/**
+ * nand_page_to_offs - Convert an eraseblock number to an absolute offset
+ * @nand: NAND device
+ * @block: eraseblock number
+ *
+ * Returns the offset pointing to the beginning of @block.
+ */
+static inline loff_t nand_eraseblock_to_offs(struct nand_device *nand,
+					     int block)
+{
+	return (loff_t)nand->memorg.eraseblocksize * block;
+}
+
+/**
+ * nand_offs_to_eraseblock - Convert an absolute offset to an eraseblock offset
+ * @nand: NAND device
+ * @offs: absolute offset
+ *
+ * Returns the eraseblock number containing @offs.
+ */
+static inline int nand_offs_to_eraseblock(struct nand_device *nand, loff_t offs)
+{
+	u64 block = offs;
+
+	do_div(block, nand->memorg.eraseblocksize);
+
+	return block;
+}
+
+/**
+ * nand_len_to_eraseblocks - Convert a length into a number of erablocks
+ * @nand: NAND device
+ * @len: length in bytes
+ *
+ * Returns the number of eraseblocks required to store @len bytes.
+ * This functions assumes your storing those data at an eraseblock-aligned
+ * offset.
+ */
+static inline int nand_len_to_eraseblocks(struct nand_device *nand, size_t len)
+{
+	return DIV_ROUND_UP(len, nand->memorg.eraseblocksize);
+}
+
+/**
+ * nand_eraseblocks_to_len - Convert a number of eraseblocks into a length
+ *			     expressed in bytes
+ * @nand: NAND device
+ * @nblocks: number of eraseblocks
+ *
+ * Returns the size taken by @nblock pages.
+ */
+static inline size_t nand_eraseblocks_to_len(struct nand_device *nand, int nblocks)
+{
+	return (size_t)nblocks * nand->memorg.eraseblocksize;
+}
+
+/**
+ * nand_per_eraseblock_oobsize - Get the amount of OOB bytes in an eraseblock
+ * @nand: NAND device
+ *
+ * Returns the OOB size per eraseblock.
+ */
+static inline int nand_per_eraseblock_oobsize(struct nand_device *nand)
+{
+	int pagesperblock = nand->memorg.eraseblocksize /
+			    nand->memorg.pagesize;
+
+	return nand->memorg.oobsize * pagesperblock;
+}
+
+/**
+ * nand_eraseblock_to_page - Convert an eraseblock number to a page number
+ * @nand: NAND device
+ * @block: eraseblock number
+ *
+ * Returns the page number assigned to the first page of @block eraseblock.
+ */
+static inline int nand_eraseblock_to_page(struct nand_device *nand, int block)
+{
+	int pagesperblock = nand->memorg.eraseblocksize /
+			    nand->memorg.pagesize;
+
+	return block * pagesperblock;
+}
+
+/**
+ * nand_page_to_eraseblock - Convert a page number to an eraseblock number
+ * @nand: NAND device
+ * @page: page number
+ *
+ * Returns the eraseblock number containing @page.
+ */
+static inline int nand_page_to_eraseblock(struct nand_device *nand, int page)
+{
+	int pagesperblock = nand->memorg.eraseblocksize /
+			    nand->memorg.pagesize;
+
+	return page / pagesperblock;
+}
+
+/**
+ * nand_eraseblocks_per_die - Get the number of eraseblocks per die
+ * @nand: NAND device
+ *
+ * Returns the number of eraseblocks per die.
+ */
+static inline int nand_eraseblocks_per_die(struct nand_device *nand)
+{
+	u64 nblocks = nand->memorg.diesize;
+
+	do_div(nblocks, nand->memorg.eraseblocksize);
+
+	return nblocks;
+}
+
+/**
+ * nand_eraseblocks_per_die - Get the number of eraseblocks per die
+ * @nand: NAND device
+ *
+ * Returns the number of eraseblocks per die.
+ */
+static inline u64 nand_diesize(struct nand_device *nand)
+{
+	return nand->memorg.diesize;
+}
+
+/**
+ * nand_ndies - Get the total of dies
+ * @nand: NAND device
+ *
+ * Returns the number of dies exposed by @nand.
+ */
+static inline int nand_ndies(struct nand_device *nand)
+{
+	return nand->memorg.ndies;
+}
+
+/**
+ * nand_die_to_offs - Convert a die number to an absolute offset
+ * @nand: NAND device
+ * @die: die number
+ *
+ * Returns the offset pointing to the beginning of @die.
+ */
+static inline loff_t nand_die_to_offs(struct nand_device *nand, int die)
+{
+	return (loff_t)nand->memorg.diesize * die;
+}
+
+/**
+ * nand_offs_to_die - Convert an absolute offset to a die number
+ * @nand: NAND device
+ * @offs: absolute offset
+ *
+ * Returns the die number containing @offs.
+ */
+static inline int nand_offs_to_die(struct nand_device *nand, loff_t offs)
+{
+	u64 die = offs;
+
+	do_div(die, nand->memorg.diesize);
+
+	return die;
+}
+
+/**
+ * nand_ndies - Get the total number of erasablocks
+ * @nand: NAND device
+ *
+ * Returns the number of eraseblocks exposed by @nand.
+ */
+static inline int nand_neraseblocks(struct nand_device *nand)
+{
+	u64 nblocks = nand->memorg.ndies * nand->memorg.diesize;
+
+	do_div(nblocks, nand->memorg.eraseblocksize);
+
+	return nblocks;
+}
+
+/**
+ * nand_register - Register a NAND device
+ * @nand: NAND device
+ *
+ * Register a NAND device.
+ * This function is just a wrapper around mtd_device_register()
+ * registering the MTD device attached to @nand.
+ */
+static inline int nand_register(struct nand_device *nand)
+{
+	return mtd_device_register(&nand->mtd, NULL, 0);
+}
+
+/**
+ * nand_unregister - Unregister a NAND device
+ * @nand: NAND device
+ *
+ * Unregister a NAND device.
+ * This function is just a wrapper around mtd_device_unregister()
+ * unregistering the MTD device attached to @nand.
+ */
+static inline void nand_unregister(struct nand_device *nand)
+{
+	mtd_device_unregister(&nand->mtd);
+}
+
+/**
+ * nand_read - Read data from NAND
+ * @nand: NAND device
+ * @offs: offset you want to read data from
+ * @ops: options describing what you want to read (in-band/out-of-band data)
+ *	 and how (raw or normal mode)
+ *
+ * Read data from NAND.
+ */
+static inline int nand_read(struct nand_device *nand, loff_t offs,
+			    struct mtd_oob_ops *ops)
+{
+	return mtd_read_oob(&nand->mtd, offs, ops);
+}
+
+/**
+ * nand_write - Write data to NAND
+ * @nand: NAND device
+ * @offs: offset you want to write data to
+ * @ops: options describing what you want to write (in-band/out-of-band data)
+ *	 and how (raw or normal mode)
+ *
+ * Read data from NAND.
+ */
+static inline int nand_write(struct nand_device *nand, loff_t offs,
+			     struct mtd_oob_ops *ops)
+{
+	return mtd_write_oob(&nand->mtd, offs, ops);
+}
+
+/**
+ * nand_erase - Erase a NAND portion
+ * @nand: NAND device
+ * @einfo: erase information
+ * @force: whether bad or protected blocks should be erased or not
+ *
+ * Erase the NAND portion described by @einfo. If @force is passed, bad and
+ * reserved block checking is bypassed and the implementation is asked to
+ * force the erasure.
+ */
+static inline int nand_erase(struct nand_device *nand,
+			     struct erase_info *einfo,
+			     bool force)
+{
+	if (!force)
+		return mtd_erase(&nand->mtd, einfo);
+
+	return nand->ops->erase(nand, einfo);
+}
+
+/**
+ * nand_markbad - Write a bad block marker to a block
+ * @nand: NAND device
+ * @block: block to mark bad
+ *
+ * Mark a block bad. This function is not using the BBT.
+ */
+static inline int nand_markbad(struct nand_device *nand, int block)
+{
+	return nand->ops->markbad(nand, block);
+}
+
+/**
+ * nand_set_of_node - Attach a DT node to a NAND device
+ * @nand: NAND device
+ * @np: DT node
+ *
+ * Attach a DT node to a NAND device.
+ */
+static inline void nand_set_of_node(struct nand_device *nand,
+				    struct device_node *np)
+{
+	mtd_set_of_node(&nand->mtd, np);
+}
+
+/**
+ * nand_get_of_node - Retrieve the DT node attached a NAND device
+ * @nand: NAND device
+ *
+ * Returns the DT node attached to @nand.
+ */
+static inline struct device_node *nand_get_of_node(struct nand_device *nand)
+{
+	return mtd_get_of_node(&nand->mtd);
+}
+#endif /* __LINUX_MTD_NAND_H */
-- 
2.7.4



From boris.brezillon at free-electrons.com  Sun Oct 16 07:35:11 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Sun, 16 Oct 2016 16:35:11 +0200
Subject: [PATCH v2 0/7] mtd: nand: Abstract away the NAND interface type
Message-ID: <1476628518-20450-1-git-send-email-boris.brezillon@free-electrons.com>

Hi,

This series is aiming at providing a generic NAND layer to share code
between different NAND based devices.

We currently have 3 different interfaces to interact with NANDs:
- Raw NANDs
- OneNANDs
- SPI NANDs

Apart from the way these NAND devices are accessed they have a lot
in common, like the way the memory is organized, or their constraints.
This is usually a good sign that some work should be done to factorize
the code.

This work has been started by Peter who wanted to re-use the BBT
code for its SPI-NAND driver. But I think we can push it further
other stuff (the software ECC implementation, or the way offsets are
converted to block/page number).

Peter, can you please review/test this version, and if possible, post
the code you've done to support SPI NANDs.

Thanks,

Boris

Changes since v1:
- use the 'raw' prefix instead of 'rawnand'
- fix a few coding style issues and typos

Boris Brezillon (7):
  mtd: nand: Rename nand.h into rawnand.h
  mtd: nand: move raw NAND related code to the raw/ subdir
  mtd: nand: add a nand.h file to expose basic NAND stuff
  mtd: nand: raw: prefix conflicting names with nandc instead of nand
  mtd: nand: raw: create struct rawnand_device
  mtd: nand: raw: make BBT code more generic
  mtd: nand: move BBT code to drivers/mtd/nand/

 Documentation/DocBook/mtdnand.tmpl                 |   12 +-
 arch/arm/mach-davinci/board-da850-evm.c            |    2 +-
 arch/arm/mach-davinci/board-dm355-evm.c            |    2 +-
 arch/arm/mach-davinci/board-dm355-leopard.c        |    2 +-
 arch/arm/mach-davinci/board-dm365-evm.c            |    2 +-
 arch/arm/mach-davinci/board-dm644x-evm.c           |    2 +-
 arch/arm/mach-davinci/board-dm646x-evm.c           |    2 +-
 arch/arm/mach-davinci/board-sffsdr.c               |    2 +-
 arch/arm/mach-dove/dove-db-setup.c                 |    2 +-
 arch/arm/mach-ep93xx/snappercl15.c                 |    6 +-
 arch/arm/mach-ep93xx/ts72xx.c                      |    6 +-
 arch/arm/mach-imx/mach-qong.c                      |    4 +-
 arch/arm/mach-ixp4xx/ixdp425-setup.c               |    4 +-
 arch/arm/mach-mmp/aspenite.c                       |    2 +-
 arch/arm/mach-omap1/board-fsample.c                |    2 +-
 arch/arm/mach-omap1/board-h2.c                     |    2 +-
 arch/arm/mach-omap1/board-h3.c                     |    2 +-
 arch/arm/mach-omap1/board-nand.c                   |    4 +-
 arch/arm/mach-omap1/board-perseus2.c               |    2 +-
 arch/arm/mach-omap2/gpmc-nand.c                    |    2 +-
 arch/arm/mach-orion5x/db88f5281-setup.c            |    2 +-
 arch/arm/mach-orion5x/kurobox_pro-setup.c          |    2 +-
 arch/arm/mach-orion5x/ts209-setup.c                |    2 +-
 arch/arm/mach-orion5x/ts78xx-setup.c               |    8 +-
 arch/arm/mach-pxa/balloon3.c                       |    4 +-
 arch/arm/mach-pxa/em-x270.c                        |    4 +-
 arch/arm/mach-pxa/eseries.c                        |    2 +-
 arch/arm/mach-pxa/palmtx.c                         |    4 +-
 arch/arm/mach-pxa/tosa.c                           |    2 +-
 arch/arm/mach-s3c24xx/common-smdk.c                |    2 +-
 arch/arm/mach-s3c24xx/mach-anubis.c                |    2 +-
 arch/arm/mach-s3c24xx/mach-at2440evb.c             |    2 +-
 arch/arm/mach-s3c24xx/mach-bast.c                  |    2 +-
 arch/arm/mach-s3c24xx/mach-gta02.c                 |    2 +-
 arch/arm/mach-s3c24xx/mach-jive.c                  |    2 +-
 arch/arm/mach-s3c24xx/mach-mini2440.c              |    2 +-
 arch/arm/mach-s3c24xx/mach-osiris.c                |    2 +-
 arch/arm/mach-s3c24xx/mach-qt2410.c                |    2 +-
 arch/arm/mach-s3c24xx/mach-rx3715.c                |    2 +-
 arch/arm/mach-s3c24xx/mach-vstms.c                 |    2 +-
 arch/blackfin/mach-bf537/boards/dnp5370.c          |    2 +-
 arch/blackfin/mach-bf537/boards/stamp.c            |    4 +-
 arch/blackfin/mach-bf561/boards/acvilon.c          |    4 +-
 arch/cris/arch-v32/drivers/mach-a3/nandflash.c     |    6 +-
 arch/cris/arch-v32/drivers/mach-fs/nandflash.c     |    6 +-
 arch/mips/alchemy/devboards/db1200.c               |    4 +-
 arch/mips/alchemy/devboards/db1300.c               |    4 +-
 arch/mips/alchemy/devboards/db1550.c               |    4 +-
 arch/mips/include/asm/mach-jz4740/jz4740_nand.h    |    2 +-
 arch/mips/jz4740/board-qi_lb60.c                   |    2 +-
 arch/mips/netlogic/xlr/platform-flash.c            |    2 +-
 arch/mips/pnx833x/common/platform.c                |    4 +-
 arch/mips/rb532/devices.c                          |    4 +-
 arch/sh/boards/mach-migor/setup.c                  |    4 +-
 drivers/mtd/inftlcore.c                            |    2 +-
 drivers/mtd/nand/Kconfig                           |  572 +-------
 drivers/mtd/nand/Makefile                          |   63 +-
 drivers/mtd/nand/{nand_bbt.c => bbt.c}             |  616 ++++-----
 drivers/mtd/nand/raw/Kconfig                       |  573 ++++++++
 drivers/mtd/nand/raw/Makefile                      |   62 +
 drivers/mtd/nand/{ => raw}/ams-delta.c             |   10 +-
 drivers/mtd/nand/{ => raw}/atmel_nand.c            |   62 +-
 drivers/mtd/nand/{ => raw}/atmel_nand_ecc.h        |    0
 drivers/mtd/nand/{ => raw}/atmel_nand_nfc.h        |    0
 drivers/mtd/nand/{ => raw}/au1550nd.c              |   28 +-
 drivers/mtd/nand/{ => raw}/bcm47xxnflash/Makefile  |    0
 .../nand/{ => raw}/bcm47xxnflash/bcm47xxnflash.h   |    2 +-
 drivers/mtd/nand/{ => raw}/bcm47xxnflash/main.c    |    4 +-
 .../mtd/nand/{ => raw}/bcm47xxnflash/ops_bcm4706.c |   18 +-
 drivers/mtd/nand/{ => raw}/bf5xx_nand.c            |   34 +-
 drivers/mtd/nand/{ => raw}/brcmnand/Makefile       |    0
 .../mtd/nand/{ => raw}/brcmnand/bcm63138_nand.c    |    0
 drivers/mtd/nand/{ => raw}/brcmnand/bcm6368_nand.c |    0
 drivers/mtd/nand/{ => raw}/brcmnand/brcmnand.c     |   34 +-
 drivers/mtd/nand/{ => raw}/brcmnand/brcmnand.h     |    0
 drivers/mtd/nand/{ => raw}/brcmnand/brcmstb_nand.c |    0
 drivers/mtd/nand/{ => raw}/brcmnand/iproc_nand.c   |    0
 drivers/mtd/nand/{ => raw}/cafe_nand.c             |   26 +-
 drivers/mtd/nand/{ => raw}/cmx270_nand.c           |   14 +-
 drivers/mtd/nand/{ => raw}/cs553x_nand.c           |   22 +-
 drivers/mtd/nand/{ => raw}/davinci_nand.c          |   16 +-
 drivers/mtd/nand/{ => raw}/denali.c                |   12 +-
 drivers/mtd/nand/{ => raw}/denali.h                |    2 +-
 drivers/mtd/nand/{ => raw}/denali_dt.c             |    0
 drivers/mtd/nand/{ => raw}/denali_pci.c            |    0
 drivers/mtd/nand/{ => raw}/diskonchip.c            |   70 +-
 drivers/mtd/nand/{ => raw}/docg4.c                 |   38 +-
 drivers/mtd/nand/{ => raw}/fsl_elbc_nand.c         |   28 +-
 drivers/mtd/nand/{ => raw}/fsl_ifc_nand.c          |   30 +-
 drivers/mtd/nand/{ => raw}/fsl_upm.c               |   14 +-
 drivers/mtd/nand/{ => raw}/fsmc_nand.c             |   26 +-
 drivers/mtd/nand/{ => raw}/gpio.c                  |    8 +-
 drivers/mtd/nand/{ => raw}/gpmi-nand/Makefile      |    0
 drivers/mtd/nand/{ => raw}/gpmi-nand/bch-regs.h    |    0
 drivers/mtd/nand/{ => raw}/gpmi-nand/gpmi-lib.c    |    2 +-
 drivers/mtd/nand/{ => raw}/gpmi-nand/gpmi-nand.c   |   38 +-
 drivers/mtd/nand/{ => raw}/gpmi-nand/gpmi-nand.h   |    2 +-
 drivers/mtd/nand/{ => raw}/gpmi-nand/gpmi-regs.h   |    0
 drivers/mtd/nand/{ => raw}/hisi504_nand.c          |   26 +-
 drivers/mtd/nand/{ => raw}/jz4740_nand.c           |   14 +-
 drivers/mtd/nand/{ => raw}/jz4780_bch.c            |    0
 drivers/mtd/nand/{ => raw}/jz4780_bch.h            |    0
 drivers/mtd/nand/{ => raw}/jz4780_nand.c           |   10 +-
 drivers/mtd/nand/{ => raw}/lpc32xx_mlc.c           |   18 +-
 drivers/mtd/nand/{ => raw}/lpc32xx_slc.c           |   22 +-
 drivers/mtd/nand/{ => raw}/mpc5121_nfc.c           |   28 +-
 drivers/mtd/nand/{ => raw}/mtk_ecc.c               |    0
 drivers/mtd/nand/{ => raw}/mtk_ecc.h               |    0
 drivers/mtd/nand/{ => raw}/mtk_nand.c              |   40 +-
 drivers/mtd/nand/{ => raw}/mxc_nand.c              |   54 +-
 drivers/mtd/nand/{ => raw}/nand_base.c             |  238 +++-
 drivers/mtd/nand/{ => raw}/nand_bch.c              |    8 +-
 drivers/mtd/nand/{ => raw}/nand_ecc.c              |    6 +-
 drivers/mtd/nand/{ => raw}/nand_ids.c              |    2 +-
 drivers/mtd/nand/{ => raw}/nand_timings.c          |    2 +-
 drivers/mtd/nand/{ => raw}/nandsim.c               |   24 +-
 drivers/mtd/nand/{ => raw}/ndfc.c                  |   20 +-
 drivers/mtd/nand/{ => raw}/nuc900_nand.c           |   10 +-
 drivers/mtd/nand/{ => raw}/omap2.c                 |   22 +-
 drivers/mtd/nand/{ => raw}/omap_elm.c              |    0
 drivers/mtd/nand/{ => raw}/orion_nand.c            |    8 +-
 drivers/mtd/nand/{ => raw}/pasemi_nand.c           |   12 +-
 drivers/mtd/nand/{ => raw}/plat_nand.c             |    6 +-
 drivers/mtd/nand/{ => raw}/pxa3xx_nand.c           |   38 +-
 drivers/mtd/nand/{ => raw}/qcom_nandc.c            |   30 +-
 drivers/mtd/nand/{ => raw}/r852.c                  |    8 +-
 drivers/mtd/nand/{ => raw}/r852.h                  |    2 +-
 drivers/mtd/nand/{ => raw}/s3c2410.c               |   18 +-
 drivers/mtd/nand/{ => raw}/sh_flctl.c              |   12 +-
 drivers/mtd/nand/{ => raw}/sharpsl.c               |   10 +-
 drivers/mtd/nand/{ => raw}/sm_common.c             |    4 +-
 drivers/mtd/nand/{ => raw}/sm_common.h             |    0
 drivers/mtd/nand/{ => raw}/socrates_nand.c         |   14 +-
 drivers/mtd/nand/{ => raw}/sunxi_nand.c            |   60 +-
 drivers/mtd/nand/{ => raw}/tmio_nand.c             |   10 +-
 drivers/mtd/nand/{ => raw}/txx9ndfmc.c             |   16 +-
 drivers/mtd/nand/{ => raw}/vf610_nfc.c             |    6 +-
 drivers/mtd/nand/{ => raw}/xway_nand.c             |   12 +-
 drivers/mtd/nftlcore.c                             |    2 +-
 drivers/mtd/nftlmount.c                            |    2 +-
 drivers/mtd/sm_ftl.c                               |    2 +-
 drivers/mtd/ssfdc.c                                |    2 +-
 drivers/mtd/tests/nandbiterrs.c                    |    2 +-
 drivers/staging/mt29f_spinand/mt29f_spinand.c      |    8 +-
 fs/jffs2/wbuf.c                                    |    2 +-
 include/linux/mtd/nand-gpio.h                      |    2 +-
 include/linux/mtd/nand.h                           | 1424 +++++---------------
 include/linux/mtd/rawnand.h                        | 1200 +++++++++++++++++
 include/linux/mtd/sh_flctl.h                       |    4 +-
 include/linux/mtd/sharpsl.h                        |    2 +-
 include/linux/platform_data/atmel.h                |    2 +-
 include/linux/platform_data/mtd-davinci.h          |    2 +-
 152 files changed, 3316 insertions(+), 2746 deletions(-)
 rename drivers/mtd/nand/{nand_bbt.c => bbt.c} (72%)
 create mode 100644 drivers/mtd/nand/raw/Kconfig
 create mode 100644 drivers/mtd/nand/raw/Makefile
 rename drivers/mtd/nand/{ => raw}/ams-delta.c (97%)
 rename drivers/mtd/nand/{ => raw}/atmel_nand.c (97%)
 rename drivers/mtd/nand/{ => raw}/atmel_nand_ecc.h (100%)
 rename drivers/mtd/nand/{ => raw}/atmel_nand_nfc.h (100%)
 rename drivers/mtd/nand/{ => raw}/au1550nd.c (95%)
 rename drivers/mtd/nand/{ => raw}/bcm47xxnflash/Makefile (100%)
 rename drivers/mtd/nand/{ => raw}/bcm47xxnflash/bcm47xxnflash.h (92%)
 rename drivers/mtd/nand/{ => raw}/bcm47xxnflash/main.c (95%)
 rename drivers/mtd/nand/{ => raw}/bcm47xxnflash/ops_bcm4706.c (96%)
 rename drivers/mtd/nand/{ => raw}/bf5xx_nand.c (95%)
 rename drivers/mtd/nand/{ => raw}/brcmnand/Makefile (100%)
 rename drivers/mtd/nand/{ => raw}/brcmnand/bcm63138_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/brcmnand/bcm6368_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/brcmnand/brcmnand.c (98%)
 rename drivers/mtd/nand/{ => raw}/brcmnand/brcmnand.h (100%)
 rename drivers/mtd/nand/{ => raw}/brcmnand/brcmstb_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/brcmnand/iproc_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/cafe_nand.c (97%)
 rename drivers/mtd/nand/{ => raw}/cmx270_nand.c (94%)
 rename drivers/mtd/nand/{ => raw}/cs553x_nand.c (95%)
 rename drivers/mtd/nand/{ => raw}/davinci_nand.c (98%)
 rename drivers/mtd/nand/{ => raw}/denali.c (99%)
 rename drivers/mtd/nand/{ => raw}/denali.h (99%)
 rename drivers/mtd/nand/{ => raw}/denali_dt.c (100%)
 rename drivers/mtd/nand/{ => raw}/denali_pci.c (100%)
 rename drivers/mtd/nand/{ => raw}/diskonchip.c (96%)
 rename drivers/mtd/nand/{ => raw}/docg4.c (98%)
 rename drivers/mtd/nand/{ => raw}/fsl_elbc_nand.c (97%)
 rename drivers/mtd/nand/{ => raw}/fsl_ifc_nand.c (97%)
 rename drivers/mtd/nand/{ => raw}/fsl_upm.c (96%)
 rename drivers/mtd/nand/{ => raw}/fsmc_nand.c (97%)
 rename drivers/mtd/nand/{ => raw}/gpio.c (97%)
 rename drivers/mtd/nand/{ => raw}/gpmi-nand/Makefile (100%)
 rename drivers/mtd/nand/{ => raw}/gpmi-nand/bch-regs.h (100%)
 rename drivers/mtd/nand/{ => raw}/gpmi-nand/gpmi-lib.c (99%)
 rename drivers/mtd/nand/{ => raw}/gpmi-nand/gpmi-nand.c (98%)
 rename drivers/mtd/nand/{ => raw}/gpmi-nand/gpmi-nand.h (99%)
 rename drivers/mtd/nand/{ => raw}/gpmi-nand/gpmi-regs.h (100%)
 rename drivers/mtd/nand/{ => raw}/hisi504_nand.c (97%)
 rename drivers/mtd/nand/{ => raw}/jz4740_nand.c (97%)
 rename drivers/mtd/nand/{ => raw}/jz4780_bch.c (100%)
 rename drivers/mtd/nand/{ => raw}/jz4780_bch.h (100%)
 rename drivers/mtd/nand/{ => raw}/jz4780_nand.c (97%)
 rename drivers/mtd/nand/{ => raw}/lpc32xx_mlc.c (98%)
 rename drivers/mtd/nand/{ => raw}/lpc32xx_slc.c (98%)
 rename drivers/mtd/nand/{ => raw}/mpc5121_nfc.c (97%)
 rename drivers/mtd/nand/{ => raw}/mtk_ecc.c (100%)
 rename drivers/mtd/nand/{ => raw}/mtk_ecc.h (100%)
 rename drivers/mtd/nand/{ => raw}/mtk_nand.c (97%)
 rename drivers/mtd/nand/{ => raw}/mxc_nand.c (97%)
 rename drivers/mtd/nand/{ => raw}/nand_base.c (95%)
 rename drivers/mtd/nand/{ => raw}/nand_bch.c (97%)
 rename drivers/mtd/nand/{ => raw}/nand_ecc.c (99%)
 rename drivers/mtd/nand/{ => raw}/nand_ids.c (99%)
 rename drivers/mtd/nand/{ => raw}/nand_timings.c (99%)
 rename drivers/mtd/nand/{ => raw}/nandsim.c (99%)
 rename drivers/mtd/nand/{ => raw}/ndfc.c (93%)
 rename drivers/mtd/nand/{ => raw}/nuc900_nand.c (96%)
 rename drivers/mtd/nand/{ => raw}/omap2.c (99%)
 rename drivers/mtd/nand/{ => raw}/omap_elm.c (100%)
 rename drivers/mtd/nand/{ => raw}/orion_nand.c (97%)
 rename drivers/mtd/nand/{ => raw}/pasemi_nand.c (95%)
 rename drivers/mtd/nand/{ => raw}/plat_nand.c (97%)
 rename drivers/mtd/nand/{ => raw}/pxa3xx_nand.c (98%)
 rename drivers/mtd/nand/{ => raw}/qcom_nandc.c (98%)
 rename drivers/mtd/nand/{ => raw}/r852.c (99%)
 rename drivers/mtd/nand/{ => raw}/r852.h (99%)
 rename drivers/mtd/nand/{ => raw}/s3c2410.c (98%)
 rename drivers/mtd/nand/{ => raw}/sh_flctl.c (99%)
 rename drivers/mtd/nand/{ => raw}/sharpsl.c (96%)
 rename drivers/mtd/nand/{ => raw}/sm_common.c (98%)
 rename drivers/mtd/nand/{ => raw}/sm_common.h (100%)
 rename drivers/mtd/nand/{ => raw}/socrates_nand.c (94%)
 rename drivers/mtd/nand/{ => raw}/sunxi_nand.c (97%)
 rename drivers/mtd/nand/{ => raw}/tmio_nand.c (98%)
 rename drivers/mtd/nand/{ => raw}/txx9ndfmc.c (97%)
 rename drivers/mtd/nand/{ => raw}/vf610_nfc.c (99%)
 rename drivers/mtd/nand/{ => raw}/xway_nand.c (96%)
 create mode 100644 include/linux/mtd/rawnand.h

-- 
2.7.4



From boris.brezillon at free-electrons.com  Sun Oct 16 07:35:12 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Sun, 16 Oct 2016 16:35:12 +0200
Subject: [PATCH v2 1/7] mtd: nand: Rename nand.h into rawnand.h
In-Reply-To: <1476628518-20450-1-git-send-email-boris.brezillon@free-electrons.com>
References: <1476628518-20450-1-git-send-email-boris.brezillon@free-electrons.com>
Message-ID: <1476628518-20450-2-git-send-email-boris.brezillon@free-electrons.com>

We are planning to share more code between different NAND based
devices (SPI NAND, OneNAND and raw NANDs), but before doing that
we need to move the existing include/linux/mtd/nand.h file into
include/linux/mtd/rawnand.h so we can later create a nand.h header
containing all common structure and function prototypes.

Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 Documentation/DocBook/mtdnand.tmpl              | 2 +-
 arch/arm/mach-davinci/board-da850-evm.c         | 2 +-
 arch/arm/mach-davinci/board-dm355-evm.c         | 2 +-
 arch/arm/mach-davinci/board-dm355-leopard.c     | 2 +-
 arch/arm/mach-davinci/board-dm365-evm.c         | 2 +-
 arch/arm/mach-davinci/board-dm644x-evm.c        | 2 +-
 arch/arm/mach-davinci/board-dm646x-evm.c        | 2 +-
 arch/arm/mach-davinci/board-sffsdr.c            | 2 +-
 arch/arm/mach-dove/dove-db-setup.c              | 2 +-
 arch/arm/mach-ep93xx/snappercl15.c              | 2 +-
 arch/arm/mach-ep93xx/ts72xx.c                   | 2 +-
 arch/arm/mach-imx/mach-qong.c                   | 2 +-
 arch/arm/mach-ixp4xx/ixdp425-setup.c            | 2 +-
 arch/arm/mach-mmp/aspenite.c                    | 2 +-
 arch/arm/mach-omap1/board-fsample.c             | 2 +-
 arch/arm/mach-omap1/board-h2.c                  | 2 +-
 arch/arm/mach-omap1/board-h3.c                  | 2 +-
 arch/arm/mach-omap1/board-nand.c                | 2 +-
 arch/arm/mach-omap1/board-perseus2.c            | 2 +-
 arch/arm/mach-omap2/gpmc-nand.c                 | 2 +-
 arch/arm/mach-orion5x/db88f5281-setup.c         | 2 +-
 arch/arm/mach-orion5x/kurobox_pro-setup.c       | 2 +-
 arch/arm/mach-orion5x/ts209-setup.c             | 2 +-
 arch/arm/mach-orion5x/ts78xx-setup.c            | 2 +-
 arch/arm/mach-pxa/balloon3.c                    | 2 +-
 arch/arm/mach-pxa/em-x270.c                     | 2 +-
 arch/arm/mach-pxa/eseries.c                     | 2 +-
 arch/arm/mach-pxa/palmtx.c                      | 2 +-
 arch/arm/mach-pxa/tosa.c                        | 2 +-
 arch/arm/mach-s3c24xx/common-smdk.c             | 2 +-
 arch/arm/mach-s3c24xx/mach-anubis.c             | 2 +-
 arch/arm/mach-s3c24xx/mach-at2440evb.c          | 2 +-
 arch/arm/mach-s3c24xx/mach-bast.c               | 2 +-
 arch/arm/mach-s3c24xx/mach-gta02.c              | 2 +-
 arch/arm/mach-s3c24xx/mach-jive.c               | 2 +-
 arch/arm/mach-s3c24xx/mach-mini2440.c           | 2 +-
 arch/arm/mach-s3c24xx/mach-osiris.c             | 2 +-
 arch/arm/mach-s3c24xx/mach-qt2410.c             | 2 +-
 arch/arm/mach-s3c24xx/mach-rx3715.c             | 2 +-
 arch/arm/mach-s3c24xx/mach-vstms.c              | 2 +-
 arch/blackfin/mach-bf537/boards/dnp5370.c       | 2 +-
 arch/blackfin/mach-bf537/boards/stamp.c         | 2 +-
 arch/blackfin/mach-bf561/boards/acvilon.c       | 2 +-
 arch/cris/arch-v32/drivers/mach-a3/nandflash.c  | 2 +-
 arch/cris/arch-v32/drivers/mach-fs/nandflash.c  | 2 +-
 arch/mips/alchemy/devboards/db1200.c            | 2 +-
 arch/mips/alchemy/devboards/db1300.c            | 2 +-
 arch/mips/alchemy/devboards/db1550.c            | 2 +-
 arch/mips/include/asm/mach-jz4740/jz4740_nand.h | 2 +-
 arch/mips/netlogic/xlr/platform-flash.c         | 2 +-
 arch/mips/pnx833x/common/platform.c             | 2 +-
 arch/mips/rb532/devices.c                       | 2 +-
 arch/sh/boards/mach-migor/setup.c               | 2 +-
 drivers/mtd/inftlcore.c                         | 2 +-
 drivers/mtd/nand/ams-delta.c                    | 2 +-
 drivers/mtd/nand/atmel_nand.c                   | 2 +-
 drivers/mtd/nand/au1550nd.c                     | 2 +-
 drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h  | 2 +-
 drivers/mtd/nand/bf5xx_nand.c                   | 2 +-
 drivers/mtd/nand/brcmnand/brcmnand.c            | 2 +-
 drivers/mtd/nand/cafe_nand.c                    | 2 +-
 drivers/mtd/nand/cmx270_nand.c                  | 2 +-
 drivers/mtd/nand/cs553x_nand.c                  | 2 +-
 drivers/mtd/nand/davinci_nand.c                 | 2 +-
 drivers/mtd/nand/denali.h                       | 2 +-
 drivers/mtd/nand/diskonchip.c                   | 2 +-
 drivers/mtd/nand/docg4.c                        | 2 +-
 drivers/mtd/nand/fsl_elbc_nand.c                | 2 +-
 drivers/mtd/nand/fsl_ifc_nand.c                 | 2 +-
 drivers/mtd/nand/fsl_upm.c                      | 2 +-
 drivers/mtd/nand/fsmc_nand.c                    | 2 +-
 drivers/mtd/nand/gpio.c                         | 2 +-
 drivers/mtd/nand/gpmi-nand/gpmi-nand.h          | 2 +-
 drivers/mtd/nand/hisi504_nand.c                 | 2 +-
 drivers/mtd/nand/jz4740_nand.c                  | 2 +-
 drivers/mtd/nand/jz4780_nand.c                  | 2 +-
 drivers/mtd/nand/lpc32xx_mlc.c                  | 2 +-
 drivers/mtd/nand/lpc32xx_slc.c                  | 2 +-
 drivers/mtd/nand/mpc5121_nfc.c                  | 2 +-
 drivers/mtd/nand/mtk_nand.c                     | 2 +-
 drivers/mtd/nand/mxc_nand.c                     | 2 +-
 drivers/mtd/nand/nand_base.c                    | 2 +-
 drivers/mtd/nand/nand_bbt.c                     | 2 +-
 drivers/mtd/nand/nand_bch.c                     | 2 +-
 drivers/mtd/nand/nand_ecc.c                     | 2 +-
 drivers/mtd/nand/nand_ids.c                     | 2 +-
 drivers/mtd/nand/nand_timings.c                 | 2 +-
 drivers/mtd/nand/nandsim.c                      | 2 +-
 drivers/mtd/nand/ndfc.c                         | 2 +-
 drivers/mtd/nand/nuc900_nand.c                  | 2 +-
 drivers/mtd/nand/omap2.c                        | 2 +-
 drivers/mtd/nand/orion_nand.c                   | 2 +-
 drivers/mtd/nand/pasemi_nand.c                  | 2 +-
 drivers/mtd/nand/plat_nand.c                    | 2 +-
 drivers/mtd/nand/pxa3xx_nand.c                  | 2 +-
 drivers/mtd/nand/qcom_nandc.c                   | 2 +-
 drivers/mtd/nand/r852.h                         | 2 +-
 drivers/mtd/nand/s3c2410.c                      | 2 +-
 drivers/mtd/nand/sh_flctl.c                     | 2 +-
 drivers/mtd/nand/sharpsl.c                      | 2 +-
 drivers/mtd/nand/sm_common.c                    | 2 +-
 drivers/mtd/nand/socrates_nand.c                | 2 +-
 drivers/mtd/nand/sunxi_nand.c                   | 2 +-
 drivers/mtd/nand/tmio_nand.c                    | 2 +-
 drivers/mtd/nand/txx9ndfmc.c                    | 2 +-
 drivers/mtd/nand/vf610_nfc.c                    | 2 +-
 drivers/mtd/nand/xway_nand.c                    | 2 +-
 drivers/mtd/nftlcore.c                          | 2 +-
 drivers/mtd/nftlmount.c                         | 2 +-
 drivers/mtd/ssfdc.c                             | 2 +-
 drivers/mtd/tests/nandbiterrs.c                 | 2 +-
 drivers/staging/mt29f_spinand/mt29f_spinand.c   | 2 +-
 fs/jffs2/wbuf.c                                 | 2 +-
 include/linux/mtd/nand-gpio.h                   | 2 +-
 include/linux/mtd/{nand.h => rawnand.h}         | 8 +++-----
 include/linux/mtd/sh_flctl.h                    | 2 +-
 include/linux/mtd/sharpsl.h                     | 2 +-
 include/linux/platform_data/atmel.h             | 2 +-
 include/linux/platform_data/mtd-davinci.h       | 2 +-
 119 files changed, 121 insertions(+), 123 deletions(-)
 rename include/linux/mtd/{nand.h => rawnand.h} (99%)

diff --git a/Documentation/DocBook/mtdnand.tmpl b/Documentation/DocBook/mtdnand.tmpl
index b442921bca54..35ec7155faa3 100644
--- a/Documentation/DocBook/mtdnand.tmpl
+++ b/Documentation/DocBook/mtdnand.tmpl
@@ -1239,7 +1239,7 @@ in this page</entry>
      struct member has a short description which is marked with an [XXX] identifier.
      See the chapter "Documentation hints" for an explanation.
      </para>
-!Iinclude/linux/mtd/nand.h
+!Iinclude/linux/mtd/rawnand.h
   </chapter>
 
   <chapter id="pubfunctions">
diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index 8e4539f69fdc..02ec0add04e0 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -24,7 +24,7 @@
 #include <linux/input/tps6507x-ts.h>
 #include <linux/mfd/tps6507x.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
 #include <linux/platform_device.h>
diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c
index 18296a99c4d2..62e7bc3018f0 100644
--- a/arch/arm/mach-davinci/board-dm355-evm.c
+++ b/arch/arm/mach-davinci/board-dm355-evm.c
@@ -14,7 +14,7 @@
 #include <linux/platform_device.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/i2c.h>
 #include <linux/gpio.h>
 #include <linux/clk.h>
diff --git a/arch/arm/mach-davinci/board-dm355-leopard.c b/arch/arm/mach-davinci/board-dm355-leopard.c
index 284ff27c1b32..be997243447b 100644
--- a/arch/arm/mach-davinci/board-dm355-leopard.c
+++ b/arch/arm/mach-davinci/board-dm355-leopard.c
@@ -13,7 +13,7 @@
 #include <linux/platform_device.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/i2c.h>
 #include <linux/gpio.h>
 #include <linux/clk.h>
diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c
index 0464999b7137..e75741fb2c1d 100644
--- a/arch/arm/mach-davinci/board-dm365-evm.c
+++ b/arch/arm/mach-davinci/board-dm365-evm.c
@@ -23,7 +23,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/slab.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/input.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/eeprom.h>
diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c
index 521e40977265..15a2476057e4 100644
--- a/arch/arm/mach-davinci/board-dm644x-evm.c
+++ b/arch/arm/mach-davinci/board-dm644x-evm.c
@@ -17,7 +17,7 @@
 #include <linux/i2c/pcf857x.h>
 #include <linux/platform_data/at24.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
 #include <linux/phy.h>
diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c
index f702d4fc8eb8..9b8864c66619 100644
--- a/arch/arm/mach-davinci/board-dm646x-evm.c
+++ b/arch/arm/mach-davinci/board-dm646x-evm.c
@@ -29,7 +29,7 @@
 #include <media/i2c/adv7343.h>
 
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/clk.h>
 #include <linux/export.h>
diff --git a/arch/arm/mach-davinci/board-sffsdr.c b/arch/arm/mach-davinci/board-sffsdr.c
index 41c7c9615791..d85accf7f760 100644
--- a/arch/arm/mach-davinci/board-sffsdr.c
+++ b/arch/arm/mach-davinci/board-sffsdr.c
@@ -28,7 +28,7 @@
 #include <linux/i2c.h>
 #include <linux/platform_data/at24.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 
 #include <asm/mach-types.h>
diff --git a/arch/arm/mach-dove/dove-db-setup.c b/arch/arm/mach-dove/dove-db-setup.c
index bcb678fd2415..8971c3c0f0fe 100644
--- a/arch/arm/mach-dove/dove-db-setup.c
+++ b/arch/arm/mach-dove/dove-db-setup.c
@@ -13,7 +13,7 @@
 #include <linux/platform_device.h>
 #include <linux/irq.h>
 #include <linux/mtd/physmap.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/timer.h>
 #include <linux/ata_platform.h>
 #include <linux/mv643xx_eth.h>
diff --git a/arch/arm/mach-ep93xx/snappercl15.c b/arch/arm/mach-ep93xx/snappercl15.c
index b2db791b3b38..8b29398f4dc7 100644
--- a/arch/arm/mach-ep93xx/snappercl15.c
+++ b/arch/arm/mach-ep93xx/snappercl15.c
@@ -25,7 +25,7 @@
 #include <linux/fb.h>
 
 #include <linux/mtd/partitions.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 
 #include <mach/hardware.h>
 #include <linux/platform_data/video-ep93xx.h>
diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c
index 3b39ea353d30..9def3b98945e 100644
--- a/arch/arm/mach-ep93xx/ts72xx.c
+++ b/arch/arm/mach-ep93xx/ts72xx.c
@@ -17,7 +17,7 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/platform_data/rtc-m48t86.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 
 #include <mach/hardware.h>
diff --git a/arch/arm/mach-imx/mach-qong.c b/arch/arm/mach-imx/mach-qong.c
index 8c2cbd693d21..42a700053103 100644
--- a/arch/arm/mach-imx/mach-qong.c
+++ b/arch/arm/mach-imx/mach-qong.c
@@ -18,7 +18,7 @@
 #include <linux/memory.h>
 #include <linux/platform_device.h>
 #include <linux/mtd/physmap.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/gpio.h>
 
 #include <asm/mach-types.h>
diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c
index 508c2d7786e2..93b89291c06b 100644
--- a/arch/arm/mach-ixp4xx/ixdp425-setup.c
+++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c
@@ -17,7 +17,7 @@
 #include <linux/i2c-gpio.h>
 #include <linux/io.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
diff --git a/arch/arm/mach-mmp/aspenite.c b/arch/arm/mach-mmp/aspenite.c
index 5db0edf716dd..d2283009a5ff 100644
--- a/arch/arm/mach-mmp/aspenite.c
+++ b/arch/arm/mach-mmp/aspenite.c
@@ -16,7 +16,7 @@
 #include <linux/smc91x.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/interrupt.h>
 #include <linux/platform_data/mv_usb.h>
 
diff --git a/arch/arm/mach-omap1/board-fsample.c b/arch/arm/mach-omap1/board-fsample.c
index fad95b74bb65..b93ad58b0a63 100644
--- a/arch/arm/mach-omap1/board-fsample.c
+++ b/arch/arm/mach-omap1/board-fsample.c
@@ -16,7 +16,7 @@
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
 #include <linux/input.h>
diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c
index 675254ee4b1e..a444b139bff5 100644
--- a/arch/arm/mach-omap1/board-h2.c
+++ b/arch/arm/mach-omap1/board-h2.c
@@ -24,7 +24,7 @@
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
 #include <linux/input.h>
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
index e62f9d454f10..a618a49a30b8 100644
--- a/arch/arm/mach-omap1/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -23,7 +23,7 @@
 #include <linux/workqueue.h>
 #include <linux/i2c.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
 #include <linux/input.h>
diff --git a/arch/arm/mach-omap1/board-nand.c b/arch/arm/mach-omap1/board-nand.c
index 7684f9203474..1bffbb4e050f 100644
--- a/arch/arm/mach-omap1/board-nand.c
+++ b/arch/arm/mach-omap1/board-nand.c
@@ -16,7 +16,7 @@
 #include <linux/kernel.h>
 #include <linux/io.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 
 #include "common.h"
 
diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c
index 150b57ba42bf..e994a78bdd09 100644
--- a/arch/arm/mach-omap1/board-perseus2.c
+++ b/arch/arm/mach-omap1/board-perseus2.c
@@ -16,7 +16,7 @@
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
 #include <linux/input.h>
diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index f6ac027f3c3b..250ae0173402 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -13,7 +13,7 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/omap-gpmc.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/platform_data/mtd-nand-omap2.h>
 
 #include <asm/mach/flash.h>
diff --git a/arch/arm/mach-orion5x/db88f5281-setup.c b/arch/arm/mach-orion5x/db88f5281-setup.c
index 12f74b46e2ff..3f5863de766a 100644
--- a/arch/arm/mach-orion5x/db88f5281-setup.c
+++ b/arch/arm/mach-orion5x/db88f5281-setup.c
@@ -16,7 +16,7 @@
 #include <linux/pci.h>
 #include <linux/irq.h>
 #include <linux/mtd/physmap.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/timer.h>
 #include <linux/mv643xx_eth.h>
 #include <linux/i2c.h>
diff --git a/arch/arm/mach-orion5x/kurobox_pro-setup.c b/arch/arm/mach-orion5x/kurobox_pro-setup.c
index 9dc3f59bed9c..83d43cff4bd7 100644
--- a/arch/arm/mach-orion5x/kurobox_pro-setup.c
+++ b/arch/arm/mach-orion5x/kurobox_pro-setup.c
@@ -15,7 +15,7 @@
 #include <linux/irq.h>
 #include <linux/delay.h>
 #include <linux/mtd/physmap.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mv643xx_eth.h>
 #include <linux/i2c.h>
 #include <linux/serial_reg.h>
diff --git a/arch/arm/mach-orion5x/ts209-setup.c b/arch/arm/mach-orion5x/ts209-setup.c
index 7bd671b2854c..0c315515dd2d 100644
--- a/arch/arm/mach-orion5x/ts209-setup.c
+++ b/arch/arm/mach-orion5x/ts209-setup.c
@@ -15,7 +15,7 @@
 #include <linux/pci.h>
 #include <linux/irq.h>
 #include <linux/mtd/physmap.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mv643xx_eth.h>
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
diff --git a/arch/arm/mach-orion5x/ts78xx-setup.c b/arch/arm/mach-orion5x/ts78xx-setup.c
index 8d597267d0c4..4632e674e9c5 100644
--- a/arch/arm/mach-orion5x/ts78xx-setup.c
+++ b/arch/arm/mach-orion5x/ts78xx-setup.c
@@ -17,7 +17,7 @@
 #include <linux/mv643xx_eth.h>
 #include <linux/ata_platform.h>
 #include <linux/platform_data/rtc-m48t86.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/timeriomem-rng.h>
 #include <asm/mach-types.h>
diff --git a/arch/arm/mach-pxa/balloon3.c b/arch/arm/mach-pxa/balloon3.c
index 8a3c409294bf..38afb6fa1dcf 100644
--- a/arch/arm/mach-pxa/balloon3.c
+++ b/arch/arm/mach-pxa/balloon3.c
@@ -28,7 +28,7 @@
 #include <linux/types.h>
 #include <linux/i2c/pcf857x.h>
 #include <linux/i2c/pxa-i2c.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/physmap.h>
 #include <linux/regulator/max1586.h>
 
diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c
index 03354c21e1f2..a6c5f5b96e47 100644
--- a/arch/arm/mach-pxa/em-x270.c
+++ b/arch/arm/mach-pxa/em-x270.c
@@ -15,7 +15,7 @@
 
 #include <linux/dm9000.h>
 #include <linux/platform_data/rtc-v3020.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
 #include <linux/input.h>
diff --git a/arch/arm/mach-pxa/eseries.c b/arch/arm/mach-pxa/eseries.c
index fa9d71d194f0..91f7c3e40065 100644
--- a/arch/arm/mach-pxa/eseries.c
+++ b/arch/arm/mach-pxa/eseries.c
@@ -20,7 +20,7 @@
 #include <linux/mfd/tc6387xb.h>
 #include <linux/mfd/tc6393xb.h>
 #include <linux/mfd/t7l66xb.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/usb/gpio_vbus.h>
 #include <linux/memblock.h>
diff --git a/arch/arm/mach-pxa/palmtx.c b/arch/arm/mach-pxa/palmtx.c
index 36646975b5d2..47e3e38e9bec 100644
--- a/arch/arm/mach-pxa/palmtx.c
+++ b/arch/arm/mach-pxa/palmtx.c
@@ -28,7 +28,7 @@
 #include <linux/wm97xx.h>
 #include <linux/power_supply.h>
 #include <linux/usb/gpio_vbus.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/physmap.h>
diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c
index 13de6602966f..6a386fd6363e 100644
--- a/arch/arm/mach-pxa/tosa.c
+++ b/arch/arm/mach-pxa/tosa.c
@@ -24,7 +24,7 @@
 #include <linux/mmc/host.h>
 #include <linux/mfd/tc6393xb.h>
 #include <linux/mfd/tmio.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
 #include <linux/pm.h>
diff --git a/arch/arm/mach-s3c24xx/common-smdk.c b/arch/arm/mach-s3c24xx/common-smdk.c
index e9fbcc91c5c0..a39d9667eb14 100644
--- a/arch/arm/mach-s3c24xx/common-smdk.c
+++ b/arch/arm/mach-s3c24xx/common-smdk.c
@@ -23,7 +23,7 @@
 #include <linux/platform_device.h>
 
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/partitions.h>
 #include <linux/io.h>
diff --git a/arch/arm/mach-s3c24xx/mach-anubis.c b/arch/arm/mach-s3c24xx/mach-anubis.c
index d03df0df01fa..357f24e3fd80 100644
--- a/arch/arm/mach-s3c24xx/mach-anubis.c
+++ b/arch/arm/mach-s3c24xx/mach-anubis.c
@@ -40,7 +40,7 @@
 #include <linux/platform_data/i2c-s3c2410.h>
 
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/partitions.h>
 
diff --git a/arch/arm/mach-s3c24xx/mach-at2440evb.c b/arch/arm/mach-s3c24xx/mach-at2440evb.c
index 9ae170fef2a7..8cb1c26e5809 100644
--- a/arch/arm/mach-s3c24xx/mach-at2440evb.c
+++ b/arch/arm/mach-s3c24xx/mach-at2440evb.c
@@ -41,7 +41,7 @@
 #include <linux/platform_data/i2c-s3c2410.h>
 
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/partitions.h>
 
diff --git a/arch/arm/mach-s3c24xx/mach-bast.c b/arch/arm/mach-s3c24xx/mach-bast.c
index ed07cf392d4b..c895050afe07 100644
--- a/arch/arm/mach-s3c24xx/mach-bast.c
+++ b/arch/arm/mach-s3c24xx/mach-bast.c
@@ -28,7 +28,7 @@
 #include <linux/serial_8250.h>
 
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/partitions.h>
 
diff --git a/arch/arm/mach-s3c24xx/mach-gta02.c b/arch/arm/mach-s3c24xx/mach-gta02.c
index 27ae6877550f..21de3ceb98a1 100644
--- a/arch/arm/mach-s3c24xx/mach-gta02.c
+++ b/arch/arm/mach-s3c24xx/mach-gta02.c
@@ -50,7 +50,7 @@
 #include <linux/mfd/pcf50633/pmic.h>
 
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
diff --git a/arch/arm/mach-s3c24xx/mach-jive.c b/arch/arm/mach-s3c24xx/mach-jive.c
index 7d99fe8f6157..1e95d1528860 100644
--- a/arch/arm/mach-s3c24xx/mach-jive.c
+++ b/arch/arm/mach-s3c24xx/mach-jive.c
@@ -43,7 +43,7 @@
 #include <asm/mach-types.h>
 
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/partitions.h>
 
diff --git a/arch/arm/mach-s3c24xx/mach-mini2440.c b/arch/arm/mach-s3c24xx/mach-mini2440.c
index ec60bd4a1646..38dc7e21deb1 100644
--- a/arch/arm/mach-s3c24xx/mach-mini2440.c
+++ b/arch/arm/mach-s3c24xx/mach-mini2440.c
@@ -49,7 +49,7 @@
 #include <linux/platform_data/usb-s3c2410_udc.h>
 
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/partitions.h>
 
diff --git a/arch/arm/mach-s3c24xx/mach-osiris.c b/arch/arm/mach-s3c24xx/mach-osiris.c
index 2f6fdc326835..0cf4f222f222 100644
--- a/arch/arm/mach-s3c24xx/mach-osiris.c
+++ b/arch/arm/mach-s3c24xx/mach-osiris.c
@@ -36,7 +36,7 @@
 #include <linux/platform_data/i2c-s3c2410.h>
 
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/partitions.h>
 
diff --git a/arch/arm/mach-s3c24xx/mach-qt2410.c b/arch/arm/mach-s3c24xx/mach-qt2410.c
index 984516e8307a..86d7ffd8c511 100644
--- a/arch/arm/mach-s3c24xx/mach-qt2410.c
+++ b/arch/arm/mach-s3c24xx/mach-qt2410.c
@@ -36,7 +36,7 @@
 #include <linux/spi/spi_gpio.h>
 #include <linux/io.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/partitions.h>
 
diff --git a/arch/arm/mach-s3c24xx/mach-rx3715.c b/arch/arm/mach-s3c24xx/mach-rx3715.c
index cf55196f89ca..b6fdd088987a 100644
--- a/arch/arm/mach-s3c24xx/mach-rx3715.c
+++ b/arch/arm/mach-s3c24xx/mach-rx3715.c
@@ -27,7 +27,7 @@
 #include <linux/serial.h>
 #include <linux/io.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/partitions.h>
 
diff --git a/arch/arm/mach-s3c24xx/mach-vstms.c b/arch/arm/mach-s3c24xx/mach-vstms.c
index b4460d5f7011..67adb4c5f327 100644
--- a/arch/arm/mach-s3c24xx/mach-vstms.c
+++ b/arch/arm/mach-s3c24xx/mach-vstms.c
@@ -20,7 +20,7 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/partitions.h>
 #include <linux/memblock.h>
diff --git a/arch/blackfin/mach-bf537/boards/dnp5370.c b/arch/blackfin/mach-bf537/boards/dnp5370.c
index e79b3b810c39..c4a8ffb15417 100644
--- a/arch/blackfin/mach-bf537/boards/dnp5370.c
+++ b/arch/blackfin/mach-bf537/boards/dnp5370.c
@@ -17,7 +17,7 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/plat-ram.h>
 #include <linux/mtd/physmap.h>
diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c
index eaec7b4832a2..ab3034fd1c5b 100644
--- a/arch/blackfin/mach-bf537/boards/stamp.c
+++ b/arch/blackfin/mach-bf537/boards/stamp.c
@@ -12,7 +12,7 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/plat-ram.h>
 #include <linux/mtd/physmap.h>
diff --git a/arch/blackfin/mach-bf561/boards/acvilon.c b/arch/blackfin/mach-bf561/boards/acvilon.c
index 37f8f25a1347..696cc9d7820a 100644
--- a/arch/blackfin/mach-bf561/boards/acvilon.c
+++ b/arch/blackfin/mach-bf561/boards/acvilon.c
@@ -38,7 +38,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/plat-ram.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/flash.h>
diff --git a/arch/cris/arch-v32/drivers/mach-a3/nandflash.c b/arch/cris/arch-v32/drivers/mach-a3/nandflash.c
index 3f646c787e58..925a98eb6d68 100644
--- a/arch/cris/arch-v32/drivers/mach-a3/nandflash.c
+++ b/arch/cris/arch-v32/drivers/mach-a3/nandflash.c
@@ -16,7 +16,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <arch/memmap.h>
 #include <hwregs/reg_map.h>
diff --git a/arch/cris/arch-v32/drivers/mach-fs/nandflash.c b/arch/cris/arch-v32/drivers/mach-fs/nandflash.c
index a74540514bdb..53b56a429dde 100644
--- a/arch/cris/arch-v32/drivers/mach-fs/nandflash.c
+++ b/arch/cris/arch-v32/drivers/mach-fs/nandflash.c
@@ -16,7 +16,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <arch/memmap.h>
 #include <hwregs/reg_map.h>
diff --git a/arch/mips/alchemy/devboards/db1200.c b/arch/mips/alchemy/devboards/db1200.c
index 992442a03d8b..83831002c832 100644
--- a/arch/mips/alchemy/devboards/db1200.c
+++ b/arch/mips/alchemy/devboards/db1200.c
@@ -29,7 +29,7 @@
 #include <linux/leds.h>
 #include <linux/mmc/host.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
diff --git a/arch/mips/alchemy/devboards/db1300.c b/arch/mips/alchemy/devboards/db1300.c
index d3c087f59f1a..06c18a80a129 100644
--- a/arch/mips/alchemy/devboards/db1300.c
+++ b/arch/mips/alchemy/devboards/db1300.c
@@ -17,7 +17,7 @@
 #include <linux/mmc/host.h>
 #include <linux/module.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/platform_device.h>
 #include <linux/smsc911x.h>
diff --git a/arch/mips/alchemy/devboards/db1550.c b/arch/mips/alchemy/devboards/db1550.c
index 1c01d6eadb08..421bd5793f7e 100644
--- a/arch/mips/alchemy/devboards/db1550.c
+++ b/arch/mips/alchemy/devboards/db1550.c
@@ -12,7 +12,7 @@
 #include <linux/io.h>
 #include <linux/interrupt.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/platform_device.h>
 #include <linux/pm.h>
diff --git a/arch/mips/include/asm/mach-jz4740/jz4740_nand.h b/arch/mips/include/asm/mach-jz4740/jz4740_nand.h
index 7f7b0fc554da..f381d465e768 100644
--- a/arch/mips/include/asm/mach-jz4740/jz4740_nand.h
+++ b/arch/mips/include/asm/mach-jz4740/jz4740_nand.h
@@ -16,7 +16,7 @@
 #ifndef __ASM_MACH_JZ4740_JZ4740_NAND_H__
 #define __ASM_MACH_JZ4740_JZ4740_NAND_H__
 
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 
 #define JZ_NAND_NUM_BANKS 4
diff --git a/arch/mips/netlogic/xlr/platform-flash.c b/arch/mips/netlogic/xlr/platform-flash.c
index f03131fec41d..4d1b4c003376 100644
--- a/arch/mips/netlogic/xlr/platform-flash.c
+++ b/arch/mips/netlogic/xlr/platform-flash.c
@@ -19,7 +19,7 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/physmap.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 
 #include <asm/netlogic/haldefs.h>
diff --git a/arch/mips/pnx833x/common/platform.c b/arch/mips/pnx833x/common/platform.c
index 7cf4eb50fc72..a7a4e9f5146d 100644
--- a/arch/mips/pnx833x/common/platform.c
+++ b/arch/mips/pnx833x/common/platform.c
@@ -30,7 +30,7 @@
 #include <linux/resource.h>
 #include <linux/serial.h>
 #include <linux/serial_pnx8xxx.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 
 #include <irq.h>
diff --git a/arch/mips/rb532/devices.c b/arch/mips/rb532/devices.c
index 0966adccf520..32ea3e6731d6 100644
--- a/arch/mips/rb532/devices.c
+++ b/arch/mips/rb532/devices.c
@@ -20,7 +20,7 @@
 #include <linux/ctype.h>
 #include <linux/string.h>
 #include <linux/platform_device.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/gpio.h>
diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c
index 5de60a77eaa1..0bcbe58b11e9 100644
--- a/arch/sh/boards/mach-migor/setup.c
+++ b/arch/sh/boards/mach-migor/setup.c
@@ -15,7 +15,7 @@
 #include <linux/mmc/host.h>
 #include <linux/mtd/physmap.h>
 #include <linux/mfd/tmio.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/i2c.h>
 #include <linux/regulator/fixed.h>
 #include <linux/regulator/machine.h>
diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c
index b66b541877f0..6373ccba8bb8 100644
--- a/drivers/mtd/inftlcore.c
+++ b/drivers/mtd/inftlcore.c
@@ -33,7 +33,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nftl.h>
 #include <linux/mtd/inftl.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <asm/uaccess.h>
 #include <asm/errno.h>
 #include <asm/io.h>
diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c
index 78e12cc8bac2..0972493b6cd2 100644
--- a/drivers/mtd/nand/ams-delta.c
+++ b/drivers/mtd/nand/ams-delta.c
@@ -20,7 +20,7 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/gpio.h>
 #include <linux/platform_data/gpio-omap.h>
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 68b9160108c9..fbb7e5da2541 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -37,7 +37,7 @@
 #include <linux/of_device.h>
 #include <linux/of_gpio.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 
 #include <linux/delay.h>
diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c
index 9bf6d9915694..9d4a28fa6b73 100644
--- a/drivers/mtd/nand/au1550nd.c
+++ b/drivers/mtd/nand/au1550nd.c
@@ -14,7 +14,7 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/platform_device.h>
 #include <asm/io.h>
diff --git a/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h b/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h
index 8ea75710a854..c8834767ab6d 100644
--- a/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h
+++ b/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h
@@ -6,7 +6,7 @@
 #endif
 
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 
 struct bcm47xxnflash {
 	struct bcma_drv_cc *cc;
diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c
index 3962f55bd034..5655dca6ce43 100644
--- a/drivers/mtd/nand/bf5xx_nand.c
+++ b/drivers/mtd/nand/bf5xx_nand.c
@@ -49,7 +49,7 @@
 #include <linux/bitops.h>
 
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/partitions.h>
 
diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c
index 9d2424bfdbf5..98453816a0a2 100644
--- a/drivers/mtd/nand/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/brcmnand/brcmnand.c
@@ -29,7 +29,7 @@
 #include <linux/bitops.h>
 #include <linux/mm.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c
index 0b0c93702abb..93880171740a 100644
--- a/drivers/mtd/nand/cafe_nand.c
+++ b/drivers/mtd/nand/cafe_nand.c
@@ -13,7 +13,7 @@
 #include <linux/device.h>
 #undef DEBUG
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/rslib.h>
 #include <linux/pci.h>
diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/cmx270_nand.c
index 49133783ca53..2efe6a56557f 100644
--- a/drivers/mtd/nand/cmx270_nand.c
+++ b/drivers/mtd/nand/cmx270_nand.c
@@ -18,7 +18,7 @@
  *   CM-X270 board.
  */
 
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/slab.h>
 #include <linux/gpio.h>
diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c
index a65e4e0f57a1..8fafb4b4488d 100644
--- a/drivers/mtd/nand/cs553x_nand.c
+++ b/drivers/mtd/nand/cs553x_nand.c
@@ -24,7 +24,7 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/partitions.h>
 
diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c
index 27fa8b87cd5f..29034e378b5b 100644
--- a/drivers/mtd/nand/davinci_nand.c
+++ b/drivers/mtd/nand/davinci_nand.c
@@ -29,7 +29,7 @@
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/io.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/slab.h>
 #include <linux/of_device.h>
diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h
index e7ab4866a5da..37618b532317 100644
--- a/drivers/mtd/nand/denali.h
+++ b/drivers/mtd/nand/denali.h
@@ -20,7 +20,7 @@
 #ifndef __DENALI_H__
 #define __DENALI_H__
 
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 
 #define DEVICE_RESET				0x0
 #define     DEVICE_RESET__BANK0				0x0001
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c
index a023ab9e9cbf..c3aa53caab5c 100644
--- a/drivers/mtd/nand/diskonchip.c
+++ b/drivers/mtd/nand/diskonchip.c
@@ -27,7 +27,7 @@
 #include <linux/io.h>
 
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/doc2000.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/inftl.h>
diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c
index 7af2a3cd949e..e038130b7206 100644
--- a/drivers/mtd/nand/docg4.c
+++ b/drivers/mtd/nand/docg4.c
@@ -41,7 +41,7 @@
 #include <linux/bitops.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/bch.h>
 #include <linux/bitrev.h>
 #include <linux/jiffies.h>
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index 113f76e59937..7d8453eb4d0f 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -34,7 +34,7 @@
 #include <linux/interrupt.h>
 
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/partitions.h>
 
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
index 0a177b1bfe3e..bcf7f0b8abf9 100644
--- a/drivers/mtd/nand/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/fsl_ifc_nand.c
@@ -26,7 +26,7 @@
 #include <linux/of_address.h>
 #include <linux/slab.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/fsl_ifc.h>
diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c
index d85fa2555b68..a88e2cf66e0f 100644
--- a/drivers/mtd/nand/fsl_upm.c
+++ b/drivers/mtd/nand/fsl_upm.c
@@ -14,7 +14,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/delay.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/mtd.h>
diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c
index d4f454a4b35e..5c08694aa153 100644
--- a/drivers/mtd/nand/fsmc_nand.c
+++ b/drivers/mtd/nand/fsmc_nand.c
@@ -28,7 +28,7 @@
 #include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/platform_device.h>
 #include <linux/of.h>
diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/gpio.c
index 6317f6836022..21b19efe1ac7 100644
--- a/drivers/mtd/nand/gpio.c
+++ b/drivers/mtd/nand/gpio.c
@@ -26,7 +26,7 @@
 #include <linux/gpio.h>
 #include <linux/io.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/nand-gpio.h>
 #include <linux/of.h>
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
index 4e49a1f5fa27..d7625cad6493 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
@@ -17,7 +17,7 @@
 #ifndef __DRIVERS_MTD_NAND_GPMI_NAND_H
 #define __DRIVERS_MTD_NAND_GPMI_NAND_H
 
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
diff --git a/drivers/mtd/nand/hisi504_nand.c b/drivers/mtd/nand/hisi504_nand.c
index 9432546f4cd4..a287d73bb17e 100644
--- a/drivers/mtd/nand/hisi504_nand.c
+++ b/drivers/mtd/nand/hisi504_nand.c
@@ -26,7 +26,7 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
 #include <linux/mtd/partitions.h>
diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
index 5551c36adbdf..e813ec11ee84 100644
--- a/drivers/mtd/nand/jz4740_nand.c
+++ b/drivers/mtd/nand/jz4740_nand.c
@@ -20,7 +20,7 @@
 #include <linux/slab.h>
 
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 
 #include <linux/gpio.h>
diff --git a/drivers/mtd/nand/jz4780_nand.c b/drivers/mtd/nand/jz4780_nand.c
index a39bb70175ee..2f725bd83de8 100644
--- a/drivers/mtd/nand/jz4780_nand.c
+++ b/drivers/mtd/nand/jz4780_nand.c
@@ -20,7 +20,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 
 #include <linux/jz4780-nemc.h>
diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c
index 852388171f20..b212bb0fd902 100644
--- a/drivers/mtd/nand/lpc32xx_mlc.c
+++ b/drivers/mtd/nand/lpc32xx_mlc.c
@@ -27,7 +27,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/clk.h>
 #include <linux/err.h>
diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c
index 8d3edc34958e..018d783d37cd 100644
--- a/drivers/mtd/nand/lpc32xx_slc.c
+++ b/drivers/mtd/nand/lpc32xx_slc.c
@@ -23,7 +23,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/clk.h>
 #include <linux/err.h>
diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c
index 7eacb2f545f5..2a1fa86fd123 100644
--- a/drivers/mtd/nand/mpc5121_nfc.c
+++ b/drivers/mtd/nand/mpc5121_nfc.c
@@ -33,7 +33,7 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
diff --git a/drivers/mtd/nand/mtk_nand.c b/drivers/mtd/nand/mtk_nand.c
index 5223a2182ee4..95f32ca88823 100644
--- a/drivers/mtd/nand/mtk_nand.c
+++ b/drivers/mtd/nand/mtk_nand.c
@@ -19,7 +19,7 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/mtd.h>
 #include <linux/module.h>
 #include <linux/iopoll.h>
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index d7f724b24fd7..58a960540369 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -22,7 +22,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/interrupt.h>
 #include <linux/device.h>
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index e5718e5ecf92..286abd768454 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -38,7 +38,7 @@
 #include <linux/mm.h>
 #include <linux/types.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/nand_bch.h>
 #include <linux/interrupt.h>
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 7695efea65f2..2915b6739bf8 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -61,7 +61,7 @@
 #include <linux/types.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/bbm.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/bitops.h>
 #include <linux/delay.h>
 #include <linux/vmalloc.h>
diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c
index 44763f87eae4..505441c9373b 100644
--- a/drivers/mtd/nand/nand_bch.c
+++ b/drivers/mtd/nand/nand_bch.c
@@ -25,7 +25,7 @@
 #include <linux/slab.h>
 #include <linux/bitops.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nand_bch.h>
 #include <linux/bch.h>
 
diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c
index d1770b066396..7613a0388044 100644
--- a/drivers/mtd/nand/nand_ecc.c
+++ b/drivers/mtd/nand/nand_ecc.c
@@ -43,7 +43,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <asm/byteorder.h>
 #else
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
index 2af9869a115e..80550dbf9467 100644
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -7,7 +7,7 @@
  *
  */
 #include <linux/module.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/sizes.h>
 
 #define LP_OPTIONS NAND_SAMSUNG_LP_OPTIONS
diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/nand_timings.c
index 13a587407be3..5cf237268284 100644
--- a/drivers/mtd/nand/nand_timings.c
+++ b/drivers/mtd/nand/nand_timings.c
@@ -11,7 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/err.h>
 #include <linux/export.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 
 static const struct nand_data_interface onfi_sdr_timings[] = {
 	/* Mode 0 */
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 1eb934414eb5..9c16635b5338 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -33,7 +33,7 @@
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nand_bch.h>
 #include <linux/mtd/partitions.h>
 #include <linux/delay.h>
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
index 28e6118362f7..d8a806894937 100644
--- a/drivers/mtd/nand/ndfc.c
+++ b/drivers/mtd/nand/ndfc.c
@@ -22,7 +22,7 @@
  *
  */
 #include <linux/module.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/ndfc.h>
diff --git a/drivers/mtd/nand/nuc900_nand.c b/drivers/mtd/nand/nuc900_nand.c
index 8f64011d32ef..7bb4d2ea9342 100644
--- a/drivers/mtd/nand/nuc900_nand.c
+++ b/drivers/mtd/nand/nuc900_nand.c
@@ -19,7 +19,7 @@
 #include <linux/err.h>
 
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 
 #define REG_FMICSR   	0x00
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 5513bfd9cdc9..5283898e9589 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -18,7 +18,7 @@
 #include <linux/jiffies.h>
 #include <linux/sched.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/omap-dma.h>
 #include <linux/io.h>
diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c
index 40a7c4a2cf0d..e68c4231e8b7 100644
--- a/drivers/mtd/nand/orion_nand.c
+++ b/drivers/mtd/nand/orion_nand.c
@@ -15,7 +15,7 @@
 #include <linux/platform_device.h>
 #include <linux/of.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/clk.h>
 #include <linux/err.h>
diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c
index 5de7591b0510..372b9736ac02 100644
--- a/drivers/mtd/nand/pasemi_nand.c
+++ b/drivers/mtd/nand/pasemi_nand.c
@@ -25,7 +25,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c
index 415a53a0deeb..d5c3c894c60d 100644
--- a/drivers/mtd/nand/plat_nand.c
+++ b/drivers/mtd/nand/plat_nand.c
@@ -15,7 +15,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 
 struct plat_nand_data {
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index b121bf4ed73a..4feec4ea3082 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -21,7 +21,7 @@
 #include <linux/delay.h>
 #include <linux/clk.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c
index 57d483ac5765..a77c66f4d8bc 100644
--- a/drivers/mtd/nand/qcom_nandc.c
+++ b/drivers/mtd/nand/qcom_nandc.c
@@ -17,7 +17,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
 #include <linux/module.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
diff --git a/drivers/mtd/nand/r852.h b/drivers/mtd/nand/r852.h
index d042ddb71a8b..8713c57f6207 100644
--- a/drivers/mtd/nand/r852.h
+++ b/drivers/mtd/nand/r852.h
@@ -10,7 +10,7 @@
 #include <linux/pci.h>
 #include <linux/completion.h>
 #include <linux/workqueue.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/spinlock.h>
 
 
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index d459c19d78de..6ce9f867a123 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -41,7 +41,7 @@
 #include <linux/cpufreq.h>
 
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/partitions.h>
 
diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c
index 442ce619b3b6..492705fb23f2 100644
--- a/drivers/mtd/nand/sh_flctl.c
+++ b/drivers/mtd/nand/sh_flctl.c
@@ -38,7 +38,7 @@
 #include <linux/string.h>
 
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/sh_flctl.h>
 
diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c
index 064ca1757589..737efe83cd36 100644
--- a/drivers/mtd/nand/sharpsl.c
+++ b/drivers/mtd/nand/sharpsl.c
@@ -17,7 +17,7 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/sharpsl.h>
diff --git a/drivers/mtd/nand/sm_common.c b/drivers/mtd/nand/sm_common.c
index 5939dff253c2..c378705c6e2b 100644
--- a/drivers/mtd/nand/sm_common.c
+++ b/drivers/mtd/nand/sm_common.c
@@ -7,7 +7,7 @@
  * published by the Free Software Foundation.
  */
 #include <linux/kernel.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/module.h>
 #include <linux/sizes.h>
 #include "sm_common.h"
diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/socrates_nand.c
index 888fd314c62a..f5a3e7252b82 100644
--- a/drivers/mtd/nand/socrates_nand.c
+++ b/drivers/mtd/nand/socrates_nand.c
@@ -13,7 +13,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index 8b8470c4e6d0..ccccc7ab9023 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -31,7 +31,7 @@
 #include <linux/of_device.h>
 #include <linux/of_gpio.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c
index 08b30549ec0a..e599ada12cd0 100644
--- a/drivers/mtd/nand/tmio_nand.c
+++ b/drivers/mtd/nand/tmio_nand.c
@@ -34,7 +34,7 @@
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/partitions.h>
 #include <linux/slab.h>
diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c
index 0a14fda2e41b..b567d212fe7d 100644
--- a/drivers/mtd/nand/txx9ndfmc.c
+++ b/drivers/mtd/nand/txx9ndfmc.c
@@ -16,7 +16,7 @@
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/partitions.h>
 #include <linux/io.h>
diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c
index 3ad514c44dcb..c497b157d56a 100644
--- a/drivers/mtd/nand/vf610_nfc.c
+++ b/drivers/mtd/nand/vf610_nfc.c
@@ -31,7 +31,7 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/consumer.h>
diff --git a/drivers/mtd/nand/xway_nand.c b/drivers/mtd/nand/xway_nand.c
index 1f2948c0c458..3e7353e76264 100644
--- a/drivers/mtd/nand/xway_nand.c
+++ b/drivers/mtd/nand/xway_nand.c
@@ -7,7 +7,7 @@
  *  Copyright ? 2016 Hauke Mehrtens <hauke at hauke-m.de>
  */
 
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/of_gpio.h>
 #include <linux/of_platform.h>
 
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
index 46f27de018c3..2a1dd0049a45 100644
--- a/drivers/mtd/nftlcore.c
+++ b/drivers/mtd/nftlcore.c
@@ -34,7 +34,7 @@
 
 #include <linux/kmod.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nftl.h>
 #include <linux/mtd/blktrans.h>
 
diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c
index a5dfbfbebfca..184c8fbfe465 100644
--- a/drivers/mtd/nftlmount.c
+++ b/drivers/mtd/nftlmount.c
@@ -25,7 +25,7 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nftl.h>
 
 #define SECTORSIZE 512
diff --git a/drivers/mtd/ssfdc.c b/drivers/mtd/ssfdc.c
index 41b13d1cdcc4..95f0bf95f095 100644
--- a/drivers/mtd/ssfdc.c
+++ b/drivers/mtd/ssfdc.c
@@ -16,7 +16,7 @@
 #include <linux/slab.h>
 #include <linux/hdreg.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/blktrans.h>
 
 struct ssfdcr_record {
diff --git a/drivers/mtd/tests/nandbiterrs.c b/drivers/mtd/tests/nandbiterrs.c
index f26dec896afa..5f03b8c885a9 100644
--- a/drivers/mtd/tests/nandbiterrs.c
+++ b/drivers/mtd/tests/nandbiterrs.c
@@ -47,7 +47,7 @@
 #include <linux/moduleparam.h>
 #include <linux/mtd/mtd.h>
 #include <linux/err.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/slab.h>
 #include "mtd_test.h"
 
diff --git a/drivers/staging/mt29f_spinand/mt29f_spinand.c b/drivers/staging/mt29f_spinand/mt29f_spinand.c
index e389009fca42..f7f6edf2dda1 100644
--- a/drivers/staging/mt29f_spinand/mt29f_spinand.c
+++ b/drivers/staging/mt29f_spinand/mt29f_spinand.c
@@ -18,7 +18,7 @@
 #include <linux/delay.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/spi/spi.h>
 
 #include "mt29f_spinand.h"
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
index b25d28a21212..48d9522e209c 100644
--- a/fs/jffs2/wbuf.c
+++ b/fs/jffs2/wbuf.c
@@ -17,7 +17,7 @@
 #include <linux/slab.h>
 #include <linux/mtd/mtd.h>
 #include <linux/crc32.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/jiffies.h>
 #include <linux/sched.h>
 #include <linux/writeback.h>
diff --git a/include/linux/mtd/nand-gpio.h b/include/linux/mtd/nand-gpio.h
index 51534e50f7fc..be4f45d89be2 100644
--- a/include/linux/mtd/nand-gpio.h
+++ b/include/linux/mtd/nand-gpio.h
@@ -1,7 +1,7 @@
 #ifndef __LINUX_MTD_NAND_GPIO_H
 #define __LINUX_MTD_NAND_GPIO_H
 
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 
 struct gpio_nand_platdata {
 	int	gpio_nce;
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/rawnand.h
similarity index 99%
rename from include/linux/mtd/nand.h
rename to include/linux/mtd/rawnand.h
index c5d3d5024fc8..fecfd05a585a 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/rawnand.h
@@ -1,6 +1,4 @@
 /*
- *  linux/include/linux/mtd/nand.h
- *
  *  Copyright ? 2000-2010 David Woodhouse <dwmw2 at infradead.org>
  *                        Steven J. Hill <sjhill at realitydiluted.com>
  *		          Thomas Gleixner <tglx at linutronix.de>
@@ -15,8 +13,8 @@
  * Changelog:
  *	See git changelog.
  */
-#ifndef __LINUX_MTD_NAND_H
-#define __LINUX_MTD_NAND_H
+#ifndef __LINUX_MTD_RAWNAND_H
+#define __LINUX_MTD_RAWNAND_H
 
 #include <linux/wait.h>
 #include <linux/spinlock.h>
@@ -1189,4 +1187,4 @@ int nand_reset(struct nand_chip *chip);
 /* Free resources held by the NAND device */
 void nand_cleanup(struct nand_chip *chip);
 
-#endif /* __LINUX_MTD_NAND_H */
+#endif /* __LINUX_MTD_RAWNAND_H */
diff --git a/include/linux/mtd/sh_flctl.h b/include/linux/mtd/sh_flctl.h
index 2251add65fa7..c759d403cbc0 100644
--- a/include/linux/mtd/sh_flctl.h
+++ b/include/linux/mtd/sh_flctl.h
@@ -22,7 +22,7 @@
 
 #include <linux/completion.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/pm_qos.h>
 
diff --git a/include/linux/mtd/sharpsl.h b/include/linux/mtd/sharpsl.h
index 65e91d0fa981..72a79c7d0e08 100644
--- a/include/linux/mtd/sharpsl.h
+++ b/include/linux/mtd/sharpsl.h
@@ -8,7 +8,7 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/partitions.h>
 
diff --git a/include/linux/platform_data/atmel.h b/include/linux/platform_data/atmel.h
index 3c8825b67298..d9d886fbc259 100644
--- a/include/linux/platform_data/atmel.h
+++ b/include/linux/platform_data/atmel.h
@@ -7,7 +7,7 @@
 #ifndef __ATMEL_H__
 #define __ATMEL_H__
 
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/serial.h>
 
diff --git a/include/linux/platform_data/mtd-davinci.h b/include/linux/platform_data/mtd-davinci.h
index 1cf555aef896..f1a2cf655bdb 100644
--- a/include/linux/platform_data/mtd-davinci.h
+++ b/include/linux/platform_data/mtd-davinci.h
@@ -28,7 +28,7 @@
 #ifndef __ARCH_ARM_DAVINCI_NAND_H
 #define __ARCH_ARM_DAVINCI_NAND_H
 
-#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
 
 #define NANDFCR_OFFSET		0x60
 #define NANDFSR_OFFSET		0x64
-- 
2.7.4



From boris.brezillon at free-electrons.com  Sun Oct 16 07:35:13 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Sun, 16 Oct 2016 16:35:13 +0200
Subject: [PATCH v2 2/7] mtd: nand: move raw NAND related code to the raw/
 subdir
In-Reply-To: <1476628518-20450-1-git-send-email-boris.brezillon@free-electrons.com>
References: <1476628518-20450-1-git-send-email-boris.brezillon@free-electrons.com>
Message-ID: <1476628518-20450-3-git-send-email-boris.brezillon@free-electrons.com>

As part of the process of sharing more code between different NAND
based devices, we need to move all raw NAND related code to the raw/
subdirectory.

Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/Kconfig                           | 573 +--------------------
 drivers/mtd/nand/Makefile                          |  63 +--
 drivers/mtd/nand/raw/Kconfig                       | 572 ++++++++++++++++++++
 drivers/mtd/nand/raw/Makefile                      |  62 +++
 drivers/mtd/nand/{ => raw}/ams-delta.c             |   0
 drivers/mtd/nand/{ => raw}/atmel_nand.c            |   0
 drivers/mtd/nand/{ => raw}/atmel_nand_ecc.h        |   0
 drivers/mtd/nand/{ => raw}/atmel_nand_nfc.h        |   0
 drivers/mtd/nand/{ => raw}/au1550nd.c              |   0
 drivers/mtd/nand/{ => raw}/bcm47xxnflash/Makefile  |   0
 .../nand/{ => raw}/bcm47xxnflash/bcm47xxnflash.h   |   0
 drivers/mtd/nand/{ => raw}/bcm47xxnflash/main.c    |   0
 .../mtd/nand/{ => raw}/bcm47xxnflash/ops_bcm4706.c |   0
 drivers/mtd/nand/{ => raw}/bf5xx_nand.c            |   0
 drivers/mtd/nand/{ => raw}/brcmnand/Makefile       |   0
 .../mtd/nand/{ => raw}/brcmnand/bcm63138_nand.c    |   0
 drivers/mtd/nand/{ => raw}/brcmnand/bcm6368_nand.c |   0
 drivers/mtd/nand/{ => raw}/brcmnand/brcmnand.c     |   0
 drivers/mtd/nand/{ => raw}/brcmnand/brcmnand.h     |   0
 drivers/mtd/nand/{ => raw}/brcmnand/brcmstb_nand.c |   0
 drivers/mtd/nand/{ => raw}/brcmnand/iproc_nand.c   |   0
 drivers/mtd/nand/{ => raw}/cafe_nand.c             |   0
 drivers/mtd/nand/{ => raw}/cmx270_nand.c           |   0
 drivers/mtd/nand/{ => raw}/cs553x_nand.c           |   0
 drivers/mtd/nand/{ => raw}/davinci_nand.c          |   0
 drivers/mtd/nand/{ => raw}/denali.c                |   0
 drivers/mtd/nand/{ => raw}/denali.h                |   0
 drivers/mtd/nand/{ => raw}/denali_dt.c             |   0
 drivers/mtd/nand/{ => raw}/denali_pci.c            |   0
 drivers/mtd/nand/{ => raw}/diskonchip.c            |   0
 drivers/mtd/nand/{ => raw}/docg4.c                 |   0
 drivers/mtd/nand/{ => raw}/fsl_elbc_nand.c         |   0
 drivers/mtd/nand/{ => raw}/fsl_ifc_nand.c          |   0
 drivers/mtd/nand/{ => raw}/fsl_upm.c               |   0
 drivers/mtd/nand/{ => raw}/fsmc_nand.c             |   0
 drivers/mtd/nand/{ => raw}/gpio.c                  |   0
 drivers/mtd/nand/{ => raw}/gpmi-nand/Makefile      |   0
 drivers/mtd/nand/{ => raw}/gpmi-nand/bch-regs.h    |   0
 drivers/mtd/nand/{ => raw}/gpmi-nand/gpmi-lib.c    |   0
 drivers/mtd/nand/{ => raw}/gpmi-nand/gpmi-nand.c   |   0
 drivers/mtd/nand/{ => raw}/gpmi-nand/gpmi-nand.h   |   0
 drivers/mtd/nand/{ => raw}/gpmi-nand/gpmi-regs.h   |   0
 drivers/mtd/nand/{ => raw}/hisi504_nand.c          |   0
 drivers/mtd/nand/{ => raw}/jz4740_nand.c           |   0
 drivers/mtd/nand/{ => raw}/jz4780_bch.c            |   0
 drivers/mtd/nand/{ => raw}/jz4780_bch.h            |   0
 drivers/mtd/nand/{ => raw}/jz4780_nand.c           |   0
 drivers/mtd/nand/{ => raw}/lpc32xx_mlc.c           |   0
 drivers/mtd/nand/{ => raw}/lpc32xx_slc.c           |   0
 drivers/mtd/nand/{ => raw}/mpc5121_nfc.c           |   0
 drivers/mtd/nand/{ => raw}/mtk_ecc.c               |   0
 drivers/mtd/nand/{ => raw}/mtk_ecc.h               |   0
 drivers/mtd/nand/{ => raw}/mtk_nand.c              |   0
 drivers/mtd/nand/{ => raw}/mxc_nand.c              |   0
 drivers/mtd/nand/{ => raw}/nand_base.c             |   0
 drivers/mtd/nand/{ => raw}/nand_bbt.c              |   0
 drivers/mtd/nand/{ => raw}/nand_bch.c              |   0
 drivers/mtd/nand/{ => raw}/nand_ecc.c              |   0
 drivers/mtd/nand/{ => raw}/nand_ids.c              |   0
 drivers/mtd/nand/{ => raw}/nand_timings.c          |   0
 drivers/mtd/nand/{ => raw}/nandsim.c               |   0
 drivers/mtd/nand/{ => raw}/ndfc.c                  |   0
 drivers/mtd/nand/{ => raw}/nuc900_nand.c           |   0
 drivers/mtd/nand/{ => raw}/omap2.c                 |   0
 drivers/mtd/nand/{ => raw}/omap_elm.c              |   0
 drivers/mtd/nand/{ => raw}/orion_nand.c            |   0
 drivers/mtd/nand/{ => raw}/pasemi_nand.c           |   0
 drivers/mtd/nand/{ => raw}/plat_nand.c             |   0
 drivers/mtd/nand/{ => raw}/pxa3xx_nand.c           |   0
 drivers/mtd/nand/{ => raw}/qcom_nandc.c            |   0
 drivers/mtd/nand/{ => raw}/r852.c                  |   0
 drivers/mtd/nand/{ => raw}/r852.h                  |   0
 drivers/mtd/nand/{ => raw}/s3c2410.c               |   0
 drivers/mtd/nand/{ => raw}/sh_flctl.c              |   0
 drivers/mtd/nand/{ => raw}/sharpsl.c               |   0
 drivers/mtd/nand/{ => raw}/sm_common.c             |   0
 drivers/mtd/nand/{ => raw}/sm_common.h             |   0
 drivers/mtd/nand/{ => raw}/socrates_nand.c         |   0
 drivers/mtd/nand/{ => raw}/sunxi_nand.c            |   0
 drivers/mtd/nand/{ => raw}/tmio_nand.c             |   0
 drivers/mtd/nand/{ => raw}/txx9ndfmc.c             |   0
 drivers/mtd/nand/{ => raw}/vf610_nfc.c             |   0
 drivers/mtd/nand/{ => raw}/xway_nand.c             |   0
 drivers/mtd/sm_ftl.c                               |   2 +-
 84 files changed, 637 insertions(+), 635 deletions(-)
 create mode 100644 drivers/mtd/nand/raw/Kconfig
 create mode 100644 drivers/mtd/nand/raw/Makefile
 rename drivers/mtd/nand/{ => raw}/ams-delta.c (100%)
 rename drivers/mtd/nand/{ => raw}/atmel_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/atmel_nand_ecc.h (100%)
 rename drivers/mtd/nand/{ => raw}/atmel_nand_nfc.h (100%)
 rename drivers/mtd/nand/{ => raw}/au1550nd.c (100%)
 rename drivers/mtd/nand/{ => raw}/bcm47xxnflash/Makefile (100%)
 rename drivers/mtd/nand/{ => raw}/bcm47xxnflash/bcm47xxnflash.h (100%)
 rename drivers/mtd/nand/{ => raw}/bcm47xxnflash/main.c (100%)
 rename drivers/mtd/nand/{ => raw}/bcm47xxnflash/ops_bcm4706.c (100%)
 rename drivers/mtd/nand/{ => raw}/bf5xx_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/brcmnand/Makefile (100%)
 rename drivers/mtd/nand/{ => raw}/brcmnand/bcm63138_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/brcmnand/bcm6368_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/brcmnand/brcmnand.c (100%)
 rename drivers/mtd/nand/{ => raw}/brcmnand/brcmnand.h (100%)
 rename drivers/mtd/nand/{ => raw}/brcmnand/brcmstb_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/brcmnand/iproc_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/cafe_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/cmx270_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/cs553x_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/davinci_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/denali.c (100%)
 rename drivers/mtd/nand/{ => raw}/denali.h (100%)
 rename drivers/mtd/nand/{ => raw}/denali_dt.c (100%)
 rename drivers/mtd/nand/{ => raw}/denali_pci.c (100%)
 rename drivers/mtd/nand/{ => raw}/diskonchip.c (100%)
 rename drivers/mtd/nand/{ => raw}/docg4.c (100%)
 rename drivers/mtd/nand/{ => raw}/fsl_elbc_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/fsl_ifc_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/fsl_upm.c (100%)
 rename drivers/mtd/nand/{ => raw}/fsmc_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/gpio.c (100%)
 rename drivers/mtd/nand/{ => raw}/gpmi-nand/Makefile (100%)
 rename drivers/mtd/nand/{ => raw}/gpmi-nand/bch-regs.h (100%)
 rename drivers/mtd/nand/{ => raw}/gpmi-nand/gpmi-lib.c (100%)
 rename drivers/mtd/nand/{ => raw}/gpmi-nand/gpmi-nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/gpmi-nand/gpmi-nand.h (100%)
 rename drivers/mtd/nand/{ => raw}/gpmi-nand/gpmi-regs.h (100%)
 rename drivers/mtd/nand/{ => raw}/hisi504_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/jz4740_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/jz4780_bch.c (100%)
 rename drivers/mtd/nand/{ => raw}/jz4780_bch.h (100%)
 rename drivers/mtd/nand/{ => raw}/jz4780_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/lpc32xx_mlc.c (100%)
 rename drivers/mtd/nand/{ => raw}/lpc32xx_slc.c (100%)
 rename drivers/mtd/nand/{ => raw}/mpc5121_nfc.c (100%)
 rename drivers/mtd/nand/{ => raw}/mtk_ecc.c (100%)
 rename drivers/mtd/nand/{ => raw}/mtk_ecc.h (100%)
 rename drivers/mtd/nand/{ => raw}/mtk_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/mxc_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/nand_base.c (100%)
 rename drivers/mtd/nand/{ => raw}/nand_bbt.c (100%)
 rename drivers/mtd/nand/{ => raw}/nand_bch.c (100%)
 rename drivers/mtd/nand/{ => raw}/nand_ecc.c (100%)
 rename drivers/mtd/nand/{ => raw}/nand_ids.c (100%)
 rename drivers/mtd/nand/{ => raw}/nand_timings.c (100%)
 rename drivers/mtd/nand/{ => raw}/nandsim.c (100%)
 rename drivers/mtd/nand/{ => raw}/ndfc.c (100%)
 rename drivers/mtd/nand/{ => raw}/nuc900_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/omap2.c (100%)
 rename drivers/mtd/nand/{ => raw}/omap_elm.c (100%)
 rename drivers/mtd/nand/{ => raw}/orion_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/pasemi_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/plat_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/pxa3xx_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/qcom_nandc.c (100%)
 rename drivers/mtd/nand/{ => raw}/r852.c (100%)
 rename drivers/mtd/nand/{ => raw}/r852.h (100%)
 rename drivers/mtd/nand/{ => raw}/s3c2410.c (100%)
 rename drivers/mtd/nand/{ => raw}/sh_flctl.c (100%)
 rename drivers/mtd/nand/{ => raw}/sharpsl.c (100%)
 rename drivers/mtd/nand/{ => raw}/sm_common.c (100%)
 rename drivers/mtd/nand/{ => raw}/sm_common.h (100%)
 rename drivers/mtd/nand/{ => raw}/socrates_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/sunxi_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/tmio_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/txx9ndfmc.c (100%)
 rename drivers/mtd/nand/{ => raw}/vf610_nfc.c (100%)
 rename drivers/mtd/nand/{ => raw}/xway_nand.c (100%)

diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 7b7a887b4709..6d5373471809 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -1,572 +1 @@
-config MTD_NAND_ECC
-	tristate
-
-config MTD_NAND_ECC_SMC
-	bool "NAND ECC Smart Media byte order"
-	depends on MTD_NAND_ECC
-	default n
-	help
-	  Software ECC according to the Smart Media Specification.
-	  The original Linux implementation had byte 0 and 1 swapped.
-
-
-menuconfig MTD_NAND
-	tristate "NAND Device Support"
-	depends on MTD
-	select MTD_NAND_IDS
-	select MTD_NAND_ECC
-	help
-	  This enables support for accessing all type of NAND flash
-	  devices. For further information see
-	  <http://www.linux-mtd.infradead.org/doc/nand.html>.
-
-if MTD_NAND
-
-config MTD_NAND_BCH
-	tristate
-	select BCH
-	depends on MTD_NAND_ECC_BCH
-	default MTD_NAND
-
-config MTD_NAND_ECC_BCH
-	bool "Support software BCH ECC"
-	default n
-	help
-	  This enables support for software BCH error correction. Binary BCH
-	  codes are more powerful and cpu intensive than traditional Hamming
-	  ECC codes. They are used with NAND devices requiring more than 1 bit
-	  of error correction.
-
-config MTD_SM_COMMON
-	tristate
-	default n
-
-config MTD_NAND_DENALI
-	tristate
-
-config MTD_NAND_DENALI_PCI
-        tristate "Support Denali NAND controller on Intel Moorestown"
-	select MTD_NAND_DENALI
-	depends on HAS_DMA && PCI
-        help
-          Enable the driver for NAND flash on Intel Moorestown, using the
-          Denali NAND controller core.
-
-config MTD_NAND_DENALI_DT
-	tristate "Support Denali NAND controller as a DT device"
-	select MTD_NAND_DENALI
-	depends on HAS_DMA && HAVE_CLK && OF
-	help
-	  Enable the driver for NAND flash on platforms using a Denali NAND
-	  controller as a DT device.
-
-config MTD_NAND_DENALI_SCRATCH_REG_ADDR
-        hex "Denali NAND size scratch register address"
-        default "0xFF108018"
-        depends on MTD_NAND_DENALI_PCI
-        help
-          Some platforms place the NAND chip size in a scratch register
-          because (some versions of) the driver aren't able to automatically
-          determine the size of certain chips. Set the address of the
-          scratch register here to enable this feature. On Intel Moorestown
-          boards, the scratch register is at 0xFF108018.
-
-config MTD_NAND_GPIO
-	tristate "GPIO assisted NAND Flash driver"
-	depends on GPIOLIB || COMPILE_TEST
-	depends on HAS_IOMEM
-	help
-	  This enables a NAND flash driver where control signals are
-	  connected to GPIO pins, and commands and data are communicated
-	  via a memory mapped interface.
-
-config MTD_NAND_AMS_DELTA
-	tristate "NAND Flash device on Amstrad E3"
-	depends on MACH_AMS_DELTA
-	default y
-	help
-	  Support for NAND flash on Amstrad E3 (Delta).
-
-config MTD_NAND_OMAP2
-	tristate "NAND Flash device on OMAP2, OMAP3, OMAP4 and Keystone"
-	depends on (ARCH_OMAP2PLUS || ARCH_KEYSTONE)
-	help
-          Support for NAND flash on Texas Instruments OMAP2, OMAP3, OMAP4
-	  and Keystone platforms.
-
-config MTD_NAND_OMAP_BCH
-	depends on MTD_NAND_OMAP2
-	bool "Support hardware based BCH error correction"
-	default n
-	select BCH
-	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 MTD_NAND_OMAP_BCH_BUILD
-	def_tristate MTD_NAND_OMAP2 && MTD_NAND_OMAP_BCH
-
-config MTD_NAND_IDS
-	tristate
-
-config MTD_NAND_RICOH
-	tristate "Ricoh xD card reader"
-	default n
-	depends on PCI
-	select MTD_SM_COMMON
-	help
-	  Enable support for Ricoh R5C852 xD card reader
-	  You also need to enable ether
-	  NAND SSFDC (SmartMedia) read only translation layer' or new
-	  expermental, readwrite
-	  'SmartMedia/xD new translation layer'
-
-config MTD_NAND_AU1550
-	tristate "Au1550/1200 NAND support"
-	depends on MIPS_ALCHEMY
-	help
-	  This enables the driver for the NAND flash controller on the
-	  AMD/Alchemy 1550 SOC.
-
-config MTD_NAND_BF5XX
-	tristate "Blackfin on-chip NAND Flash Controller driver"
-	depends on BF54x || BF52x
-	help
-	  This enables the Blackfin on-chip NAND flash controller
-
-	  No board specific support is done by this driver, each board
-	  must advertise a platform_device for the driver to attach.
-
-	  This driver can also be built as a module. If so, the module
-	  will be called bf5xx-nand.
-
-config MTD_NAND_BF5XX_HWECC
-	bool "BF5XX NAND Hardware ECC"
-	default y
-	depends on MTD_NAND_BF5XX
-	help
-	  Enable the use of the BF5XX's internal ECC generator when
-	  using NAND.
-
-config MTD_NAND_BF5XX_BOOTROM_ECC
-	bool "Use Blackfin BootROM ECC Layout"
-	default n
-	depends on MTD_NAND_BF5XX_HWECC
-	help
-	  If you wish to modify NAND pages and allow the Blackfin on-chip
-	  BootROM to boot from them, say Y here.  This is only necessary
-	  if you are booting U-Boot out of NAND and you wish to update
-	  U-Boot from Linux' userspace.  Otherwise, you should say N here.
-
-	  If unsure, say N.
-
-config MTD_NAND_S3C2410
-	tristate "NAND Flash support for Samsung S3C SoCs"
-	depends on ARCH_S3C24XX || ARCH_S3C64XX
-	help
-	  This enables the NAND flash controller on the S3C24xx and S3C64xx
-	  SoCs
-
-	  No board specific support is done by this driver, each board
-	  must advertise a platform_device for the driver to attach.
-
-config MTD_NAND_S3C2410_DEBUG
-	bool "Samsung S3C NAND driver debug"
-	depends on MTD_NAND_S3C2410
-	help
-	  Enable debugging of the S3C NAND driver
-
-config MTD_NAND_S3C2410_HWECC
-	bool "Samsung S3C NAND Hardware ECC"
-	depends on MTD_NAND_S3C2410
-	help
-	  Enable the use of the controller's internal ECC generator when
-	  using NAND. Early versions of the chips have had problems with
-	  incorrect ECC generation, and if using these, the default of
-	  software ECC is preferable.
-
-config MTD_NAND_NDFC
-	tristate "NDFC NanD Flash Controller"
-	depends on 4xx
-	select MTD_NAND_ECC_SMC
-	help
-	 NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs
-
-config MTD_NAND_S3C2410_CLKSTOP
-	bool "Samsung S3C NAND IDLE clock stop"
-	depends on MTD_NAND_S3C2410
-	default n
-	help
-	  Stop the clock to the NAND controller when there is no chip
-	  selected to save power. This will mean there is a small delay
-	  when the is NAND chip selected or released, but will save
-	  approximately 5mA of power when there is nothing happening.
-
-config MTD_NAND_DISKONCHIP
-	tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation)"
-	depends on HAS_IOMEM
-	select REED_SOLOMON
-	select REED_SOLOMON_DEC16
-	help
-	  This is a reimplementation of M-Systems DiskOnChip 2000,
-	  Millennium and Millennium Plus as a standard NAND device driver,
-	  as opposed to the earlier self-contained MTD device drivers.
-	  This should enable, among other things, proper JFFS2 operation on
-	  these devices.
-
-config MTD_NAND_DISKONCHIP_PROBE_ADVANCED
-        bool "Advanced detection options for DiskOnChip"
-        depends on MTD_NAND_DISKONCHIP
-        help
-          This option allows you to specify nonstandard address at which to
-          probe for a DiskOnChip, or to change the detection options.  You
-          are unlikely to need any of this unless you are using LinuxBIOS.
-          Say 'N'.
-
-config MTD_NAND_DISKONCHIP_PROBE_ADDRESS
-        hex "Physical address of DiskOnChip" if MTD_NAND_DISKONCHIP_PROBE_ADVANCED
-        depends on MTD_NAND_DISKONCHIP
-        default "0"
-        ---help---
-        By default, the probe for DiskOnChip devices will look for a
-        DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
-        This option allows you to specify a single address at which to probe
-        for the device, which is useful if you have other devices in that
-        range which get upset when they are probed.
-
-        (Note that on PowerPC, the normal probe will only check at
-        0xE4000000.)
-
-        Normally, you should leave this set to zero, to allow the probe at
-        the normal addresses.
-
-config MTD_NAND_DISKONCHIP_PROBE_HIGH
-        bool "Probe high addresses"
-        depends on MTD_NAND_DISKONCHIP_PROBE_ADVANCED
-        help
-          By default, the probe for DiskOnChip devices will look for a
-          DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
-          This option changes to make it probe between 0xFFFC8000 and
-          0xFFFEE000.  Unless you are using LinuxBIOS, this is unlikely to be
-          useful to you.  Say 'N'.
-
-config MTD_NAND_DISKONCHIP_BBTWRITE
-	bool "Allow BBT writes on DiskOnChip Millennium and 2000TSOP"
-	depends on MTD_NAND_DISKONCHIP
-	help
-	  On DiskOnChip devices shipped with the INFTL filesystem (Millennium
-	  and 2000 TSOP/Alon), Linux reserves some space at the end of the
-	  device for the Bad Block Table (BBT).  If you have existing INFTL
-	  data on your device (created by non-Linux tools such as M-Systems'
-	  DOS drivers), your data might overlap the area Linux wants to use for
-	  the BBT.  If this is a concern for you, leave this option disabled and
-	  Linux will not write BBT data into this area.
-	  The downside of leaving this option disabled is that if bad blocks
-	  are detected by Linux, they will not be recorded in the BBT, which
-	  could cause future problems.
-	  Once you enable this option, new filesystems (INFTL or others, created
-	  in Linux or other operating systems) will not use the reserved area.
-	  The only reason not to enable this option is to prevent damage to
-	  preexisting filesystems.
-	  Even if you leave this disabled, you can enable BBT writes at module
-	  load time (assuming you build diskonchip as a module) with the module
-	  parameter "inftl_bbt_write=1".
-
-config MTD_NAND_DOCG4
-	tristate "Support for DiskOnChip G4"
-	depends on HAS_IOMEM
-	select BCH
-	select BITREVERSE
-	help
-	  Support for diskonchip G4 nand flash, found in various smartphones and
-	  PDAs, among them the Palm Treo680, HTC Prophet and Wizard, Toshiba
-	  Portege G900, Asus P526, and O2 XDA Zinc.
-
-	  With this driver you will be able to use UBI and create a ubifs on the
-	  device, so you may wish to consider enabling UBI and UBIFS as well.
-
-	  These devices ship with the Mys/Sandisk SAFTL formatting, for which
-	  there is currently no mtd parser, so you may want to use command line
-	  partitioning to segregate write-protected blocks. On the Treo680, the
-	  first five erase blocks (256KiB each) are write-protected, followed
-	  by the block containing the saftl partition table.  This is probably
-	  typical.
-
-config MTD_NAND_SHARPSL
-	tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
-	depends on ARCH_PXA
-
-config MTD_NAND_CAFE
-	tristate "NAND support for OLPC CAF? chip"
-	depends on PCI
-	select REED_SOLOMON
-	select REED_SOLOMON_DEC16
-	help
-	  Use NAND flash attached to the CAF? chip designed for the OLPC
-	  laptop.
-
-config MTD_NAND_CS553X
-	tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)"
-	depends on X86_32
-	depends on !UML && HAS_IOMEM
-	help
-	  The CS553x companion chips for the AMD Geode processor
-	  include NAND flash controllers with built-in hardware ECC
-	  capabilities; enabling this option will allow you to use
-	  these. The driver will check the MSRs to verify that the
-	  controller is enabled for NAND, and currently requires that
-	  the controller be in MMIO mode.
-
-	  If you say "m", the module will be called cs553x_nand.
-
-config MTD_NAND_ATMEL
-	tristate "Support for NAND Flash / SmartMedia on AT91 and AVR32"
-	depends on ARCH_AT91 || AVR32
-	help
-	  Enables support for NAND Flash / Smart Media Card interface
-	  on Atmel AT91 and AVR32 processors.
-
-config MTD_NAND_PXA3xx
-	tristate "NAND support on PXA3xx and Armada 370/XP"
-	depends on PXA3xx || ARCH_MMP || PLAT_ORION
-	help
-	  This enables the driver for the NAND flash device found on
-	  PXA3xx processors (NFCv1) and also on Armada 370/XP (NFCv2).
-
-config MTD_NAND_SLC_LPC32XX
-	tristate "NXP LPC32xx SLC Controller"
-	depends on ARCH_LPC32XX
-	help
-	  Enables support for NXP's LPC32XX SLC (i.e. for Single Level Cell
-	  chips) NAND controller. This is the default for the PHYTEC 3250
-	  reference board which contains a NAND256R3A2CZA6 chip.
-
-	  Please check the actual NAND chip connected and its support
-	  by the SLC NAND controller.
-
-config MTD_NAND_MLC_LPC32XX
-	tristate "NXP LPC32xx MLC Controller"
-	depends on ARCH_LPC32XX
-	help
-	  Uses the LPC32XX MLC (i.e. for Multi Level Cell chips) NAND
-	  controller. This is the default for the WORK92105 controller
-	  board.
-
-	  Please check the actual NAND chip connected and its support
-	  by the MLC NAND controller.
-
-config MTD_NAND_CM_X270
-	tristate "Support for NAND Flash on CM-X270 modules"
-	depends on MACH_ARMCORE
-
-config MTD_NAND_PASEMI
-	tristate "NAND support for PA Semi PWRficient"
-	depends on PPC_PASEMI
-	help
-	  Enables support for NAND Flash interface on PA Semi PWRficient
-	  based boards
-
-config MTD_NAND_TMIO
-	tristate "NAND Flash device on Toshiba Mobile IO Controller"
-	depends on MFD_TMIO
-	help
-	  Support for NAND flash connected to a Toshiba Mobile IO
-	  Controller in some PDAs, including the Sharp SL6000x.
-
-config MTD_NAND_NANDSIM
-	tristate "Support for NAND Flash Simulator"
-	help
-	  The simulator may simulate various NAND flash chips for the
-	  MTD nand layer.
-
-config MTD_NAND_GPMI_NAND
-        tristate "GPMI NAND Flash Controller driver"
-        depends on MTD_NAND && MXS_DMA
-        help
-	 Enables NAND Flash support for IMX23, IMX28 or IMX6.
-	 The GPMI controller is very powerful, with the help of BCH
-	 module, it can do the hardware ECC. The GPMI supports several
-	 NAND flashs at the same time. The GPMI may conflicts with other
-	 block, such as SD card. So pay attention to it when you enable
-	 the GPMI.
-
-config MTD_NAND_BRCMNAND
-	tristate "Broadcom STB NAND controller"
-	depends on ARM || ARM64 || MIPS
-	help
-	  Enables the Broadcom NAND controller driver. The controller was
-	  originally designed for Set-Top Box but is used on various BCM7xxx,
-	  BCM3xxx, BCM63xxx, iProc/Cygnus and more.
-
-config MTD_NAND_BCM47XXNFLASH
-	tristate "Support for NAND flash on BCM4706 BCMA bus"
-	depends on BCMA_NFLASH
-	help
-	  BCMA bus can have various flash memories attached, they are
-	  registered by bcma as platform devices. This enables driver for
-	  NAND flash memories. For now only BCM4706 is supported.
-
-config MTD_NAND_PLATFORM
-	tristate "Support for generic platform NAND driver"
-	depends on HAS_IOMEM
-	help
-	  This implements a generic NAND driver for on-SOC platform
-	  devices. You will need to provide platform-specific functions
-	  via platform_data.
-
-config MTD_NAND_ORION
-	tristate "NAND Flash support for Marvell Orion SoC"
-	depends on PLAT_ORION
-	help
-	  This enables the NAND flash controller on Orion machines.
-
-	  No board specific support is done by this driver, each board
-	  must advertise a platform_device for the driver to attach.
-
-config MTD_NAND_FSL_ELBC
-	tristate "NAND support for Freescale eLBC controllers"
-	depends on FSL_SOC
-	select FSL_LBC
-	help
-	  Various Freescale chips, including the 8313, include a NAND Flash
-	  Controller Module with built-in hardware ECC capabilities.
-	  Enabling this option will enable you to use this to control
-	  external NAND devices.
-
-config MTD_NAND_FSL_IFC
-	tristate "NAND support for Freescale IFC controller"
-	depends on FSL_SOC || ARCH_LAYERSCAPE
-	select FSL_IFC
-	select MEMORY
-	help
-	  Various Freescale chips e.g P1010, include a NAND Flash machine
-	  with built-in hardware ECC capabilities.
-	  Enabling this option will enable you to use this to control
-	  external NAND devices.
-
-config MTD_NAND_FSL_UPM
-	tristate "Support for NAND on Freescale UPM"
-	depends on PPC_83xx || PPC_85xx
-	select FSL_LBC
-	help
-	  Enables support for NAND Flash chips wired onto Freescale PowerPC
-	  processor localbus with User-Programmable Machine support.
-
-config MTD_NAND_MPC5121_NFC
-	tristate "MPC5121 built-in NAND Flash Controller support"
-	depends on PPC_MPC512x
-	help
-	  This enables the driver for the NAND flash controller on the
-	  MPC5121 SoC.
-
-config MTD_NAND_VF610_NFC
-	tristate "Support for Freescale NFC for VF610/MPC5125"
-	depends on (SOC_VF610 || COMPILE_TEST)
-	depends on HAS_IOMEM
-	help
-	  Enables support for NAND Flash Controller on some Freescale
-	  processors like the VF610, MPC5125, MCF54418 or Kinetis K70.
-	  The driver supports a maximum 2k page size. With 2k pages and
-	  64 bytes or more of OOB, hardware ECC with up to 32-bit error
-	  correction is supported. Hardware ECC is only enabled through
-	  device tree.
-
-config MTD_NAND_MXC
-	tristate "MXC NAND support"
-	depends on ARCH_MXC
-	help
-	  This enables the driver for the NAND flash controller on the
-	  MXC processors.
-
-config MTD_NAND_SH_FLCTL
-	tristate "Support for NAND on Renesas SuperH FLCTL"
-	depends on SUPERH || COMPILE_TEST
-	depends on HAS_IOMEM
-	depends on HAS_DMA
-	help
-	  Several Renesas SuperH CPU has FLCTL. This option enables support
-	  for NAND Flash using FLCTL.
-
-config MTD_NAND_DAVINCI
-        tristate "Support NAND on DaVinci/Keystone SoC"
-        depends on ARCH_DAVINCI || (ARCH_KEYSTONE && TI_AEMIF)
-        help
-	  Enable the driver for NAND flash chips on Texas Instruments
-	  DaVinci/Keystone processors.
-
-config MTD_NAND_TXX9NDFMC
-	tristate "NAND Flash support for TXx9 SoC"
-	depends on SOC_TX4938 || SOC_TX4939
-	help
-	  This enables the NAND flash controller on the TXx9 SoCs.
-
-config MTD_NAND_SOCRATES
-	tristate "Support for NAND on Socrates board"
-	depends on SOCRATES
-	help
-	  Enables support for NAND Flash chips wired onto Socrates board.
-
-config MTD_NAND_NUC900
-	tristate "Support for NAND on Nuvoton NUC9xx/w90p910 evaluation boards."
-	depends on ARCH_W90X900
-	help
-	  This enables the driver for the NAND Flash on evaluation board based
-	  on w90p910 / NUC9xx.
-
-config MTD_NAND_JZ4740
-	tristate "Support for JZ4740 SoC NAND controller"
-	depends on MACH_JZ4740
-	help
-		Enables support for NAND Flash on JZ4740 SoC based boards.
-
-config MTD_NAND_JZ4780
-	tristate "Support for NAND on JZ4780 SoC"
-	depends on MACH_JZ4780 && JZ4780_NEMC
-	help
-	  Enables support for NAND Flash connected to the NEMC on JZ4780 SoC
-	  based boards, using the BCH controller for hardware error correction.
-
-config MTD_NAND_FSMC
-	tristate "Support for NAND on ST Micros FSMC"
-	depends on PLAT_SPEAR || ARCH_NOMADIK || ARCH_U8500 || MACH_U300
-	help
-	  Enables support for NAND Flash chips on the ST Microelectronics
-	  Flexible Static Memory Controller (FSMC)
-
-config MTD_NAND_XWAY
-	tristate "Support for NAND on Lantiq XWAY SoC"
-	depends on LANTIQ && SOC_TYPE_XWAY
-	help
-	  Enables support for NAND Flash chips on Lantiq XWAY SoCs. NAND is attached
-	  to the External Bus Unit (EBU).
-
-config MTD_NAND_SUNXI
-	tristate "Support for NAND on Allwinner SoCs"
-	depends on ARCH_SUNXI
-	help
-	  Enables support for NAND Flash chips on Allwinner SoCs.
-
-config MTD_NAND_HISI504
-	tristate "Support for NAND controller on Hisilicon SoC Hip04"
-	depends on HAS_DMA
-	help
-	  Enables support for NAND controller on Hisilicon SoC Hip04.
-
-config MTD_NAND_QCOM
-	tristate "Support for NAND on QCOM SoCs"
-	depends on ARCH_QCOM
-	help
-	  Enables support for NAND flash chips on SoCs containing the EBI2 NAND
-	  controller. This controller is found on IPQ806x SoC.
-
-config MTD_NAND_MTK
-	tristate "Support for NAND controller on MTK SoCs"
-	depends on HAS_DMA
-	help
-	  Enables support for NAND controller on MTK SoCs.
-	  This controller is found on mt27xx, mt81xx, mt65xx SoCs.
-
-endif # MTD_NAND
+source "drivers/mtd/nand/raw/Kconfig"
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index cafde6f3d957..eee2f27e92fc 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -1,62 +1 @@
-#
-# linux/drivers/nand/Makefile
-#
-
-obj-$(CONFIG_MTD_NAND)			+= nand.o
-obj-$(CONFIG_MTD_NAND_ECC)		+= nand_ecc.o
-obj-$(CONFIG_MTD_NAND_BCH)		+= nand_bch.o
-obj-$(CONFIG_MTD_NAND_IDS)		+= nand_ids.o
-obj-$(CONFIG_MTD_SM_COMMON) 		+= sm_common.o
-
-obj-$(CONFIG_MTD_NAND_CAFE)		+= cafe_nand.o
-obj-$(CONFIG_MTD_NAND_AMS_DELTA)	+= ams-delta.o
-obj-$(CONFIG_MTD_NAND_DENALI)		+= denali.o
-obj-$(CONFIG_MTD_NAND_DENALI_PCI)	+= denali_pci.o
-obj-$(CONFIG_MTD_NAND_DENALI_DT)	+= denali_dt.o
-obj-$(CONFIG_MTD_NAND_AU1550)		+= au1550nd.o
-obj-$(CONFIG_MTD_NAND_BF5XX)		+= bf5xx_nand.o
-obj-$(CONFIG_MTD_NAND_S3C2410)		+= s3c2410.o
-obj-$(CONFIG_MTD_NAND_DAVINCI)		+= davinci_nand.o
-obj-$(CONFIG_MTD_NAND_DISKONCHIP)	+= diskonchip.o
-obj-$(CONFIG_MTD_NAND_DOCG4)		+= docg4.o
-obj-$(CONFIG_MTD_NAND_FSMC)		+= fsmc_nand.o
-obj-$(CONFIG_MTD_NAND_SHARPSL)		+= sharpsl.o
-obj-$(CONFIG_MTD_NAND_NANDSIM)		+= nandsim.o
-obj-$(CONFIG_MTD_NAND_CS553X)		+= cs553x_nand.o
-obj-$(CONFIG_MTD_NAND_NDFC)		+= ndfc.o
-obj-$(CONFIG_MTD_NAND_ATMEL)		+= atmel_nand.o
-obj-$(CONFIG_MTD_NAND_GPIO)		+= gpio.o
-omap2_nand-objs := omap2.o
-obj-$(CONFIG_MTD_NAND_OMAP2) 		+= omap2_nand.o
-obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD)	+= omap_elm.o
-obj-$(CONFIG_MTD_NAND_CM_X270)		+= cmx270_nand.o
-obj-$(CONFIG_MTD_NAND_PXA3xx)		+= pxa3xx_nand.o
-obj-$(CONFIG_MTD_NAND_TMIO)		+= tmio_nand.o
-obj-$(CONFIG_MTD_NAND_PLATFORM)		+= plat_nand.o
-obj-$(CONFIG_MTD_NAND_PASEMI)		+= pasemi_nand.o
-obj-$(CONFIG_MTD_NAND_ORION)		+= orion_nand.o
-obj-$(CONFIG_MTD_NAND_FSL_ELBC)		+= fsl_elbc_nand.o
-obj-$(CONFIG_MTD_NAND_FSL_IFC)		+= fsl_ifc_nand.o
-obj-$(CONFIG_MTD_NAND_FSL_UPM)		+= fsl_upm.o
-obj-$(CONFIG_MTD_NAND_SLC_LPC32XX)      += lpc32xx_slc.o
-obj-$(CONFIG_MTD_NAND_MLC_LPC32XX)      += lpc32xx_mlc.o
-obj-$(CONFIG_MTD_NAND_SH_FLCTL)		+= sh_flctl.o
-obj-$(CONFIG_MTD_NAND_MXC)		+= mxc_nand.o
-obj-$(CONFIG_MTD_NAND_SOCRATES)		+= socrates_nand.o
-obj-$(CONFIG_MTD_NAND_TXX9NDFMC)	+= txx9ndfmc.o
-obj-$(CONFIG_MTD_NAND_NUC900)		+= nuc900_nand.o
-obj-$(CONFIG_MTD_NAND_MPC5121_NFC)	+= mpc5121_nfc.o
-obj-$(CONFIG_MTD_NAND_VF610_NFC)	+= vf610_nfc.o
-obj-$(CONFIG_MTD_NAND_RICOH)		+= r852.o
-obj-$(CONFIG_MTD_NAND_JZ4740)		+= jz4740_nand.o
-obj-$(CONFIG_MTD_NAND_JZ4780)		+= jz4780_nand.o jz4780_bch.o
-obj-$(CONFIG_MTD_NAND_GPMI_NAND)	+= gpmi-nand/
-obj-$(CONFIG_MTD_NAND_XWAY)		+= xway_nand.o
-obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH)	+= bcm47xxnflash/
-obj-$(CONFIG_MTD_NAND_SUNXI)		+= sunxi_nand.o
-obj-$(CONFIG_MTD_NAND_HISI504)	        += hisi504_nand.o
-obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= brcmnand/
-obj-$(CONFIG_MTD_NAND_QCOM)		+= qcom_nandc.o
-obj-$(CONFIG_MTD_NAND_MTK)		+= mtk_nand.o mtk_ecc.o
-
-nand-objs := nand_base.o nand_bbt.o nand_timings.o
+obj-y	+= raw/
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
new file mode 100644
index 000000000000..7b7a887b4709
--- /dev/null
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -0,0 +1,572 @@
+config MTD_NAND_ECC
+	tristate
+
+config MTD_NAND_ECC_SMC
+	bool "NAND ECC Smart Media byte order"
+	depends on MTD_NAND_ECC
+	default n
+	help
+	  Software ECC according to the Smart Media Specification.
+	  The original Linux implementation had byte 0 and 1 swapped.
+
+
+menuconfig MTD_NAND
+	tristate "NAND Device Support"
+	depends on MTD
+	select MTD_NAND_IDS
+	select MTD_NAND_ECC
+	help
+	  This enables support for accessing all type of NAND flash
+	  devices. For further information see
+	  <http://www.linux-mtd.infradead.org/doc/nand.html>.
+
+if MTD_NAND
+
+config MTD_NAND_BCH
+	tristate
+	select BCH
+	depends on MTD_NAND_ECC_BCH
+	default MTD_NAND
+
+config MTD_NAND_ECC_BCH
+	bool "Support software BCH ECC"
+	default n
+	help
+	  This enables support for software BCH error correction. Binary BCH
+	  codes are more powerful and cpu intensive than traditional Hamming
+	  ECC codes. They are used with NAND devices requiring more than 1 bit
+	  of error correction.
+
+config MTD_SM_COMMON
+	tristate
+	default n
+
+config MTD_NAND_DENALI
+	tristate
+
+config MTD_NAND_DENALI_PCI
+        tristate "Support Denali NAND controller on Intel Moorestown"
+	select MTD_NAND_DENALI
+	depends on HAS_DMA && PCI
+        help
+          Enable the driver for NAND flash on Intel Moorestown, using the
+          Denali NAND controller core.
+
+config MTD_NAND_DENALI_DT
+	tristate "Support Denali NAND controller as a DT device"
+	select MTD_NAND_DENALI
+	depends on HAS_DMA && HAVE_CLK && OF
+	help
+	  Enable the driver for NAND flash on platforms using a Denali NAND
+	  controller as a DT device.
+
+config MTD_NAND_DENALI_SCRATCH_REG_ADDR
+        hex "Denali NAND size scratch register address"
+        default "0xFF108018"
+        depends on MTD_NAND_DENALI_PCI
+        help
+          Some platforms place the NAND chip size in a scratch register
+          because (some versions of) the driver aren't able to automatically
+          determine the size of certain chips. Set the address of the
+          scratch register here to enable this feature. On Intel Moorestown
+          boards, the scratch register is at 0xFF108018.
+
+config MTD_NAND_GPIO
+	tristate "GPIO assisted NAND Flash driver"
+	depends on GPIOLIB || COMPILE_TEST
+	depends on HAS_IOMEM
+	help
+	  This enables a NAND flash driver where control signals are
+	  connected to GPIO pins, and commands and data are communicated
+	  via a memory mapped interface.
+
+config MTD_NAND_AMS_DELTA
+	tristate "NAND Flash device on Amstrad E3"
+	depends on MACH_AMS_DELTA
+	default y
+	help
+	  Support for NAND flash on Amstrad E3 (Delta).
+
+config MTD_NAND_OMAP2
+	tristate "NAND Flash device on OMAP2, OMAP3, OMAP4 and Keystone"
+	depends on (ARCH_OMAP2PLUS || ARCH_KEYSTONE)
+	help
+          Support for NAND flash on Texas Instruments OMAP2, OMAP3, OMAP4
+	  and Keystone platforms.
+
+config MTD_NAND_OMAP_BCH
+	depends on MTD_NAND_OMAP2
+	bool "Support hardware based BCH error correction"
+	default n
+	select BCH
+	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 MTD_NAND_OMAP_BCH_BUILD
+	def_tristate MTD_NAND_OMAP2 && MTD_NAND_OMAP_BCH
+
+config MTD_NAND_IDS
+	tristate
+
+config MTD_NAND_RICOH
+	tristate "Ricoh xD card reader"
+	default n
+	depends on PCI
+	select MTD_SM_COMMON
+	help
+	  Enable support for Ricoh R5C852 xD card reader
+	  You also need to enable ether
+	  NAND SSFDC (SmartMedia) read only translation layer' or new
+	  expermental, readwrite
+	  'SmartMedia/xD new translation layer'
+
+config MTD_NAND_AU1550
+	tristate "Au1550/1200 NAND support"
+	depends on MIPS_ALCHEMY
+	help
+	  This enables the driver for the NAND flash controller on the
+	  AMD/Alchemy 1550 SOC.
+
+config MTD_NAND_BF5XX
+	tristate "Blackfin on-chip NAND Flash Controller driver"
+	depends on BF54x || BF52x
+	help
+	  This enables the Blackfin on-chip NAND flash controller
+
+	  No board specific support is done by this driver, each board
+	  must advertise a platform_device for the driver to attach.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called bf5xx-nand.
+
+config MTD_NAND_BF5XX_HWECC
+	bool "BF5XX NAND Hardware ECC"
+	default y
+	depends on MTD_NAND_BF5XX
+	help
+	  Enable the use of the BF5XX's internal ECC generator when
+	  using NAND.
+
+config MTD_NAND_BF5XX_BOOTROM_ECC
+	bool "Use Blackfin BootROM ECC Layout"
+	default n
+	depends on MTD_NAND_BF5XX_HWECC
+	help
+	  If you wish to modify NAND pages and allow the Blackfin on-chip
+	  BootROM to boot from them, say Y here.  This is only necessary
+	  if you are booting U-Boot out of NAND and you wish to update
+	  U-Boot from Linux' userspace.  Otherwise, you should say N here.
+
+	  If unsure, say N.
+
+config MTD_NAND_S3C2410
+	tristate "NAND Flash support for Samsung S3C SoCs"
+	depends on ARCH_S3C24XX || ARCH_S3C64XX
+	help
+	  This enables the NAND flash controller on the S3C24xx and S3C64xx
+	  SoCs
+
+	  No board specific support is done by this driver, each board
+	  must advertise a platform_device for the driver to attach.
+
+config MTD_NAND_S3C2410_DEBUG
+	bool "Samsung S3C NAND driver debug"
+	depends on MTD_NAND_S3C2410
+	help
+	  Enable debugging of the S3C NAND driver
+
+config MTD_NAND_S3C2410_HWECC
+	bool "Samsung S3C NAND Hardware ECC"
+	depends on MTD_NAND_S3C2410
+	help
+	  Enable the use of the controller's internal ECC generator when
+	  using NAND. Early versions of the chips have had problems with
+	  incorrect ECC generation, and if using these, the default of
+	  software ECC is preferable.
+
+config MTD_NAND_NDFC
+	tristate "NDFC NanD Flash Controller"
+	depends on 4xx
+	select MTD_NAND_ECC_SMC
+	help
+	 NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs
+
+config MTD_NAND_S3C2410_CLKSTOP
+	bool "Samsung S3C NAND IDLE clock stop"
+	depends on MTD_NAND_S3C2410
+	default n
+	help
+	  Stop the clock to the NAND controller when there is no chip
+	  selected to save power. This will mean there is a small delay
+	  when the is NAND chip selected or released, but will save
+	  approximately 5mA of power when there is nothing happening.
+
+config MTD_NAND_DISKONCHIP
+	tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation)"
+	depends on HAS_IOMEM
+	select REED_SOLOMON
+	select REED_SOLOMON_DEC16
+	help
+	  This is a reimplementation of M-Systems DiskOnChip 2000,
+	  Millennium and Millennium Plus as a standard NAND device driver,
+	  as opposed to the earlier self-contained MTD device drivers.
+	  This should enable, among other things, proper JFFS2 operation on
+	  these devices.
+
+config MTD_NAND_DISKONCHIP_PROBE_ADVANCED
+        bool "Advanced detection options for DiskOnChip"
+        depends on MTD_NAND_DISKONCHIP
+        help
+          This option allows you to specify nonstandard address at which to
+          probe for a DiskOnChip, or to change the detection options.  You
+          are unlikely to need any of this unless you are using LinuxBIOS.
+          Say 'N'.
+
+config MTD_NAND_DISKONCHIP_PROBE_ADDRESS
+        hex "Physical address of DiskOnChip" if MTD_NAND_DISKONCHIP_PROBE_ADVANCED
+        depends on MTD_NAND_DISKONCHIP
+        default "0"
+        ---help---
+        By default, the probe for DiskOnChip devices will look for a
+        DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
+        This option allows you to specify a single address at which to probe
+        for the device, which is useful if you have other devices in that
+        range which get upset when they are probed.
+
+        (Note that on PowerPC, the normal probe will only check at
+        0xE4000000.)
+
+        Normally, you should leave this set to zero, to allow the probe at
+        the normal addresses.
+
+config MTD_NAND_DISKONCHIP_PROBE_HIGH
+        bool "Probe high addresses"
+        depends on MTD_NAND_DISKONCHIP_PROBE_ADVANCED
+        help
+          By default, the probe for DiskOnChip devices will look for a
+          DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
+          This option changes to make it probe between 0xFFFC8000 and
+          0xFFFEE000.  Unless you are using LinuxBIOS, this is unlikely to be
+          useful to you.  Say 'N'.
+
+config MTD_NAND_DISKONCHIP_BBTWRITE
+	bool "Allow BBT writes on DiskOnChip Millennium and 2000TSOP"
+	depends on MTD_NAND_DISKONCHIP
+	help
+	  On DiskOnChip devices shipped with the INFTL filesystem (Millennium
+	  and 2000 TSOP/Alon), Linux reserves some space at the end of the
+	  device for the Bad Block Table (BBT).  If you have existing INFTL
+	  data on your device (created by non-Linux tools such as M-Systems'
+	  DOS drivers), your data might overlap the area Linux wants to use for
+	  the BBT.  If this is a concern for you, leave this option disabled and
+	  Linux will not write BBT data into this area.
+	  The downside of leaving this option disabled is that if bad blocks
+	  are detected by Linux, they will not be recorded in the BBT, which
+	  could cause future problems.
+	  Once you enable this option, new filesystems (INFTL or others, created
+	  in Linux or other operating systems) will not use the reserved area.
+	  The only reason not to enable this option is to prevent damage to
+	  preexisting filesystems.
+	  Even if you leave this disabled, you can enable BBT writes at module
+	  load time (assuming you build diskonchip as a module) with the module
+	  parameter "inftl_bbt_write=1".
+
+config MTD_NAND_DOCG4
+	tristate "Support for DiskOnChip G4"
+	depends on HAS_IOMEM
+	select BCH
+	select BITREVERSE
+	help
+	  Support for diskonchip G4 nand flash, found in various smartphones and
+	  PDAs, among them the Palm Treo680, HTC Prophet and Wizard, Toshiba
+	  Portege G900, Asus P526, and O2 XDA Zinc.
+
+	  With this driver you will be able to use UBI and create a ubifs on the
+	  device, so you may wish to consider enabling UBI and UBIFS as well.
+
+	  These devices ship with the Mys/Sandisk SAFTL formatting, for which
+	  there is currently no mtd parser, so you may want to use command line
+	  partitioning to segregate write-protected blocks. On the Treo680, the
+	  first five erase blocks (256KiB each) are write-protected, followed
+	  by the block containing the saftl partition table.  This is probably
+	  typical.
+
+config MTD_NAND_SHARPSL
+	tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
+	depends on ARCH_PXA
+
+config MTD_NAND_CAFE
+	tristate "NAND support for OLPC CAF? chip"
+	depends on PCI
+	select REED_SOLOMON
+	select REED_SOLOMON_DEC16
+	help
+	  Use NAND flash attached to the CAF? chip designed for the OLPC
+	  laptop.
+
+config MTD_NAND_CS553X
+	tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)"
+	depends on X86_32
+	depends on !UML && HAS_IOMEM
+	help
+	  The CS553x companion chips for the AMD Geode processor
+	  include NAND flash controllers with built-in hardware ECC
+	  capabilities; enabling this option will allow you to use
+	  these. The driver will check the MSRs to verify that the
+	  controller is enabled for NAND, and currently requires that
+	  the controller be in MMIO mode.
+
+	  If you say "m", the module will be called cs553x_nand.
+
+config MTD_NAND_ATMEL
+	tristate "Support for NAND Flash / SmartMedia on AT91 and AVR32"
+	depends on ARCH_AT91 || AVR32
+	help
+	  Enables support for NAND Flash / Smart Media Card interface
+	  on Atmel AT91 and AVR32 processors.
+
+config MTD_NAND_PXA3xx
+	tristate "NAND support on PXA3xx and Armada 370/XP"
+	depends on PXA3xx || ARCH_MMP || PLAT_ORION
+	help
+	  This enables the driver for the NAND flash device found on
+	  PXA3xx processors (NFCv1) and also on Armada 370/XP (NFCv2).
+
+config MTD_NAND_SLC_LPC32XX
+	tristate "NXP LPC32xx SLC Controller"
+	depends on ARCH_LPC32XX
+	help
+	  Enables support for NXP's LPC32XX SLC (i.e. for Single Level Cell
+	  chips) NAND controller. This is the default for the PHYTEC 3250
+	  reference board which contains a NAND256R3A2CZA6 chip.
+
+	  Please check the actual NAND chip connected and its support
+	  by the SLC NAND controller.
+
+config MTD_NAND_MLC_LPC32XX
+	tristate "NXP LPC32xx MLC Controller"
+	depends on ARCH_LPC32XX
+	help
+	  Uses the LPC32XX MLC (i.e. for Multi Level Cell chips) NAND
+	  controller. This is the default for the WORK92105 controller
+	  board.
+
+	  Please check the actual NAND chip connected and its support
+	  by the MLC NAND controller.
+
+config MTD_NAND_CM_X270
+	tristate "Support for NAND Flash on CM-X270 modules"
+	depends on MACH_ARMCORE
+
+config MTD_NAND_PASEMI
+	tristate "NAND support for PA Semi PWRficient"
+	depends on PPC_PASEMI
+	help
+	  Enables support for NAND Flash interface on PA Semi PWRficient
+	  based boards
+
+config MTD_NAND_TMIO
+	tristate "NAND Flash device on Toshiba Mobile IO Controller"
+	depends on MFD_TMIO
+	help
+	  Support for NAND flash connected to a Toshiba Mobile IO
+	  Controller in some PDAs, including the Sharp SL6000x.
+
+config MTD_NAND_NANDSIM
+	tristate "Support for NAND Flash Simulator"
+	help
+	  The simulator may simulate various NAND flash chips for the
+	  MTD nand layer.
+
+config MTD_NAND_GPMI_NAND
+        tristate "GPMI NAND Flash Controller driver"
+        depends on MTD_NAND && MXS_DMA
+        help
+	 Enables NAND Flash support for IMX23, IMX28 or IMX6.
+	 The GPMI controller is very powerful, with the help of BCH
+	 module, it can do the hardware ECC. The GPMI supports several
+	 NAND flashs at the same time. The GPMI may conflicts with other
+	 block, such as SD card. So pay attention to it when you enable
+	 the GPMI.
+
+config MTD_NAND_BRCMNAND
+	tristate "Broadcom STB NAND controller"
+	depends on ARM || ARM64 || MIPS
+	help
+	  Enables the Broadcom NAND controller driver. The controller was
+	  originally designed for Set-Top Box but is used on various BCM7xxx,
+	  BCM3xxx, BCM63xxx, iProc/Cygnus and more.
+
+config MTD_NAND_BCM47XXNFLASH
+	tristate "Support for NAND flash on BCM4706 BCMA bus"
+	depends on BCMA_NFLASH
+	help
+	  BCMA bus can have various flash memories attached, they are
+	  registered by bcma as platform devices. This enables driver for
+	  NAND flash memories. For now only BCM4706 is supported.
+
+config MTD_NAND_PLATFORM
+	tristate "Support for generic platform NAND driver"
+	depends on HAS_IOMEM
+	help
+	  This implements a generic NAND driver for on-SOC platform
+	  devices. You will need to provide platform-specific functions
+	  via platform_data.
+
+config MTD_NAND_ORION
+	tristate "NAND Flash support for Marvell Orion SoC"
+	depends on PLAT_ORION
+	help
+	  This enables the NAND flash controller on Orion machines.
+
+	  No board specific support is done by this driver, each board
+	  must advertise a platform_device for the driver to attach.
+
+config MTD_NAND_FSL_ELBC
+	tristate "NAND support for Freescale eLBC controllers"
+	depends on FSL_SOC
+	select FSL_LBC
+	help
+	  Various Freescale chips, including the 8313, include a NAND Flash
+	  Controller Module with built-in hardware ECC capabilities.
+	  Enabling this option will enable you to use this to control
+	  external NAND devices.
+
+config MTD_NAND_FSL_IFC
+	tristate "NAND support for Freescale IFC controller"
+	depends on FSL_SOC || ARCH_LAYERSCAPE
+	select FSL_IFC
+	select MEMORY
+	help
+	  Various Freescale chips e.g P1010, include a NAND Flash machine
+	  with built-in hardware ECC capabilities.
+	  Enabling this option will enable you to use this to control
+	  external NAND devices.
+
+config MTD_NAND_FSL_UPM
+	tristate "Support for NAND on Freescale UPM"
+	depends on PPC_83xx || PPC_85xx
+	select FSL_LBC
+	help
+	  Enables support for NAND Flash chips wired onto Freescale PowerPC
+	  processor localbus with User-Programmable Machine support.
+
+config MTD_NAND_MPC5121_NFC
+	tristate "MPC5121 built-in NAND Flash Controller support"
+	depends on PPC_MPC512x
+	help
+	  This enables the driver for the NAND flash controller on the
+	  MPC5121 SoC.
+
+config MTD_NAND_VF610_NFC
+	tristate "Support for Freescale NFC for VF610/MPC5125"
+	depends on (SOC_VF610 || COMPILE_TEST)
+	depends on HAS_IOMEM
+	help
+	  Enables support for NAND Flash Controller on some Freescale
+	  processors like the VF610, MPC5125, MCF54418 or Kinetis K70.
+	  The driver supports a maximum 2k page size. With 2k pages and
+	  64 bytes or more of OOB, hardware ECC with up to 32-bit error
+	  correction is supported. Hardware ECC is only enabled through
+	  device tree.
+
+config MTD_NAND_MXC
+	tristate "MXC NAND support"
+	depends on ARCH_MXC
+	help
+	  This enables the driver for the NAND flash controller on the
+	  MXC processors.
+
+config MTD_NAND_SH_FLCTL
+	tristate "Support for NAND on Renesas SuperH FLCTL"
+	depends on SUPERH || COMPILE_TEST
+	depends on HAS_IOMEM
+	depends on HAS_DMA
+	help
+	  Several Renesas SuperH CPU has FLCTL. This option enables support
+	  for NAND Flash using FLCTL.
+
+config MTD_NAND_DAVINCI
+        tristate "Support NAND on DaVinci/Keystone SoC"
+        depends on ARCH_DAVINCI || (ARCH_KEYSTONE && TI_AEMIF)
+        help
+	  Enable the driver for NAND flash chips on Texas Instruments
+	  DaVinci/Keystone processors.
+
+config MTD_NAND_TXX9NDFMC
+	tristate "NAND Flash support for TXx9 SoC"
+	depends on SOC_TX4938 || SOC_TX4939
+	help
+	  This enables the NAND flash controller on the TXx9 SoCs.
+
+config MTD_NAND_SOCRATES
+	tristate "Support for NAND on Socrates board"
+	depends on SOCRATES
+	help
+	  Enables support for NAND Flash chips wired onto Socrates board.
+
+config MTD_NAND_NUC900
+	tristate "Support for NAND on Nuvoton NUC9xx/w90p910 evaluation boards."
+	depends on ARCH_W90X900
+	help
+	  This enables the driver for the NAND Flash on evaluation board based
+	  on w90p910 / NUC9xx.
+
+config MTD_NAND_JZ4740
+	tristate "Support for JZ4740 SoC NAND controller"
+	depends on MACH_JZ4740
+	help
+		Enables support for NAND Flash on JZ4740 SoC based boards.
+
+config MTD_NAND_JZ4780
+	tristate "Support for NAND on JZ4780 SoC"
+	depends on MACH_JZ4780 && JZ4780_NEMC
+	help
+	  Enables support for NAND Flash connected to the NEMC on JZ4780 SoC
+	  based boards, using the BCH controller for hardware error correction.
+
+config MTD_NAND_FSMC
+	tristate "Support for NAND on ST Micros FSMC"
+	depends on PLAT_SPEAR || ARCH_NOMADIK || ARCH_U8500 || MACH_U300
+	help
+	  Enables support for NAND Flash chips on the ST Microelectronics
+	  Flexible Static Memory Controller (FSMC)
+
+config MTD_NAND_XWAY
+	tristate "Support for NAND on Lantiq XWAY SoC"
+	depends on LANTIQ && SOC_TYPE_XWAY
+	help
+	  Enables support for NAND Flash chips on Lantiq XWAY SoCs. NAND is attached
+	  to the External Bus Unit (EBU).
+
+config MTD_NAND_SUNXI
+	tristate "Support for NAND on Allwinner SoCs"
+	depends on ARCH_SUNXI
+	help
+	  Enables support for NAND Flash chips on Allwinner SoCs.
+
+config MTD_NAND_HISI504
+	tristate "Support for NAND controller on Hisilicon SoC Hip04"
+	depends on HAS_DMA
+	help
+	  Enables support for NAND controller on Hisilicon SoC Hip04.
+
+config MTD_NAND_QCOM
+	tristate "Support for NAND on QCOM SoCs"
+	depends on ARCH_QCOM
+	help
+	  Enables support for NAND flash chips on SoCs containing the EBI2 NAND
+	  controller. This controller is found on IPQ806x SoC.
+
+config MTD_NAND_MTK
+	tristate "Support for NAND controller on MTK SoCs"
+	depends on HAS_DMA
+	help
+	  Enables support for NAND controller on MTK SoCs.
+	  This controller is found on mt27xx, mt81xx, mt65xx SoCs.
+
+endif # MTD_NAND
diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile
new file mode 100644
index 000000000000..cafde6f3d957
--- /dev/null
+++ b/drivers/mtd/nand/raw/Makefile
@@ -0,0 +1,62 @@
+#
+# linux/drivers/nand/Makefile
+#
+
+obj-$(CONFIG_MTD_NAND)			+= nand.o
+obj-$(CONFIG_MTD_NAND_ECC)		+= nand_ecc.o
+obj-$(CONFIG_MTD_NAND_BCH)		+= nand_bch.o
+obj-$(CONFIG_MTD_NAND_IDS)		+= nand_ids.o
+obj-$(CONFIG_MTD_SM_COMMON) 		+= sm_common.o
+
+obj-$(CONFIG_MTD_NAND_CAFE)		+= cafe_nand.o
+obj-$(CONFIG_MTD_NAND_AMS_DELTA)	+= ams-delta.o
+obj-$(CONFIG_MTD_NAND_DENALI)		+= denali.o
+obj-$(CONFIG_MTD_NAND_DENALI_PCI)	+= denali_pci.o
+obj-$(CONFIG_MTD_NAND_DENALI_DT)	+= denali_dt.o
+obj-$(CONFIG_MTD_NAND_AU1550)		+= au1550nd.o
+obj-$(CONFIG_MTD_NAND_BF5XX)		+= bf5xx_nand.o
+obj-$(CONFIG_MTD_NAND_S3C2410)		+= s3c2410.o
+obj-$(CONFIG_MTD_NAND_DAVINCI)		+= davinci_nand.o
+obj-$(CONFIG_MTD_NAND_DISKONCHIP)	+= diskonchip.o
+obj-$(CONFIG_MTD_NAND_DOCG4)		+= docg4.o
+obj-$(CONFIG_MTD_NAND_FSMC)		+= fsmc_nand.o
+obj-$(CONFIG_MTD_NAND_SHARPSL)		+= sharpsl.o
+obj-$(CONFIG_MTD_NAND_NANDSIM)		+= nandsim.o
+obj-$(CONFIG_MTD_NAND_CS553X)		+= cs553x_nand.o
+obj-$(CONFIG_MTD_NAND_NDFC)		+= ndfc.o
+obj-$(CONFIG_MTD_NAND_ATMEL)		+= atmel_nand.o
+obj-$(CONFIG_MTD_NAND_GPIO)		+= gpio.o
+omap2_nand-objs := omap2.o
+obj-$(CONFIG_MTD_NAND_OMAP2) 		+= omap2_nand.o
+obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD)	+= omap_elm.o
+obj-$(CONFIG_MTD_NAND_CM_X270)		+= cmx270_nand.o
+obj-$(CONFIG_MTD_NAND_PXA3xx)		+= pxa3xx_nand.o
+obj-$(CONFIG_MTD_NAND_TMIO)		+= tmio_nand.o
+obj-$(CONFIG_MTD_NAND_PLATFORM)		+= plat_nand.o
+obj-$(CONFIG_MTD_NAND_PASEMI)		+= pasemi_nand.o
+obj-$(CONFIG_MTD_NAND_ORION)		+= orion_nand.o
+obj-$(CONFIG_MTD_NAND_FSL_ELBC)		+= fsl_elbc_nand.o
+obj-$(CONFIG_MTD_NAND_FSL_IFC)		+= fsl_ifc_nand.o
+obj-$(CONFIG_MTD_NAND_FSL_UPM)		+= fsl_upm.o
+obj-$(CONFIG_MTD_NAND_SLC_LPC32XX)      += lpc32xx_slc.o
+obj-$(CONFIG_MTD_NAND_MLC_LPC32XX)      += lpc32xx_mlc.o
+obj-$(CONFIG_MTD_NAND_SH_FLCTL)		+= sh_flctl.o
+obj-$(CONFIG_MTD_NAND_MXC)		+= mxc_nand.o
+obj-$(CONFIG_MTD_NAND_SOCRATES)		+= socrates_nand.o
+obj-$(CONFIG_MTD_NAND_TXX9NDFMC)	+= txx9ndfmc.o
+obj-$(CONFIG_MTD_NAND_NUC900)		+= nuc900_nand.o
+obj-$(CONFIG_MTD_NAND_MPC5121_NFC)	+= mpc5121_nfc.o
+obj-$(CONFIG_MTD_NAND_VF610_NFC)	+= vf610_nfc.o
+obj-$(CONFIG_MTD_NAND_RICOH)		+= r852.o
+obj-$(CONFIG_MTD_NAND_JZ4740)		+= jz4740_nand.o
+obj-$(CONFIG_MTD_NAND_JZ4780)		+= jz4780_nand.o jz4780_bch.o
+obj-$(CONFIG_MTD_NAND_GPMI_NAND)	+= gpmi-nand/
+obj-$(CONFIG_MTD_NAND_XWAY)		+= xway_nand.o
+obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH)	+= bcm47xxnflash/
+obj-$(CONFIG_MTD_NAND_SUNXI)		+= sunxi_nand.o
+obj-$(CONFIG_MTD_NAND_HISI504)	        += hisi504_nand.o
+obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= brcmnand/
+obj-$(CONFIG_MTD_NAND_QCOM)		+= qcom_nandc.o
+obj-$(CONFIG_MTD_NAND_MTK)		+= mtk_nand.o mtk_ecc.o
+
+nand-objs := nand_base.o nand_bbt.o nand_timings.o
diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/raw/ams-delta.c
similarity index 100%
rename from drivers/mtd/nand/ams-delta.c
rename to drivers/mtd/nand/raw/ams-delta.c
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/raw/atmel_nand.c
similarity index 100%
rename from drivers/mtd/nand/atmel_nand.c
rename to drivers/mtd/nand/raw/atmel_nand.c
diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/raw/atmel_nand_ecc.h
similarity index 100%
rename from drivers/mtd/nand/atmel_nand_ecc.h
rename to drivers/mtd/nand/raw/atmel_nand_ecc.h
diff --git a/drivers/mtd/nand/atmel_nand_nfc.h b/drivers/mtd/nand/raw/atmel_nand_nfc.h
similarity index 100%
rename from drivers/mtd/nand/atmel_nand_nfc.h
rename to drivers/mtd/nand/raw/atmel_nand_nfc.h
diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/raw/au1550nd.c
similarity index 100%
rename from drivers/mtd/nand/au1550nd.c
rename to drivers/mtd/nand/raw/au1550nd.c
diff --git a/drivers/mtd/nand/bcm47xxnflash/Makefile b/drivers/mtd/nand/raw/bcm47xxnflash/Makefile
similarity index 100%
rename from drivers/mtd/nand/bcm47xxnflash/Makefile
rename to drivers/mtd/nand/raw/bcm47xxnflash/Makefile
diff --git a/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h b/drivers/mtd/nand/raw/bcm47xxnflash/bcm47xxnflash.h
similarity index 100%
rename from drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h
rename to drivers/mtd/nand/raw/bcm47xxnflash/bcm47xxnflash.h
diff --git a/drivers/mtd/nand/bcm47xxnflash/main.c b/drivers/mtd/nand/raw/bcm47xxnflash/main.c
similarity index 100%
rename from drivers/mtd/nand/bcm47xxnflash/main.c
rename to drivers/mtd/nand/raw/bcm47xxnflash/main.c
diff --git a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c
similarity index 100%
rename from drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c
rename to drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c
diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/raw/bf5xx_nand.c
similarity index 100%
rename from drivers/mtd/nand/bf5xx_nand.c
rename to drivers/mtd/nand/raw/bf5xx_nand.c
diff --git a/drivers/mtd/nand/brcmnand/Makefile b/drivers/mtd/nand/raw/brcmnand/Makefile
similarity index 100%
rename from drivers/mtd/nand/brcmnand/Makefile
rename to drivers/mtd/nand/raw/brcmnand/Makefile
diff --git a/drivers/mtd/nand/brcmnand/bcm63138_nand.c b/drivers/mtd/nand/raw/brcmnand/bcm63138_nand.c
similarity index 100%
rename from drivers/mtd/nand/brcmnand/bcm63138_nand.c
rename to drivers/mtd/nand/raw/brcmnand/bcm63138_nand.c
diff --git a/drivers/mtd/nand/brcmnand/bcm6368_nand.c b/drivers/mtd/nand/raw/brcmnand/bcm6368_nand.c
similarity index 100%
rename from drivers/mtd/nand/brcmnand/bcm6368_nand.c
rename to drivers/mtd/nand/raw/brcmnand/bcm6368_nand.c
diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
similarity index 100%
rename from drivers/mtd/nand/brcmnand/brcmnand.c
rename to drivers/mtd/nand/raw/brcmnand/brcmnand.c
diff --git a/drivers/mtd/nand/brcmnand/brcmnand.h b/drivers/mtd/nand/raw/brcmnand/brcmnand.h
similarity index 100%
rename from drivers/mtd/nand/brcmnand/brcmnand.h
rename to drivers/mtd/nand/raw/brcmnand/brcmnand.h
diff --git a/drivers/mtd/nand/brcmnand/brcmstb_nand.c b/drivers/mtd/nand/raw/brcmnand/brcmstb_nand.c
similarity index 100%
rename from drivers/mtd/nand/brcmnand/brcmstb_nand.c
rename to drivers/mtd/nand/raw/brcmnand/brcmstb_nand.c
diff --git a/drivers/mtd/nand/brcmnand/iproc_nand.c b/drivers/mtd/nand/raw/brcmnand/iproc_nand.c
similarity index 100%
rename from drivers/mtd/nand/brcmnand/iproc_nand.c
rename to drivers/mtd/nand/raw/brcmnand/iproc_nand.c
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/raw/cafe_nand.c
similarity index 100%
rename from drivers/mtd/nand/cafe_nand.c
rename to drivers/mtd/nand/raw/cafe_nand.c
diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/raw/cmx270_nand.c
similarity index 100%
rename from drivers/mtd/nand/cmx270_nand.c
rename to drivers/mtd/nand/raw/cmx270_nand.c
diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/raw/cs553x_nand.c
similarity index 100%
rename from drivers/mtd/nand/cs553x_nand.c
rename to drivers/mtd/nand/raw/cs553x_nand.c
diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c
similarity index 100%
rename from drivers/mtd/nand/davinci_nand.c
rename to drivers/mtd/nand/raw/davinci_nand.c
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/raw/denali.c
similarity index 100%
rename from drivers/mtd/nand/denali.c
rename to drivers/mtd/nand/raw/denali.c
diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/raw/denali.h
similarity index 100%
rename from drivers/mtd/nand/denali.h
rename to drivers/mtd/nand/raw/denali.h
diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/raw/denali_dt.c
similarity index 100%
rename from drivers/mtd/nand/denali_dt.c
rename to drivers/mtd/nand/raw/denali_dt.c
diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/raw/denali_pci.c
similarity index 100%
rename from drivers/mtd/nand/denali_pci.c
rename to drivers/mtd/nand/raw/denali_pci.c
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/raw/diskonchip.c
similarity index 100%
rename from drivers/mtd/nand/diskonchip.c
rename to drivers/mtd/nand/raw/diskonchip.c
diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/raw/docg4.c
similarity index 100%
rename from drivers/mtd/nand/docg4.c
rename to drivers/mtd/nand/raw/docg4.c
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/raw/fsl_elbc_nand.c
similarity index 100%
rename from drivers/mtd/nand/fsl_elbc_nand.c
rename to drivers/mtd/nand/raw/fsl_elbc_nand.c
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/raw/fsl_ifc_nand.c
similarity index 100%
rename from drivers/mtd/nand/fsl_ifc_nand.c
rename to drivers/mtd/nand/raw/fsl_ifc_nand.c
diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/raw/fsl_upm.c
similarity index 100%
rename from drivers/mtd/nand/fsl_upm.c
rename to drivers/mtd/nand/raw/fsl_upm.c
diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c
similarity index 100%
rename from drivers/mtd/nand/fsmc_nand.c
rename to drivers/mtd/nand/raw/fsmc_nand.c
diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/raw/gpio.c
similarity index 100%
rename from drivers/mtd/nand/gpio.c
rename to drivers/mtd/nand/raw/gpio.c
diff --git a/drivers/mtd/nand/gpmi-nand/Makefile b/drivers/mtd/nand/raw/gpmi-nand/Makefile
similarity index 100%
rename from drivers/mtd/nand/gpmi-nand/Makefile
rename to drivers/mtd/nand/raw/gpmi-nand/Makefile
diff --git a/drivers/mtd/nand/gpmi-nand/bch-regs.h b/drivers/mtd/nand/raw/gpmi-nand/bch-regs.h
similarity index 100%
rename from drivers/mtd/nand/gpmi-nand/bch-regs.h
rename to drivers/mtd/nand/raw/gpmi-nand/bch-regs.h
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c
similarity index 100%
rename from drivers/mtd/nand/gpmi-nand/gpmi-lib.c
rename to drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
similarity index 100%
rename from drivers/mtd/nand/gpmi-nand/gpmi-nand.c
rename to drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h
similarity index 100%
rename from drivers/mtd/nand/gpmi-nand/gpmi-nand.h
rename to drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-regs.h b/drivers/mtd/nand/raw/gpmi-nand/gpmi-regs.h
similarity index 100%
rename from drivers/mtd/nand/gpmi-nand/gpmi-regs.h
rename to drivers/mtd/nand/raw/gpmi-nand/gpmi-regs.h
diff --git a/drivers/mtd/nand/hisi504_nand.c b/drivers/mtd/nand/raw/hisi504_nand.c
similarity index 100%
rename from drivers/mtd/nand/hisi504_nand.c
rename to drivers/mtd/nand/raw/hisi504_nand.c
diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/raw/jz4740_nand.c
similarity index 100%
rename from drivers/mtd/nand/jz4740_nand.c
rename to drivers/mtd/nand/raw/jz4740_nand.c
diff --git a/drivers/mtd/nand/jz4780_bch.c b/drivers/mtd/nand/raw/jz4780_bch.c
similarity index 100%
rename from drivers/mtd/nand/jz4780_bch.c
rename to drivers/mtd/nand/raw/jz4780_bch.c
diff --git a/drivers/mtd/nand/jz4780_bch.h b/drivers/mtd/nand/raw/jz4780_bch.h
similarity index 100%
rename from drivers/mtd/nand/jz4780_bch.h
rename to drivers/mtd/nand/raw/jz4780_bch.h
diff --git a/drivers/mtd/nand/jz4780_nand.c b/drivers/mtd/nand/raw/jz4780_nand.c
similarity index 100%
rename from drivers/mtd/nand/jz4780_nand.c
rename to drivers/mtd/nand/raw/jz4780_nand.c
diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/raw/lpc32xx_mlc.c
similarity index 100%
rename from drivers/mtd/nand/lpc32xx_mlc.c
rename to drivers/mtd/nand/raw/lpc32xx_mlc.c
diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/raw/lpc32xx_slc.c
similarity index 100%
rename from drivers/mtd/nand/lpc32xx_slc.c
rename to drivers/mtd/nand/raw/lpc32xx_slc.c
diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/raw/mpc5121_nfc.c
similarity index 100%
rename from drivers/mtd/nand/mpc5121_nfc.c
rename to drivers/mtd/nand/raw/mpc5121_nfc.c
diff --git a/drivers/mtd/nand/mtk_ecc.c b/drivers/mtd/nand/raw/mtk_ecc.c
similarity index 100%
rename from drivers/mtd/nand/mtk_ecc.c
rename to drivers/mtd/nand/raw/mtk_ecc.c
diff --git a/drivers/mtd/nand/mtk_ecc.h b/drivers/mtd/nand/raw/mtk_ecc.h
similarity index 100%
rename from drivers/mtd/nand/mtk_ecc.h
rename to drivers/mtd/nand/raw/mtk_ecc.h
diff --git a/drivers/mtd/nand/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c
similarity index 100%
rename from drivers/mtd/nand/mtk_nand.c
rename to drivers/mtd/nand/raw/mtk_nand.c
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/raw/mxc_nand.c
similarity index 100%
rename from drivers/mtd/nand/mxc_nand.c
rename to drivers/mtd/nand/raw/mxc_nand.c
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
similarity index 100%
rename from drivers/mtd/nand/nand_base.c
rename to drivers/mtd/nand/raw/nand_base.c
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/raw/nand_bbt.c
similarity index 100%
rename from drivers/mtd/nand/nand_bbt.c
rename to drivers/mtd/nand/raw/nand_bbt.c
diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/raw/nand_bch.c
similarity index 100%
rename from drivers/mtd/nand/nand_bch.c
rename to drivers/mtd/nand/raw/nand_bch.c
diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/raw/nand_ecc.c
similarity index 100%
rename from drivers/mtd/nand/nand_ecc.c
rename to drivers/mtd/nand/raw/nand_ecc.c
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/raw/nand_ids.c
similarity index 100%
rename from drivers/mtd/nand/nand_ids.c
rename to drivers/mtd/nand/raw/nand_ids.c
diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/raw/nand_timings.c
similarity index 100%
rename from drivers/mtd/nand/nand_timings.c
rename to drivers/mtd/nand/raw/nand_timings.c
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/raw/nandsim.c
similarity index 100%
rename from drivers/mtd/nand/nandsim.c
rename to drivers/mtd/nand/raw/nandsim.c
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/raw/ndfc.c
similarity index 100%
rename from drivers/mtd/nand/ndfc.c
rename to drivers/mtd/nand/raw/ndfc.c
diff --git a/drivers/mtd/nand/nuc900_nand.c b/drivers/mtd/nand/raw/nuc900_nand.c
similarity index 100%
rename from drivers/mtd/nand/nuc900_nand.c
rename to drivers/mtd/nand/raw/nuc900_nand.c
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/raw/omap2.c
similarity index 100%
rename from drivers/mtd/nand/omap2.c
rename to drivers/mtd/nand/raw/omap2.c
diff --git a/drivers/mtd/nand/omap_elm.c b/drivers/mtd/nand/raw/omap_elm.c
similarity index 100%
rename from drivers/mtd/nand/omap_elm.c
rename to drivers/mtd/nand/raw/omap_elm.c
diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/raw/orion_nand.c
similarity index 100%
rename from drivers/mtd/nand/orion_nand.c
rename to drivers/mtd/nand/raw/orion_nand.c
diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/raw/pasemi_nand.c
similarity index 100%
rename from drivers/mtd/nand/pasemi_nand.c
rename to drivers/mtd/nand/raw/pasemi_nand.c
diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/raw/plat_nand.c
similarity index 100%
rename from drivers/mtd/nand/plat_nand.c
rename to drivers/mtd/nand/raw/plat_nand.c
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/raw/pxa3xx_nand.c
similarity index 100%
rename from drivers/mtd/nand/pxa3xx_nand.c
rename to drivers/mtd/nand/raw/pxa3xx_nand.c
diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c
similarity index 100%
rename from drivers/mtd/nand/qcom_nandc.c
rename to drivers/mtd/nand/raw/qcom_nandc.c
diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/raw/r852.c
similarity index 100%
rename from drivers/mtd/nand/r852.c
rename to drivers/mtd/nand/raw/r852.c
diff --git a/drivers/mtd/nand/r852.h b/drivers/mtd/nand/raw/r852.h
similarity index 100%
rename from drivers/mtd/nand/r852.h
rename to drivers/mtd/nand/raw/r852.h
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/raw/s3c2410.c
similarity index 100%
rename from drivers/mtd/nand/s3c2410.c
rename to drivers/mtd/nand/raw/s3c2410.c
diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/raw/sh_flctl.c
similarity index 100%
rename from drivers/mtd/nand/sh_flctl.c
rename to drivers/mtd/nand/raw/sh_flctl.c
diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/raw/sharpsl.c
similarity index 100%
rename from drivers/mtd/nand/sharpsl.c
rename to drivers/mtd/nand/raw/sharpsl.c
diff --git a/drivers/mtd/nand/sm_common.c b/drivers/mtd/nand/raw/sm_common.c
similarity index 100%
rename from drivers/mtd/nand/sm_common.c
rename to drivers/mtd/nand/raw/sm_common.c
diff --git a/drivers/mtd/nand/sm_common.h b/drivers/mtd/nand/raw/sm_common.h
similarity index 100%
rename from drivers/mtd/nand/sm_common.h
rename to drivers/mtd/nand/raw/sm_common.h
diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/raw/socrates_nand.c
similarity index 100%
rename from drivers/mtd/nand/socrates_nand.c
rename to drivers/mtd/nand/raw/socrates_nand.c
diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c
similarity index 100%
rename from drivers/mtd/nand/sunxi_nand.c
rename to drivers/mtd/nand/raw/sunxi_nand.c
diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/raw/tmio_nand.c
similarity index 100%
rename from drivers/mtd/nand/tmio_nand.c
rename to drivers/mtd/nand/raw/tmio_nand.c
diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/raw/txx9ndfmc.c
similarity index 100%
rename from drivers/mtd/nand/txx9ndfmc.c
rename to drivers/mtd/nand/raw/txx9ndfmc.c
diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c
similarity index 100%
rename from drivers/mtd/nand/vf610_nfc.c
rename to drivers/mtd/nand/raw/vf610_nfc.c
diff --git a/drivers/mtd/nand/xway_nand.c b/drivers/mtd/nand/raw/xway_nand.c
similarity index 100%
rename from drivers/mtd/nand/xway_nand.c
rename to drivers/mtd/nand/raw/xway_nand.c
diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c
index 3692dd547879..bcc851d02440 100644
--- a/drivers/mtd/sm_ftl.c
+++ b/drivers/mtd/sm_ftl.c
@@ -17,7 +17,7 @@
 #include <linux/bitops.h>
 #include <linux/slab.h>
 #include <linux/mtd/nand_ecc.h>
-#include "nand/sm_common.h"
+#include "nand/raw/sm_common.h"
 #include "sm_ftl.h"
 
 
-- 
2.7.4



From boris.brezillon at free-electrons.com  Sun Oct 16 07:35:18 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Sun, 16 Oct 2016 16:35:18 +0200
Subject: [PATCH v2 7/7] mtd: nand: move BBT code to drivers/mtd/nand/
In-Reply-To: <1476628518-20450-1-git-send-email-boris.brezillon@free-electrons.com>
References: <1476628518-20450-1-git-send-email-boris.brezillon@free-electrons.com>
Message-ID: <1476628518-20450-8-git-send-email-boris.brezillon@free-electrons.com>

Now that the BBT code is generic, we can move it to drivers/mtd/nand/.

Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/Kconfig                   | 3 +++
 drivers/mtd/nand/Makefile                  | 4 ++++
 drivers/mtd/nand/{raw/nand_bbt.c => bbt.c} | 5 +++++
 drivers/mtd/nand/raw/Kconfig               | 1 +
 drivers/mtd/nand/raw/Makefile              | 2 +-
 5 files changed, 14 insertions(+), 1 deletion(-)
 rename drivers/mtd/nand/{raw/nand_bbt.c => bbt.c} (99%)

diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 6d5373471809..1c1a1f487e20 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -1 +1,4 @@
+config MTD_NAND_CORE
+	tristate
+
 source "drivers/mtd/nand/raw/Kconfig"
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index eee2f27e92fc..fe430d919224 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -1 +1,5 @@
+obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
+
+nandcore-objs :=  bbt.o
+
 obj-y	+= raw/
diff --git a/drivers/mtd/nand/raw/nand_bbt.c b/drivers/mtd/nand/bbt.c
similarity index 99%
rename from drivers/mtd/nand/raw/nand_bbt.c
rename to drivers/mtd/nand/bbt.c
index 0ad2c43adbd3..f308f1ed9fe0 100644
--- a/drivers/mtd/nand/raw/nand_bbt.c
+++ b/drivers/mtd/nand/bbt.c
@@ -1289,6 +1289,7 @@ int nand_scan_bbt(struct nand_device *this)
 	this->bbt.bbt = NULL;
 	return res;
 }
+EXPORT_SYMBOL_GPL(nand_scan_bbt);
 
 /**
  * nand_update_bbt - update bad block table(s)
@@ -1342,6 +1343,7 @@ int nand_update_bbt(struct nand_device *this, loff_t offs)
 	kfree(buf);
 	return res;
 }
+EXPORT_SYMBOL_GPL(nand_update_bbt);
 
 /**
  * nand_isreserved_bbt - [NAND Interface] Check if a block is reserved
@@ -1355,6 +1357,7 @@ int nand_isreserved_bbt(struct nand_device *this, loff_t offs)
 	block = nand_offs_to_eraseblock(this, offs);
 	return bbt_get_entry(this, block) == BBT_BLOCK_RESERVED;
 }
+EXPORT_SYMBOL_GPL(nand_isreserved_bbt);
 
 /**
  * nand_isbad_bbt - [NAND Interface] Check if a block is bad
@@ -1382,6 +1385,7 @@ int nand_isbad_bbt(struct nand_device *this, loff_t offs, int allowbbt)
 	}
 	return 1;
 }
+EXPORT_SYMBOL_GPL(nand_isbad_bbt);
 
 /**
  * nand_markbad_bbt - [NAND Interface] Mark a block bad in the BBT
@@ -1403,3 +1407,4 @@ int nand_markbad_bbt(struct nand_device *this, loff_t offs)
 
 	return ret;
 }
+EXPORT_SYMBOL_GPL(nand_markbad_bbt);
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
index 7b7a887b4709..9b4b90039dc3 100644
--- a/drivers/mtd/nand/raw/Kconfig
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -15,6 +15,7 @@ menuconfig MTD_NAND
 	depends on MTD
 	select MTD_NAND_IDS
 	select MTD_NAND_ECC
+	select MTD_NAND_CORE
 	help
 	  This enables support for accessing all type of NAND flash
 	  devices. For further information see
diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile
index cafde6f3d957..1df932034ae2 100644
--- a/drivers/mtd/nand/raw/Makefile
+++ b/drivers/mtd/nand/raw/Makefile
@@ -59,4 +59,4 @@ obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= brcmnand/
 obj-$(CONFIG_MTD_NAND_QCOM)		+= qcom_nandc.o
 obj-$(CONFIG_MTD_NAND_MTK)		+= mtk_nand.o mtk_ecc.o
 
-nand-objs := nand_base.o nand_bbt.o nand_timings.o
+nand-objs := nand_base.o nand_timings.o
-- 
2.7.4



From boris.brezillon at free-electrons.com  Sun Oct 16 07:35:16 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Sun, 16 Oct 2016 16:35:16 +0200
Subject: [PATCH v2 5/7] mtd: nand: raw: create struct rawnand_device
In-Reply-To: <1476628518-20450-1-git-send-email-boris.brezillon@free-electrons.com>
References: <1476628518-20450-1-git-send-email-boris.brezillon@free-electrons.com>
Message-ID: <1476628518-20450-6-git-send-email-boris.brezillon@free-electrons.com>

Create the rawnand_device struct inheriting from nand_device and make
nand_chip inherit from this struct.

The rawnand_device object should be used for the new
rawnand-device/rawnand-controller model, and fields inside nand_chip
should progressively move to the future rawnand_controller or the existing
rawnand_device struct.

In the meantime, we make sure nand_device fields are properly initialized
by converting information stored in mtd_info and nand_chip into the
nand_memory_organization format.

Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/raw/nand_base.c | 40 ++++++++++++++++++++++++++++++++++++++++
 include/linux/mtd/rawnand.h      | 26 ++++++++++++++++++++------
 2 files changed, 60 insertions(+), 6 deletions(-)

diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 6d8ab58d4eb5..b86f4a1bfbe1 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -3972,6 +3972,43 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
 	return false;
 }
 
+static int rawnand_erase(struct nand_device *nand, struct erase_info *einfo)
+{
+	struct mtd_info *mtd = nand_to_mtd(nand);
+
+	return nand_erase_nand(mtd, einfo, 1);
+}
+
+static int rawnand_markbad(struct nand_device *nand, int block)
+{
+	struct mtd_info *mtd = nand_to_mtd(nand);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
+	loff_t offs = nand_eraseblock_to_offs(nand, block);
+
+	return chip->block_markbad(mtd, offs);
+}
+
+static const struct nand_ops rawnand_ops = {
+	.erase = rawnand_erase,
+	.markbad = rawnand_markbad,
+};
+
+static void nandc_fill_nandd(struct nand_chip *chip)
+{
+	struct mtd_info *mtd = nandc_to_mtd(chip);
+	struct nand_device *nand = mtd_to_nand(mtd);
+	struct nand_memory_organization *memorg = &nand->memorg;
+
+	memorg->pagesize = mtd->writesize;
+	memorg->oobsize = mtd->oobsize;
+	memorg->eraseblocksize = mtd->erasesize;
+	memorg->ndies = chip->numchips;
+	memorg->diesize = chip->chipsize;
+	/* TODO: fill ->planesize and ->nplanes */
+
+	nand->ops = &rawnand_ops;
+}
+
 /*
  * Get the flash and manufacturer id and lookup if the type is supported.
  */
@@ -4357,6 +4394,9 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
 	chip->numchips = i;
 	mtd->size = i * chip->chipsize;
 
+	/* Fill nand_device info */
+	nandc_fill_nandd(chip);
+
 	return 0;
 }
 EXPORT_SYMBOL(nand_scan_ident);
diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
index 941218dec463..8efff12604ad 100644
--- a/include/linux/mtd/rawnand.h
+++ b/include/linux/mtd/rawnand.h
@@ -20,6 +20,7 @@
 #include <linux/spinlock.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/flashchip.h>
+#include <linux/mtd/nand.h>
 #include <linux/mtd/bbm.h>
 
 struct mtd_info;
@@ -689,8 +690,21 @@ nand_get_sdr_timings(const struct nand_data_interface *conf)
 }
 
 /**
+ * struct rawnand_device - raw NAND device structure
+ * @base: NAND device instance (inheritance)
+ *
+ * This structure describes a raw NAND device and should progressively
+ * replace the nand_chip struct.
+ *
+ * Note: do not blindly move nand_chip fields into rawnand_device.
+ */
+struct rawnand_device {
+	struct nand_device base;
+};
+
+/**
  * struct nand_chip - NAND Private Flash Chip Data
- * @mtd:		MTD device registered to the MTD framework
+ * @base:		raw NAND device instance (inheritance)
  * @IO_ADDR_R:		[BOARDSPECIFIC] address to read the 8 I/O lines of the
  *			flash device
  * @IO_ADDR_W:		[BOARDSPECIFIC] address to write the 8 I/O lines of the
@@ -790,7 +804,7 @@ nand_get_sdr_timings(const struct nand_data_interface *conf)
  */
 
 struct nand_chip {
-	struct mtd_info mtd;
+	struct rawnand_device base;
 	void __iomem *IO_ADDR_R;
 	void __iomem *IO_ADDR_W;
 
@@ -880,22 +894,22 @@ extern const struct mtd_ooblayout_ops nand_ooblayout_lp_ops;
 static inline void nand_set_flash_node(struct nand_chip *chip,
 				       struct device_node *np)
 {
-	mtd_set_of_node(&chip->mtd, np);
+	nand_set_of_node(&chip->base.base, np);
 }
 
 static inline struct device_node *nand_get_flash_node(struct nand_chip *chip)
 {
-	return mtd_get_of_node(&chip->mtd);
+	return nand_get_of_node(&chip->base.base);
 }
 
 static inline struct nand_chip *mtd_to_nandc(struct mtd_info *mtd)
 {
-	return container_of(mtd, struct nand_chip, mtd);
+	return container_of(mtd_to_nand(mtd), struct nand_chip, base.base);
 }
 
 static inline struct mtd_info *nandc_to_mtd(struct nand_chip *chip)
 {
-	return &chip->mtd;
+	return nand_to_mtd(&chip->base.base);
 }
 
 static inline void *nand_get_controller_data(struct nand_chip *chip)
-- 
2.7.4



From boris.brezillon at free-electrons.com  Sun Oct 16 07:35:17 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Sun, 16 Oct 2016 16:35:17 +0200
Subject: [PATCH v2 6/7] mtd: nand: raw: make BBT code more generic
In-Reply-To: <1476628518-20450-1-git-send-email-boris.brezillon@free-electrons.com>
References: <1476628518-20450-1-git-send-email-boris.brezillon@free-electrons.com>
Message-ID: <1476628518-20450-7-git-send-email-boris.brezillon@free-electrons.com>

BBT support is currently tightly tied to raw NAND, though this is the kind
of code we could share across all NAND based devices, no matter what
physical interface is to communicate with the NAND chip.

Make BBT code interface agnostic by replacing all occurrence of
struct nand_chip by struct nand_device, and move functions that are
specific to raw NANDs to drivers/mtd/nand/rawnand/nand_base.c.

Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/raw/nand_base.c |  78 ++++-
 drivers/mtd/nand/raw/nand_bbt.c  | 609 ++++++++++++++++++---------------------
 include/linux/mtd/nand.h         |   8 +
 include/linux/mtd/rawnand.h      |   4 -
 4 files changed, 361 insertions(+), 338 deletions(-)

diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index b86f4a1bfbe1..4930b3569de9 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -471,7 +471,7 @@ static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
 
 	/* Mark block bad in BBT */
 	if (chip->bbt) {
-		res = nand_markbad_bbt(mtd, ofs);
+		res = nand_markbad_bbt(mtd_to_nand(mtd), ofs);
 		if (!ret)
 			ret = res;
 	}
@@ -511,12 +511,12 @@ static int nand_check_wp(struct mtd_info *mtd)
  */
 static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs)
 {
-	struct nand_chip *chip = mtd_to_nandc(mtd);
+	struct nand_device *nand = mtd_to_nand(mtd);
 
-	if (!chip->bbt)
+	if (!nand->bbt.bbt)
 		return 0;
 	/* Return info from the table */
-	return nand_isreserved_bbt(mtd, ofs);
+	return nand_isreserved_bbt(nand, ofs);
 }
 
 /**
@@ -530,13 +530,14 @@ static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs)
  */
 static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int allowbbt)
 {
+	struct nand_device *nand = mtd_to_nand(mtd);
 	struct nand_chip *chip = mtd_to_nandc(mtd);
 
-	if (!chip->bbt)
+	if (!nand->bbt.bbt)
 		return chip->block_bad(mtd, ofs);
 
 	/* Return info from the table */
-	return nand_isbad_bbt(mtd, ofs, allowbbt);
+	return nand_isbad_bbt(nand, ofs, allowbbt);
 }
 
 /**
@@ -3310,6 +3311,71 @@ static void nand_shutdown(struct mtd_info *mtd)
 	nand_get_device(mtd, FL_PM_SUSPENDED);
 }
 
+/*
+ * Define some generic bad / good block scan pattern which are used
+ * while scanning a device for factory marked good / bad blocks.
+ */
+static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
+
+#define BADBLOCK_SCAN_MASK (~NAND_BBT_NO_OOB)
+
+/**
+ * nand_create_badblock_pattern - [INTERN] Creates a BBT descriptor structure
+ * @this: NAND chip to create descriptor for
+ *
+ * This function allocates and initializes a nand_bbt_descr for BBM detection
+ * based on the properties of @this. The new descriptor is stored in
+ * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when
+ * passed to this function.
+ */
+static int nand_create_badblock_pattern(struct nand_chip *chip)
+{
+	struct nand_device *this = &chip->base.base;
+	struct nand_bbt_descr *bd;
+	if (this->bbt.bbp) {
+		pr_warn("Bad block pattern already allocated; not replacing\n");
+		return -EINVAL;
+	}
+	bd = kzalloc(sizeof(*bd), GFP_KERNEL);
+	if (!bd)
+		return -ENOMEM;
+	bd->options = this->bbt.options & BADBLOCK_SCAN_MASK;
+	bd->offs = chip->badblockpos;
+	bd->len = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1;
+	bd->pattern = scan_ff_pattern;
+	bd->options |= NAND_BBT_DYNAMICSTRUCT;
+	this->bbt.bbp = bd;
+	return 0;
+}
+
+/**
+ * nand_default_bbt - [NAND Interface] Select a default bad block table for the device
+ * @mtd: MTD device structure
+ *
+ * This function selects the default bad block table support for the device and
+ * calls the nand_scan_bbt function.
+ */
+static int nand_default_bbt(struct mtd_info *mtd)
+{
+	struct nand_device *this = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
+	int ret;
+
+	/* Initialize BBT config from nand_chip info */
+	this->bbt.options = chip->bbt_options;
+	this->bbt.td = chip->bbt_td;
+	this->bbt.md = chip->bbt_md;
+	this->bbt.bbp = chip->badblock_pattern;
+
+	if (!this->bbt.bbp) {
+		ret = nand_create_badblock_pattern(chip);
+		if (ret)
+			return ret;
+	}
+
+	return nand_scan_bbt(this);
+}
+
 /* Set default functions */
 static void nand_set_defaults(struct nand_chip *chip, int busw)
 {
diff --git a/drivers/mtd/nand/raw/nand_bbt.c b/drivers/mtd/nand/raw/nand_bbt.c
index 3f2e785f4bfb..0ad2c43adbd3 100644
--- a/drivers/mtd/nand/raw/nand_bbt.c
+++ b/drivers/mtd/nand/raw/nand_bbt.c
@@ -76,20 +76,18 @@
 #define BBT_ENTRY_MASK		0x03
 #define BBT_ENTRY_SHIFT		2
 
-static int nand_update_bbt(struct mtd_info *mtd, loff_t offs);
-
-static inline uint8_t bbt_get_entry(struct nand_chip *chip, int block)
+static inline uint8_t bbt_get_entry(struct nand_device *chip, int block)
 {
-	uint8_t entry = chip->bbt[block >> BBT_ENTRY_SHIFT];
+	uint8_t entry = chip->bbt.bbt[block >> BBT_ENTRY_SHIFT];
 	entry >>= (block & BBT_ENTRY_MASK) * 2;
 	return entry & BBT_ENTRY_MASK;
 }
 
-static inline void bbt_mark_entry(struct nand_chip *chip, int block,
+static inline void bbt_mark_entry(struct nand_device *chip, int block,
 		uint8_t mark)
 {
 	uint8_t msk = (mark & BBT_ENTRY_MASK) << ((block & BBT_ENTRY_MASK) * 2);
-	chip->bbt[block >> BBT_ENTRY_SHIFT] |= msk;
+	chip->bbt.bbt[block >> BBT_ENTRY_SHIFT] |= msk;
 }
 
 static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td)
@@ -159,7 +157,7 @@ static u32 add_marker_len(struct nand_bbt_descr *td)
 
 /**
  * read_bbt - [GENERIC] Read the bad block table starting from page
- * @mtd: MTD device structure
+ * @this: NAND device
  * @buf: temporary buffer
  * @page: the starting page
  * @num: the number of bbt descriptors to read
@@ -168,11 +166,11 @@ static u32 add_marker_len(struct nand_bbt_descr *td)
  *
  * Read the bad block table starting from page.
  */
-static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
-		struct nand_bbt_descr *td, int offs)
+static int read_bbt(struct nand_device *this, uint8_t *buf, int page, int num,
+		    struct nand_bbt_descr *td, int offs)
 {
+	struct mtd_info *mtd = nand_to_mtd(this);
 	int res, ret = 0, i, j, act = 0;
-	struct nand_chip *this = mtd_to_nandc(mtd);
 	size_t retlen, len, totlen;
 	loff_t from;
 	int bits = td->options & NAND_BBT_NRBITS_MSK;
@@ -182,10 +180,10 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
 
 	totlen = (num * bits) >> 3;
 	marker_len = add_marker_len(td);
-	from = ((loff_t)page) << this->page_shift;
+	from = nand_page_to_offs(this, page);
 
 	while (totlen) {
-		len = min(totlen, (size_t)(1 << this->bbt_erase_shift));
+		len = min(totlen, nand_eraseblock_size(this));
 		if (marker_len) {
 			/*
 			 * In case the BBT marker is not in the OOB area it
@@ -199,11 +197,11 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
 		if (res < 0) {
 			if (mtd_is_eccerr(res)) {
 				pr_info("nand_bbt: ECC error in BBT at 0x%012llx\n",
-					from & ~mtd->writesize);
+					from & ~nand_page_size(this));
 				return res;
 			} else if (mtd_is_bitflip(res)) {
 				pr_info("nand_bbt: corrected error in BBT at 0x%012llx\n",
-					from & ~mtd->writesize);
+					from & ~nand_page_size(this));
 				ret = res;
 			} else {
 				pr_info("nand_bbt: error reading BBT\n");
@@ -220,8 +218,8 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
 					continue;
 				if (reserved_block_code && (tmp == reserved_block_code)) {
 					pr_info("nand_read_bbt: reserved block at 0x%012llx\n",
-						 (loff_t)(offs + act) <<
-						 this->bbt_erase_shift);
+						nand_eraseblock_to_offs(this,
+								offs + act));
 					bbt_mark_entry(this, offs + act,
 							BBT_BLOCK_RESERVED);
 					mtd->ecc_stats.bbtblocks++;
@@ -232,8 +230,8 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
 				 * move this message to pr_debug.
 				 */
 				pr_info("nand_read_bbt: bad block at 0x%012llx\n",
-					 (loff_t)(offs + act) <<
-					 this->bbt_erase_shift);
+					nand_eraseblock_to_offs(this,
+								offs + act));
 				/* Factory marked bad or worn out? */
 				if (tmp == 0)
 					bbt_mark_entry(this, offs + act,
@@ -252,7 +250,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
 
 /**
  * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page
- * @mtd: MTD device structure
+ * @this: NAND device
  * @buf: temporary buffer
  * @td: descriptor for the bad block table
  * @chip: read the table for a specific chip, -1 read all chips; applies only if
@@ -261,25 +259,26 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
  * Read the bad block table for all chips starting at a given page. We assume
  * that the bbt bits are in consecutive order.
  */
-static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip)
+static int read_abs_bbt(struct nand_device *this, uint8_t *buf,
+			struct nand_bbt_descr *td, int chip)
 {
-	struct nand_chip *this = mtd_to_nandc(mtd);
+	int ndies = nand_ndies(this);
 	int res = 0, i;
 
 	if (td->options & NAND_BBT_PERCHIP) {
-		int offs = 0;
-		for (i = 0; i < this->numchips; i++) {
+		int offs = 0, nbbd = nand_eraseblocks_per_die(this);
+		for (i = 0; i < ndies; i++) {
 			if (chip == -1 || chip == i)
-				res = read_bbt(mtd, buf, td->pages[i],
-					this->chipsize >> this->bbt_erase_shift,
-					td, offs);
+				res = read_bbt(this, buf, td->pages[i], nbbd,
+					       td, offs);
 			if (res)
 				return res;
-			offs += this->chipsize >> this->bbt_erase_shift;
+
+			offs += nbbd;
 		}
 	} else {
-		res = read_bbt(mtd, buf, td->pages[0],
-				mtd->size >> this->bbt_erase_shift, td, 0);
+		res = read_bbt(this, buf, td->pages[0],
+			       nand_neraseblocks(this), td, 0);
 		if (res)
 			return res;
 	}
@@ -287,9 +286,10 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 }
 
 /* BBT marker is in the first page, no OOB */
-static int scan_read_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
-			 struct nand_bbt_descr *td)
+static int scan_read_data(struct nand_device *this, uint8_t *buf, loff_t offs,
+			  struct nand_bbt_descr *td)
 {
+	struct mtd_info *mtd = nand_to_mtd(this);
 	size_t retlen;
 	size_t len;
 
@@ -302,7 +302,7 @@ static int scan_read_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
 
 /**
  * scan_read_oob - [GENERIC] Scan data+OOB region to buffer
- * @mtd: MTD device structure
+ * @this: NAND device
  * @buf: temporary buffer
  * @offs: offset at which to scan
  * @len: length of data region to read
@@ -311,19 +311,20 @@ static int scan_read_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
  * page,OOB,page,OOB,... in buf. Completes transfer and returns the "strongest"
  * ECC condition (error or bitflip). May quit on the first (non-ECC) error.
  */
-static int scan_read_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
+static int scan_read_oob(struct nand_device *this, uint8_t *buf, loff_t offs,
 			 size_t len)
 {
+	struct mtd_info *mtd = nand_to_mtd(this);
 	struct mtd_oob_ops ops;
 	int res, ret = 0;
 
 	ops.mode = MTD_OPS_PLACE_OOB;
 	ops.ooboffs = 0;
-	ops.ooblen = mtd->oobsize;
+	ops.ooblen = nand_per_page_oobsize(this);
 
 	while (len > 0) {
 		ops.datbuf = buf;
-		ops.len = min(len, (size_t)mtd->writesize);
+		ops.len = min(len, nand_page_size(this));
 		ops.oobbuf = buf + ops.len;
 
 		res = mtd_read_oob(mtd, offs, &ops);
@@ -334,31 +335,32 @@ static int scan_read_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
 				ret = res;
 		}
 
-		buf += mtd->oobsize + mtd->writesize;
-		len -= mtd->writesize;
-		offs += mtd->writesize;
+		buf += nand_per_page_oobsize(this) + nand_page_size(this);
+		len -= nand_page_size(this);
+		offs += nand_page_size(this);
 	}
 	return ret;
 }
 
-static int scan_read(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
-			 size_t len, struct nand_bbt_descr *td)
+static int scan_read(struct nand_device *this, uint8_t *buf, loff_t offs,
+		     size_t len, struct nand_bbt_descr *td)
 {
 	if (td->options & NAND_BBT_NO_OOB)
-		return scan_read_data(mtd, buf, offs, td);
+		return scan_read_data(this, buf, offs, td);
 	else
-		return scan_read_oob(mtd, buf, offs, len);
+		return scan_read_oob(this, buf, offs, len);
 }
 
 /* Scan write data with oob to flash */
-static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len,
+static int scan_write_bbt(struct nand_device *this, loff_t offs, size_t len,
 			  uint8_t *buf, uint8_t *oob)
 {
+	struct mtd_info *mtd = nand_to_mtd(this);
 	struct mtd_oob_ops ops;
 
 	ops.mode = MTD_OPS_PLACE_OOB;
 	ops.ooboffs = 0;
-	ops.ooblen = mtd->oobsize;
+	ops.ooblen = nand_per_page_oobsize(this);
 	ops.datbuf = buf;
 	ops.oobbuf = oob;
 	ops.len = len;
@@ -366,18 +368,19 @@ static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len,
 	return mtd_write_oob(mtd, offs, &ops);
 }
 
-static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td)
+static u32 bbt_get_ver_offs(struct nand_device *this,
+			    struct nand_bbt_descr *td)
 {
 	u32 ver_offs = td->veroffs;
 
 	if (!(td->options & NAND_BBT_NO_OOB))
-		ver_offs += mtd->writesize;
+		ver_offs += nand_page_size(this);
 	return ver_offs;
 }
 
 /**
  * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page
- * @mtd: MTD device structure
+ * @this: NAND device
  * @buf: temporary buffer
  * @td: descriptor for the bad block table
  * @md:	descriptor for the bad block table mirror
@@ -385,38 +388,37 @@ static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td)
  * Read the bad block table(s) for all chips starting at a given page. We
  * assume that the bbt bits are in consecutive order.
  */
-static void read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
+static void read_abs_bbts(struct nand_device *this, uint8_t *buf,
 			  struct nand_bbt_descr *td, struct nand_bbt_descr *md)
 {
-	struct nand_chip *this = mtd_to_nandc(mtd);
-
 	/* Read the primary version, if available */
 	if (td->options & NAND_BBT_VERSION) {
-		scan_read(mtd, buf, (loff_t)td->pages[0] << this->page_shift,
-			      mtd->writesize, td);
-		td->version[0] = buf[bbt_get_ver_offs(mtd, td)];
+		scan_read(this, buf, nand_page_to_offs(this, td->pages[0]),
+			  nand_page_size(this), td);
+		td->version[0] = buf[bbt_get_ver_offs(this, td)];
 		pr_info("Bad block table at page %d, version 0x%02X\n",
 			 td->pages[0], td->version[0]);
 	}
 
 	/* Read the mirror version, if available */
 	if (md && (md->options & NAND_BBT_VERSION)) {
-		scan_read(mtd, buf, (loff_t)md->pages[0] << this->page_shift,
-			      mtd->writesize, md);
-		md->version[0] = buf[bbt_get_ver_offs(mtd, md)];
+		scan_read(this, buf, nand_page_to_offs(this, td->pages[0]),
+			  nand_page_size(this), md);
+		md->version[0] = buf[bbt_get_ver_offs(this, md)];
 		pr_info("Bad block table at page %d, version 0x%02X\n",
 			 md->pages[0], md->version[0]);
 	}
 }
 
 /* Scan a given block partially */
-static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
+static int scan_block_fast(struct nand_device *this, struct nand_bbt_descr *bd,
 			   loff_t offs, uint8_t *buf, int numpages)
 {
+	struct mtd_info *mtd = nand_to_mtd(this);
 	struct mtd_oob_ops ops;
 	int j, ret;
 
-	ops.ooblen = mtd->oobsize;
+	ops.ooblen = nand_per_page_oobsize(this);
 	ops.oobbuf = buf;
 	ops.ooboffs = 0;
 	ops.datbuf = NULL;
@@ -435,14 +437,14 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
 		if (check_short_pattern(buf, bd))
 			return 1;
 
-		offs += mtd->writesize;
+		offs += nand_page_size(this);
 	}
 	return 0;
 }
 
 /**
  * create_bbt - [GENERIC] Create a bad block table by scanning the device
- * @mtd: MTD device structure
+ * @this: NAND device
  * @buf: temporary buffer
  * @bd: descriptor for the good/bad block search pattern
  * @chip: create the table for a specific chip, -1 read all chips; applies only
@@ -451,10 +453,10 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
  * Create a bad block table by scanning the device for the given good/bad block
  * identify pattern.
  */
-static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
-	struct nand_bbt_descr *bd, int chip)
+static int create_bbt(struct nand_device *this, uint8_t *buf,
+		      struct nand_bbt_descr *bd, int chip)
 {
-	struct nand_chip *this = mtd_to_nandc(mtd);
+	struct mtd_info *mtd = nand_to_mtd(this);
 	int i, numblocks, numpages;
 	int startblock;
 	loff_t from;
@@ -467,30 +469,31 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
 		numpages = 1;
 
 	if (chip == -1) {
-		numblocks = mtd->size >> this->bbt_erase_shift;
+		numblocks = nand_neraseblocks(this);
 		startblock = 0;
 		from = 0;
 	} else {
-		if (chip >= this->numchips) {
+		if (chip >= nand_ndies(this)) {
 			pr_warn("create_bbt(): chipnr (%d) > available chips (%d)\n",
-			       chip + 1, this->numchips);
+			       chip + 1, nand_ndies(this));
 			return -EINVAL;
 		}
-		numblocks = this->chipsize >> this->bbt_erase_shift;
+		numblocks = nand_eraseblocks_per_die(this);
 		startblock = chip * numblocks;
 		numblocks += startblock;
-		from = (loff_t)startblock << this->bbt_erase_shift;
+		from = nand_eraseblock_to_offs(this, startblock);
 	}
 
-	if (this->bbt_options & NAND_BBT_SCANLASTPAGE)
-		from += mtd->erasesize - (mtd->writesize * numpages);
+	if (this->bbt.options & NAND_BBT_SCANLASTPAGE)
+		from += nand_eraseblock_size(this) -
+			(nand_page_size(this) * numpages);
 
 	for (i = startblock; i < numblocks; i++) {
 		int ret;
 
 		BUG_ON(bd->options & NAND_BBT_NO_OOB);
 
-		ret = scan_block_fast(mtd, bd, from, buf, numpages);
+		ret = scan_block_fast(this, bd, from, buf, numpages);
 		if (ret < 0)
 			return ret;
 
@@ -501,14 +504,14 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
 			mtd->ecc_stats.badblocks++;
 		}
 
-		from += (1 << this->bbt_erase_shift);
+		from += nand_eraseblock_size(this);
 	}
 	return 0;
 }
 
 /**
  * search_bbt - [GENERIC] scan the device for a specific bad block table
- * @mtd: MTD device structure
+ * @this: NAND device
  * @buf: temporary buffer
  * @td: descriptor for the bad block table
  *
@@ -521,18 +524,17 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
  *
  * The bbt ident pattern resides in the oob area of the first page in a block.
  */
-static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td)
+static int search_bbt(struct nand_device *this, uint8_t *buf,
+		      struct nand_bbt_descr *td)
 {
-	struct nand_chip *this = mtd_to_nandc(mtd);
 	int i, chips;
 	int startblock, block, dir;
-	int scanlen = mtd->writesize + mtd->oobsize;
+	int scanlen = nand_page_size(this) + nand_per_page_oobsize(this);
 	int bbtblocks;
-	int blocktopage = this->bbt_erase_shift - this->page_shift;
 
 	/* Search direction top -> down? */
 	if (td->options & NAND_BBT_LASTBLOCK) {
-		startblock = (mtd->size >> this->bbt_erase_shift) - 1;
+		startblock = nand_neraseblocks(this) - 1;
 		dir = -1;
 	} else {
 		startblock = 0;
@@ -541,12 +543,12 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
 
 	/* Do we have a bbt per chip? */
 	if (td->options & NAND_BBT_PERCHIP) {
-		chips = this->numchips;
-		bbtblocks = this->chipsize >> this->bbt_erase_shift;
+		chips = nand_ndies(this);
+		bbtblocks = nand_eraseblocks_per_die(this);
 		startblock &= bbtblocks - 1;
 	} else {
 		chips = 1;
-		bbtblocks = mtd->size >> this->bbt_erase_shift;
+		bbtblocks = nand_neraseblocks(this);
 	}
 
 	for (i = 0; i < chips; i++) {
@@ -557,20 +559,21 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
 		for (block = 0; block < td->maxblocks; block++) {
 
 			int actblock = startblock + dir * block;
-			loff_t offs = (loff_t)actblock << this->bbt_erase_shift;
+			loff_t offs = nand_eraseblock_to_offs(this, actblock);
 
 			/* Read first page */
-			scan_read(mtd, buf, offs, mtd->writesize, td);
-			if (!check_pattern(buf, scanlen, mtd->writesize, td)) {
-				td->pages[i] = actblock << blocktopage;
+			scan_read(this, buf, offs, nand_page_size(this), td);
+			if (!check_pattern(buf, scanlen, nand_page_size(this), td)) {
+				td->pages[i] = nand_eraseblock_to_page(this,
+								  actblock);
 				if (td->options & NAND_BBT_VERSION) {
-					offs = bbt_get_ver_offs(mtd, td);
+					offs = bbt_get_ver_offs(this, td);
 					td->version[i] = buf[offs];
 				}
 				break;
 			}
 		}
-		startblock += this->chipsize >> this->bbt_erase_shift;
+		startblock += nand_eraseblocks_per_die(this);
 	}
 	/* Check, if we found a bbt for each requested chip */
 	for (i = 0; i < chips; i++) {
@@ -585,23 +588,23 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
 
 /**
  * search_read_bbts - [GENERIC] scan the device for bad block table(s)
- * @mtd: MTD device structure
+ * @this: NAND device
  * @buf: temporary buffer
  * @td: descriptor for the bad block table
  * @md: descriptor for the bad block table mirror
  *
  * Search and read the bad block table(s).
  */
-static void search_read_bbts(struct mtd_info *mtd, uint8_t *buf,
+static void search_read_bbts(struct nand_device *this, uint8_t *buf,
 			     struct nand_bbt_descr *td,
 			     struct nand_bbt_descr *md)
 {
 	/* Search the primary table */
-	search_bbt(mtd, buf, td);
+	search_bbt(this, buf, td);
 
 	/* Search the mirror table */
 	if (md)
-		search_bbt(mtd, buf, md);
+		search_bbt(this, buf, md);
 }
 
 /**
@@ -617,7 +620,7 @@ static void search_read_bbts(struct mtd_info *mtd, uint8_t *buf,
  * pointing to a valid block we re-use it, otherwise we search for the next
  * valid one.
  */
-static int get_bbt_block(struct nand_chip *this, struct nand_bbt_descr *td,
+static int get_bbt_block(struct nand_device *this, struct nand_bbt_descr *td,
 			 struct nand_bbt_descr *md, int chip)
 {
 	int startblock, dir, page, numblocks, i;
@@ -628,12 +631,11 @@ static int get_bbt_block(struct nand_chip *this, struct nand_bbt_descr *td,
 	 * td->pages.
 	 */
 	if (td->pages[chip] != -1)
-		return td->pages[chip] >>
-				(this->bbt_erase_shift - this->page_shift);
+		return nand_page_to_eraseblock(this, td->pages[chip]);
 
-	numblocks = (int)(this->chipsize >> this->bbt_erase_shift);
+	numblocks = nand_eraseblocks_per_die(this);
 	if (!(td->options & NAND_BBT_PERCHIP))
-		numblocks *= this->numchips;
+		numblocks *= nand_ndies(this);
 
 	/*
 	 * Automatic placement of the bad block table. Search direction
@@ -657,7 +659,7 @@ static int get_bbt_block(struct nand_chip *this, struct nand_bbt_descr *td,
 			continue;
 		}
 
-		page = block << (this->bbt_erase_shift - this->page_shift);
+		page = nand_eraseblock_to_page(this, block);
 
 		/* Check, if the block is used by the mirror table */
 		if (!md || md->pages[chip] != page)
@@ -679,18 +681,15 @@ static int get_bbt_block(struct nand_chip *this, struct nand_bbt_descr *td,
  * block as bad using a bad block marker and invalidating the associated
  * td->pages[] entry.
  */
-static void mark_bbt_block_bad(struct nand_chip *this,
+static void mark_bbt_block_bad(struct nand_device *this,
 			       struct nand_bbt_descr *td,
 			       int chip, int block)
 {
-	struct mtd_info *mtd = nandc_to_mtd(this);
-	loff_t to;
 	int res;
 
 	bbt_mark_entry(this, block, BBT_BLOCK_WORN);
 
-	to = (loff_t)block << this->bbt_erase_shift;
-	res = this->block_markbad(mtd, to);
+	res = nand_markbad(this, block);
 	if (res)
 		pr_warn("nand_bbt: error %d while marking block %d bad\n",
 			res, block);
@@ -700,7 +699,7 @@ static void mark_bbt_block_bad(struct nand_chip *this,
 
 /**
  * write_bbt - [GENERIC] (Re)write the bad block table
- * @mtd: MTD device structure
+ * @this: NAND device
  * @buf: temporary buffer
  * @td: descriptor for the bad block table
  * @md: descriptor for the bad block table mirror
@@ -708,11 +707,11 @@ static void mark_bbt_block_bad(struct nand_chip *this,
  *
  * (Re)write the bad block table.
  */
-static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
+static int write_bbt(struct nand_device *this, uint8_t *buf,
 		     struct nand_bbt_descr *td, struct nand_bbt_descr *md,
 		     int chipsel)
 {
-	struct nand_chip *this = mtd_to_nandc(mtd);
+	struct mtd_info *mtd = nand_to_mtd(this);
 	struct erase_info einfo;
 	int i, res, chip = 0;
 	int bits, page, offs, numblocks, sft, sftmsk;
@@ -723,7 +722,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
 	loff_t to;
 	struct mtd_oob_ops ops;
 
-	ops.ooblen = mtd->oobsize;
+	ops.ooblen = nand_per_page_oobsize(this);
 	ops.ooboffs = 0;
 	ops.datbuf = NULL;
 	ops.mode = MTD_OPS_PLACE_OOB;
@@ -732,16 +731,16 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
 		rcode = 0xff;
 	/* Write bad block table per chip rather than per device? */
 	if (td->options & NAND_BBT_PERCHIP) {
-		numblocks = (int)(this->chipsize >> this->bbt_erase_shift);
+		numblocks = nand_eraseblocks_per_die(this);
 		/* Full device write or specific chip? */
 		if (chipsel == -1) {
-			nrchips = this->numchips;
+			nrchips = nand_ndies(this);
 		} else {
 			nrchips = chipsel + 1;
 			chip = chipsel;
 		}
 	} else {
-		numblocks = (int)(mtd->size >> this->bbt_erase_shift);
+		numblocks = nand_neraseblocks(this);
 		nrchips = 1;
 	}
 
@@ -760,7 +759,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
 		 * get_bbt_block() returns a block number, shift the value to
 		 * get a page number.
 		 */
-		page = block << (this->bbt_erase_shift - this->page_shift);
+		nand_eraseblock_to_page(this, block);
 
 		/* Set up shift count and masks for the flash table */
 		bits = td->options & NAND_BBT_NRBITS_MSK;
@@ -781,13 +780,14 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
 		default: return -EINVAL;
 		}
 
-		to = ((loff_t)page) << this->page_shift;
+		to = nand_page_to_offs(this, page);
 
 		/* Must we save the block contents? */
 		if (td->options & NAND_BBT_SAVECONTENT) {
 			/* Make it block aligned */
-			to &= ~(((loff_t)1 << this->bbt_erase_shift) - 1);
-			len = 1 << this->bbt_erase_shift;
+			to = nand_eraseblock_to_offs(this,
+					nand_page_to_eraseblock(this, page));
+			len = nand_eraseblock_size(this);
 			res = mtd_read(mtd, to, len, &retlen, buf);
 			if (res < 0) {
 				if (retlen != len) {
@@ -797,18 +797,19 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
 				pr_warn("nand_bbt: ECC error while reading block for writing bad block table\n");
 			}
 			/* Read oob data */
-			ops.ooblen = (len >> this->page_shift) * mtd->oobsize;
+			ops.ooblen = nand_len_to_pages(this, len) *
+				     nand_per_page_oobsize(this);
 			ops.oobbuf = &buf[len];
-			res = mtd_read_oob(mtd, to + mtd->writesize, &ops);
+			res = mtd_read_oob(mtd, to + nand_page_size(this), &ops);
 			if (res < 0 || ops.oobretlen != ops.ooblen)
 				goto outerr;
 
 			/* Calc the byte offset in the buffer */
-			pageoffs = page - (int)(to >> this->page_shift);
-			offs = pageoffs << this->page_shift;
+			pageoffs = page - nand_offs_to_page(this, to);
+			offs = nand_page_to_offs(this, pageoffs);
 			/* Preset the bbt area with 0xff */
 			memset(&buf[offs], 0xff, (size_t)(numblocks >> sft));
-			ooboffs = len + (pageoffs * mtd->oobsize);
+			ooboffs = len + (pageoffs * nand_per_page_oobsize(this));
 
 		} else if (td->options & NAND_BBT_NO_OOB) {
 			ooboffs = 0;
@@ -820,7 +821,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
 			len = (size_t)(numblocks >> sft);
 			len += offs;
 			/* Make it page aligned! */
-			len = ALIGN(len, mtd->writesize);
+			len = ALIGN(len, nand_page_size(this));
 			/* Preset the buffer with 0xff */
 			memset(buf, 0xff, len);
 			/* Pattern is located at the begin of first page */
@@ -829,10 +830,11 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
 			/* Calc length */
 			len = (size_t)(numblocks >> sft);
 			/* Make it page aligned! */
-			len = ALIGN(len, mtd->writesize);
+			len = ALIGN(len, nand_page_size(this));
 			/* Preset the buffer with 0xff */
 			memset(buf, 0xff, len +
-			       (len >> this->page_shift)* mtd->oobsize);
+					  (nand_len_to_pages(this, len) *
+					   nand_per_page_oobsize(this)));
 			offs = 0;
 			ooboffs = len;
 			/* Pattern is located in oob area of first page */
@@ -854,8 +856,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
 		memset(&einfo, 0, sizeof(einfo));
 		einfo.mtd = mtd;
 		einfo.addr = to;
-		einfo.len = 1 << this->bbt_erase_shift;
-		res = nand_erase_nand(mtd, &einfo, 1);
+		einfo.len = nand_eraseblock_size(this);
+		res = nand_erase(this, &einfo, 1);
 		if (res < 0) {
 			pr_warn("nand_bbt: error while erasing BBT block %d\n",
 				res);
@@ -863,9 +865,9 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
 			continue;
 		}
 
-		res = scan_write_bbt(mtd, to, len, buf,
-				td->options & NAND_BBT_NO_OOB ? NULL :
-				&buf[len]);
+		res = scan_write_bbt(this, to, len, buf,
+				     td->options & NAND_BBT_NO_OOB ? NULL :
+				     &buf[len]);
 		if (res < 0) {
 			pr_warn("nand_bbt: error while writing BBT block %d\n",
 				res);
@@ -888,22 +890,31 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
 
 /**
  * nand_memory_bbt - [GENERIC] create a memory based bad block table
- * @mtd: MTD device structure
+ * @this: NAND device
  * @bd: descriptor for the good/bad block search pattern
  *
  * The function creates a memory based bbt by scanning the device for
  * manufacturer / software marked good / bad blocks.
  */
-static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
+static inline int nand_memory_bbt(struct nand_device *this,
+				  struct nand_bbt_descr *bd)
 {
-	struct nand_chip *this = mtd_to_nandc(mtd);
+	void *buffer;
+	int ret;
 
-	return create_bbt(mtd, this->buffers->databuf, bd, -1);
+	buffer = kmalloc(nand_page_size(this), GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	ret = create_bbt(this, buffer, bd, -1);
+	kfree(buffer);
+
+	return ret;
 }
 
 /**
  * check_create - [GENERIC] create and write bbt(s) if necessary
- * @mtd: MTD device structure
+ * @this: NAND device
  * @buf: temporary buffer
  * @bd: descriptor for the good/bad block search pattern
  *
@@ -912,17 +923,17 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b
  * for the chip/device. Update is necessary if one of the tables is missing or
  * the version nr. of one table is less than the other.
  */
-static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd)
+static int check_create(struct nand_device *this, uint8_t *buf,
+			struct nand_bbt_descr *bd)
 {
 	int i, chips, writeops, create, chipsel, res, res2;
-	struct nand_chip *this = mtd_to_nandc(mtd);
-	struct nand_bbt_descr *td = this->bbt_td;
-	struct nand_bbt_descr *md = this->bbt_md;
+	struct nand_bbt_descr *td = this->bbt.td;
+	struct nand_bbt_descr *md = this->bbt.md;
 	struct nand_bbt_descr *rd, *rd2;
 
 	/* Do we have a bbt per chip? */
 	if (td->options & NAND_BBT_PERCHIP)
-		chips = this->numchips;
+		chips = nand_ndies(this);
 	else
 		chips = 1;
 
@@ -971,8 +982,8 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 				continue;
 
 			/* Create the table in memory by scanning the chip(s) */
-			if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY))
-				create_bbt(mtd, buf, bd, chipsel);
+			if (!(this->bbt.options & NAND_BBT_CREATE_EMPTY))
+				create_bbt(this, buf, bd, chipsel);
 
 			td->version[i] = 1;
 			if (md)
@@ -981,7 +992,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 
 		/* Read back first? */
 		if (rd) {
-			res = read_abs_bbt(mtd, buf, rd, chipsel);
+			res = read_abs_bbt(this, buf, rd, chipsel);
 			if (mtd_is_eccerr(res)) {
 				/* Mark table as invalid */
 				rd->pages[i] = -1;
@@ -992,7 +1003,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 		}
 		/* If they weren't versioned, read both */
 		if (rd2) {
-			res2 = read_abs_bbt(mtd, buf, rd2, chipsel);
+			res2 = read_abs_bbt(this, buf, rd2, chipsel);
 			if (mtd_is_eccerr(res2)) {
 				/* Mark table as invalid */
 				rd2->pages[i] = -1;
@@ -1014,14 +1025,14 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 
 		/* Write the bad block table to the device? */
 		if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
-			res = write_bbt(mtd, buf, td, md, chipsel);
+			res = write_bbt(this, buf, td, md, chipsel);
 			if (res < 0)
 				return res;
 		}
 
 		/* Write the mirror bad block table to the device? */
 		if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
-			res = write_bbt(mtd, buf, md, td, chipsel);
+			res = write_bbt(this, buf, md, td, chipsel);
 			if (res < 0)
 				return res;
 		}
@@ -1031,25 +1042,26 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 
 /**
  * mark_bbt_regions - [GENERIC] mark the bad block table regions
- * @mtd: MTD device structure
+ * @this: NAND device
  * @td: bad block table descriptor
  *
  * The bad block table regions are marked as "bad" to prevent accidental
  * erasures / writes. The regions are identified by the mark 0x02.
  */
-static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
+static void mark_bbt_region(struct nand_device *this,
+			    struct nand_bbt_descr *td)
 {
-	struct nand_chip *this = mtd_to_nandc(mtd);
 	int i, j, chips, block, nrblocks, update;
 	uint8_t oldval;
+	loff_t offs;
 
 	/* Do we have a bbt per chip? */
 	if (td->options & NAND_BBT_PERCHIP) {
-		chips = this->numchips;
-		nrblocks = (int)(this->chipsize >> this->bbt_erase_shift);
+		chips = nand_ndies(this);
+		nrblocks = nand_eraseblocks_per_die(this);
 	} else {
 		chips = 1;
-		nrblocks = (int)(mtd->size >> this->bbt_erase_shift);
+		nrblocks = nand_neraseblocks(this);
 	}
 
 	for (i = 0; i < chips; i++) {
@@ -1057,13 +1069,14 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
 		    !(td->options & NAND_BBT_WRITE)) {
 			if (td->pages[i] == -1)
 				continue;
-			block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift);
+			block = nand_page_to_eraseblock(this, td->pages[i]);
 			oldval = bbt_get_entry(this, block);
 			bbt_mark_entry(this, block, BBT_BLOCK_RESERVED);
 			if ((oldval != BBT_BLOCK_RESERVED) &&
-					td->reserved_block_code)
-				nand_update_bbt(mtd, (loff_t)block <<
-						this->bbt_erase_shift);
+			    td->reserved_block_code) {
+				offs = nand_eraseblock_to_offs(this, block);
+				nand_update_bbt(this, offs);
+			}
 			continue;
 		}
 		update = 0;
@@ -1083,23 +1096,23 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
 		 * new ones have been marked, then we need to update the stored
 		 * bbts.  This should only happen once.
 		 */
-		if (update && td->reserved_block_code)
-			nand_update_bbt(mtd, (loff_t)(block - 1) <<
-					this->bbt_erase_shift);
+		if (update && td->reserved_block_code) {
+			offs = nand_eraseblock_to_offs(this, block - 1);
+			nand_update_bbt(this, offs);
+		}
 	}
 }
 
 /**
  * verify_bbt_descr - verify the bad block description
- * @mtd: MTD device structure
+ * @this: NAND device
  * @bd: the table to verify
  *
  * This functions performs a few sanity checks on the bad block description
  * table.
  */
-static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)
+static void verify_bbt_descr(struct nand_device *this, struct nand_bbt_descr *bd)
 {
-	struct nand_chip *this = mtd_to_nandc(mtd);
 	u32 pattern_len;
 	u32 bits;
 	u32 table_size;
@@ -1110,16 +1123,16 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)
 	pattern_len = bd->len;
 	bits = bd->options & NAND_BBT_NRBITS_MSK;
 
-	BUG_ON((this->bbt_options & NAND_BBT_NO_OOB) &&
-			!(this->bbt_options & NAND_BBT_USE_FLASH));
+	BUG_ON((this->bbt.options & NAND_BBT_NO_OOB) &&
+		!(this->bbt.options & NAND_BBT_USE_FLASH));
 	BUG_ON(!bits);
 
 	if (bd->options & NAND_BBT_VERSION)
 		pattern_len++;
 
 	if (bd->options & NAND_BBT_NO_OOB) {
-		BUG_ON(!(this->bbt_options & NAND_BBT_USE_FLASH));
-		BUG_ON(!(this->bbt_options & NAND_BBT_NO_OOB));
+		BUG_ON(!(this->bbt.options & NAND_BBT_USE_FLASH));
+		BUG_ON(!(this->bbt.options & NAND_BBT_NO_OOB));
 		BUG_ON(bd->offs);
 		if (bd->options & NAND_BBT_VERSION)
 			BUG_ON(bd->veroffs != bd->len);
@@ -1127,19 +1140,63 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)
 	}
 
 	if (bd->options & NAND_BBT_PERCHIP)
-		table_size = this->chipsize >> this->bbt_erase_shift;
+		table_size = nand_eraseblocks_per_die(this);
 	else
-		table_size = mtd->size >> this->bbt_erase_shift;
+		table_size = nand_neraseblocks(this);
 	table_size >>= 3;
 	table_size *= bits;
 	if (bd->options & NAND_BBT_NO_OOB)
 		table_size += pattern_len;
-	BUG_ON(table_size > (1 << this->bbt_erase_shift));
+	BUG_ON(table_size > nand_eraseblock_size(this));
 }
 
+/* Generic flash bbt descriptors */
+static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
+static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
+
+static struct nand_bbt_descr bbt_main_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+	.offs =	8,
+	.len = 4,
+	.veroffs = 12,
+	.maxblocks = NAND_BBT_SCAN_MAXBLOCKS,
+	.pattern = bbt_pattern
+};
+
+static struct nand_bbt_descr bbt_mirror_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+	.offs =	8,
+	.len = 4,
+	.veroffs = 12,
+	.maxblocks = NAND_BBT_SCAN_MAXBLOCKS,
+	.pattern = mirror_pattern
+};
+
+static struct nand_bbt_descr bbt_main_no_oob_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP
+		| NAND_BBT_NO_OOB,
+	.len = 4,
+	.veroffs = 4,
+	.maxblocks = NAND_BBT_SCAN_MAXBLOCKS,
+	.pattern = bbt_pattern
+};
+
+static struct nand_bbt_descr bbt_mirror_no_oob_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP
+		| NAND_BBT_NO_OOB,
+	.len = 4,
+	.veroffs = 4,
+	.maxblocks = NAND_BBT_SCAN_MAXBLOCKS,
+	.pattern = mirror_pattern
+};
+
 /**
  * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s)
- * @mtd: MTD device structure
+ * @this: NAND device
  * @bd: descriptor for the good/bad block search pattern
  *
  * The function checks, if a bad block table(s) is/are already available. If
@@ -1149,21 +1206,40 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)
  * The bad block table memory is allocated here. It must be freed by calling
  * the nand_free_bbt function.
  */
-static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
+int nand_scan_bbt(struct nand_device *this)
 {
-	struct nand_chip *this = mtd_to_nandc(mtd);
 	int len, res;
 	uint8_t *buf;
-	struct nand_bbt_descr *td = this->bbt_td;
-	struct nand_bbt_descr *md = this->bbt_md;
+	struct nand_bbt_descr *td, *md, *bd;
+
+	/* Is a flash based bad block table requested? */
+	if (this->bbt.options & NAND_BBT_USE_FLASH) {
+		/* Use the default pattern descriptors */
+		if (!this->bbt.td) {
+			if (this->bbt.options & NAND_BBT_NO_OOB) {
+				this->bbt.td = &bbt_main_no_oob_descr;
+				this->bbt.md = &bbt_mirror_no_oob_descr;
+			} else {
+				this->bbt.td = &bbt_main_descr;
+				this->bbt.md = &bbt_mirror_descr;
+			}
+		}
+	} else {
+		this->bbt.td = NULL;
+		this->bbt.md = NULL;
+	}
+
+	td = this->bbt.td;
+	md = this->bbt.md;
+	bd = this->bbt.bbp;
 
-	len = (mtd->size >> (this->bbt_erase_shift + 2)) ? : 1;
 	/*
 	 * Allocate memory (2bit per block) and clear the memory bad block
 	 * table.
 	 */
-	this->bbt = kzalloc(len, GFP_KERNEL);
-	if (!this->bbt)
+	len = DIV_ROUND_UP(nand_neraseblocks(this) * 2, 8);
+	this->bbt.bbt = kzalloc(len, GFP_KERNEL);
+	if (!this->bbt.bbt)
 		return -ENOMEM;
 
 	/*
@@ -1171,18 +1247,17 @@ static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
 	 * memory based bad block table.
 	 */
 	if (!td) {
-		if ((res = nand_memory_bbt(mtd, bd))) {
+		if ((res = nand_memory_bbt(this, bd))) {
 			pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n");
 			goto err;
 		}
 		return 0;
 	}
-	verify_bbt_descr(mtd, td);
-	verify_bbt_descr(mtd, md);
+	verify_bbt_descr(this, td);
+	verify_bbt_descr(this, md);
 
 	/* Allocate a temporary buffer for one eraseblock incl. oob */
-	len = (1 << this->bbt_erase_shift);
-	len += (len >> this->page_shift) * mtd->oobsize;
+	len = nand_eraseblock_size(this) + nand_per_eraseblock_oobsize(this);
 	buf = vmalloc(len);
 	if (!buf) {
 		res = -ENOMEM;
@@ -1191,63 +1266,61 @@ static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
 
 	/* Is the bbt at a given page? */
 	if (td->options & NAND_BBT_ABSPAGE) {
-		read_abs_bbts(mtd, buf, td, md);
+		read_abs_bbts(this, buf, td, md);
 	} else {
 		/* Search the bad block table using a pattern in oob */
-		search_read_bbts(mtd, buf, td, md);
+		search_read_bbts(this, buf, td, md);
 	}
 
-	res = check_create(mtd, buf, bd);
+	res = check_create(this, buf, bd);
 	if (res)
 		goto err;
 
 	/* Prevent the bbt regions from erasing / writing */
-	mark_bbt_region(mtd, td);
+	mark_bbt_region(this, td);
 	if (md)
-		mark_bbt_region(mtd, md);
+		mark_bbt_region(this, md);
 
 	vfree(buf);
 	return 0;
 
 err:
-	kfree(this->bbt);
-	this->bbt = NULL;
+	kfree(this->bbt.bbt);
+	this->bbt.bbt = NULL;
 	return res;
 }
 
 /**
  * nand_update_bbt - update bad block table(s)
- * @mtd: MTD device structure
+ * @this: NAND device
  * @offs: the offset of the newly marked block
  *
  * The function updates the bad block table(s).
  */
-static int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
+int nand_update_bbt(struct nand_device *this, loff_t offs)
 {
-	struct nand_chip *this = mtd_to_nandc(mtd);
 	int len, res = 0;
 	int chip, chipsel;
 	uint8_t *buf;
-	struct nand_bbt_descr *td = this->bbt_td;
-	struct nand_bbt_descr *md = this->bbt_md;
+	struct nand_bbt_descr *td = this->bbt.td;
+	struct nand_bbt_descr *md = this->bbt.md;
 
-	if (!this->bbt || !td)
+	if (!this->bbt.bbt || !td)
 		return -EINVAL;
 
 	/* Allocate a temporary buffer for one eraseblock incl. oob */
-	len = (1 << this->bbt_erase_shift);
-	len += (len >> this->page_shift) * mtd->oobsize;
+	len = nand_eraseblock_size(this) + nand_per_eraseblock_oobsize(this);
 	buf = kmalloc(len, GFP_KERNEL);
 	if (!buf)
 		return -ENOMEM;
 
 	/* Do we have a bbt per chip? */
 	if (td->options & NAND_BBT_PERCHIP) {
-		chip = (int)(offs >> this->chip_shift);
+		chip = nand_offs_to_die(this, offs);
 		chipsel = chip;
 	} else {
 		chip = 0;
-		chipsel = -1;
+		chipsel = -1 ;
 	}
 
 	td->version[chip]++;
@@ -1256,13 +1329,13 @@ static int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
 
 	/* Write the bad block table to the device? */
 	if (td->options & NAND_BBT_WRITE) {
-		res = write_bbt(mtd, buf, td, md, chipsel);
+		res = write_bbt(this, buf, td, md, chipsel);
 		if (res < 0)
 			goto out;
 	}
 	/* Write the mirror bad block table to the device? */
 	if (md && (md->options & NAND_BBT_WRITE)) {
-		res = write_bbt(mtd, buf, md, td, chipsel);
+		res = write_bbt(this, buf, md, td, chipsel);
 	}
 
  out:
@@ -1270,149 +1343,30 @@ static int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
 	return res;
 }
 
-/*
- * Define some generic bad / good block scan pattern which are used
- * while scanning a device for factory marked good / bad blocks.
- */
-static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
-
-/* Generic flash bbt descriptors */
-static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
-static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
-
-static struct nand_bbt_descr bbt_main_descr = {
-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
-	.offs =	8,
-	.len = 4,
-	.veroffs = 12,
-	.maxblocks = NAND_BBT_SCAN_MAXBLOCKS,
-	.pattern = bbt_pattern
-};
-
-static struct nand_bbt_descr bbt_mirror_descr = {
-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
-	.offs =	8,
-	.len = 4,
-	.veroffs = 12,
-	.maxblocks = NAND_BBT_SCAN_MAXBLOCKS,
-	.pattern = mirror_pattern
-};
-
-static struct nand_bbt_descr bbt_main_no_oob_descr = {
-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP
-		| NAND_BBT_NO_OOB,
-	.len = 4,
-	.veroffs = 4,
-	.maxblocks = NAND_BBT_SCAN_MAXBLOCKS,
-	.pattern = bbt_pattern
-};
-
-static struct nand_bbt_descr bbt_mirror_no_oob_descr = {
-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP
-		| NAND_BBT_NO_OOB,
-	.len = 4,
-	.veroffs = 4,
-	.maxblocks = NAND_BBT_SCAN_MAXBLOCKS,
-	.pattern = mirror_pattern
-};
-
-#define BADBLOCK_SCAN_MASK (~NAND_BBT_NO_OOB)
-/**
- * nand_create_badblock_pattern - [INTERN] Creates a BBT descriptor structure
- * @this: NAND chip to create descriptor for
- *
- * This function allocates and initializes a nand_bbt_descr for BBM detection
- * based on the properties of @this. The new descriptor is stored in
- * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when
- * passed to this function.
- */
-static int nand_create_badblock_pattern(struct nand_chip *this)
-{
-	struct nand_bbt_descr *bd;
-	if (this->badblock_pattern) {
-		pr_warn("Bad block pattern already allocated; not replacing\n");
-		return -EINVAL;
-	}
-	bd = kzalloc(sizeof(*bd), GFP_KERNEL);
-	if (!bd)
-		return -ENOMEM;
-	bd->options = this->bbt_options & BADBLOCK_SCAN_MASK;
-	bd->offs = this->badblockpos;
-	bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1;
-	bd->pattern = scan_ff_pattern;
-	bd->options |= NAND_BBT_DYNAMICSTRUCT;
-	this->badblock_pattern = bd;
-	return 0;
-}
-
-/**
- * nand_default_bbt - [NAND Interface] Select a default bad block table for the device
- * @mtd: MTD device structure
- *
- * This function selects the default bad block table support for the device and
- * calls the nand_scan_bbt function.
- */
-int nand_default_bbt(struct mtd_info *mtd)
-{
-	struct nand_chip *this = mtd_to_nandc(mtd);
-	int ret;
-
-	/* Is a flash based bad block table requested? */
-	if (this->bbt_options & NAND_BBT_USE_FLASH) {
-		/* Use the default pattern descriptors */
-		if (!this->bbt_td) {
-			if (this->bbt_options & NAND_BBT_NO_OOB) {
-				this->bbt_td = &bbt_main_no_oob_descr;
-				this->bbt_md = &bbt_mirror_no_oob_descr;
-			} else {
-				this->bbt_td = &bbt_main_descr;
-				this->bbt_md = &bbt_mirror_descr;
-			}
-		}
-	} else {
-		this->bbt_td = NULL;
-		this->bbt_md = NULL;
-	}
-
-	if (!this->badblock_pattern) {
-		ret = nand_create_badblock_pattern(this);
-		if (ret)
-			return ret;
-	}
-
-	return nand_scan_bbt(mtd, this->badblock_pattern);
-}
-
 /**
  * nand_isreserved_bbt - [NAND Interface] Check if a block is reserved
- * @mtd: MTD device structure
+ * @this: NAND device
  * @offs: offset in the device
  */
-int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs)
+int nand_isreserved_bbt(struct nand_device *this, loff_t offs)
 {
-	struct nand_chip *this = mtd_to_nandc(mtd);
 	int block;
 
-	block = (int)(offs >> this->bbt_erase_shift);
+	block = nand_offs_to_eraseblock(this, offs);
 	return bbt_get_entry(this, block) == BBT_BLOCK_RESERVED;
 }
 
 /**
  * nand_isbad_bbt - [NAND Interface] Check if a block is bad
- * @mtd: MTD device structure
+ * @this: NAND device
  * @offs: offset in the device
  * @allowbbt: allow access to bad block table region
  */
-int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
+int nand_isbad_bbt(struct nand_device *this, loff_t offs, int allowbbt)
 {
-	struct nand_chip *this = mtd_to_nandc(mtd);
 	int block, res;
 
-	block = (int)(offs >> this->bbt_erase_shift);
+	block = nand_offs_to_eraseblock(this, offs);
 	res = bbt_get_entry(this, block);
 
 	pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",
@@ -1431,22 +1385,21 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
 
 /**
  * nand_markbad_bbt - [NAND Interface] Mark a block bad in the BBT
- * @mtd: MTD device structure
+ * @this: NAND device
  * @offs: offset of the bad block
  */
-int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs)
+int nand_markbad_bbt(struct nand_device *this, loff_t offs)
 {
-	struct nand_chip *this = mtd_to_nandc(mtd);
 	int block, ret = 0;
 
-	block = (int)(offs >> this->bbt_erase_shift);
+	block = nand_offs_to_eraseblock(this, offs);
 
 	/* Mark bad block in memory */
 	bbt_mark_entry(this, block, BBT_BLOCK_WORN);
 
 	/* Update flash-based bad block table */
-	if (this->bbt_options & NAND_BBT_USE_FLASH)
-		ret = nand_update_bbt(mtd, offs);
+	if (this->bbt.options & NAND_BBT_USE_FLASH)
+		ret = nand_update_bbt(this, offs);
 
 	return ret;
 }
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index b9b5d3c1bdf9..b59636662c1e 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -477,4 +477,12 @@ static inline struct device_node *nand_get_of_node(struct nand_device *nand)
 {
 	return mtd_get_of_node(&nand->mtd);
 }
+
+/* BBT related functions */
+int nand_scan_bbt(struct nand_device *this);
+int nand_update_bbt(struct nand_device *this, loff_t offs);
+int nand_isreserved_bbt(struct nand_device *this, loff_t offs);
+int nand_isbad_bbt(struct nand_device *this, loff_t offs, int allowbbt);
+int nand_markbad_bbt(struct nand_device *this, loff_t offs);
+
 #endif /* __LINUX_MTD_NAND_H */
diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
index 8efff12604ad..8a2ff41af588 100644
--- a/include/linux/mtd/rawnand.h
+++ b/include/linux/mtd/rawnand.h
@@ -1036,10 +1036,6 @@ struct nand_manufacturers {
 extern struct nand_flash_dev nand_flash_ids[];
 extern struct nand_manufacturers nand_manuf_ids[];
 
-int nand_default_bbt(struct mtd_info *mtd);
-int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs);
-int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs);
-int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt);
 int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
 		    int allowbbt);
 int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
-- 
2.7.4



From boris.brezillon at free-electrons.com  Sun Oct 16 07:35:15 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Sun, 16 Oct 2016 16:35:15 +0200
Subject: [PATCH v2 4/7] mtd: nand: raw: prefix conflicting names with nandc
 instead of nand
In-Reply-To: <1476628518-20450-1-git-send-email-boris.brezillon@free-electrons.com>
References: <1476628518-20450-1-git-send-email-boris.brezillon@free-electrons.com>
Message-ID: <1476628518-20450-5-git-send-email-boris.brezillon@free-electrons.com>

Some raw NAND function names conflict with names defined in nand.h.
Prefix all those functions with nandc (for nand chip) instead of nand so
we can include nand.h from rawnand.h

Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 Documentation/DocBook/mtdnand.tmpl               |  10 +-
 arch/arm/mach-ep93xx/snappercl15.c               |   4 +-
 arch/arm/mach-ep93xx/ts72xx.c                    |   4 +-
 arch/arm/mach-imx/mach-qong.c                    |   2 +-
 arch/arm/mach-ixp4xx/ixdp425-setup.c             |   2 +-
 arch/arm/mach-omap1/board-nand.c                 |   2 +-
 arch/arm/mach-orion5x/ts78xx-setup.c             |   6 +-
 arch/arm/mach-pxa/balloon3.c                     |   2 +-
 arch/arm/mach-pxa/em-x270.c                      |   2 +-
 arch/arm/mach-pxa/palmtx.c                       |   2 +-
 arch/blackfin/mach-bf537/boards/stamp.c          |   2 +-
 arch/blackfin/mach-bf561/boards/acvilon.c        |   2 +-
 arch/cris/arch-v32/drivers/mach-a3/nandflash.c   |   4 +-
 arch/cris/arch-v32/drivers/mach-fs/nandflash.c   |   4 +-
 arch/mips/alchemy/devboards/db1200.c             |   2 +-
 arch/mips/alchemy/devboards/db1300.c             |   2 +-
 arch/mips/alchemy/devboards/db1550.c             |   2 +-
 arch/mips/jz4740/board-qi_lb60.c                 |   2 +-
 arch/mips/pnx833x/common/platform.c              |   2 +-
 arch/mips/rb532/devices.c                        |   2 +-
 arch/sh/boards/mach-migor/setup.c                |   2 +-
 drivers/mtd/nand/raw/ams-delta.c                 |   8 +-
 drivers/mtd/nand/raw/atmel_nand.c                |  60 ++++++------
 drivers/mtd/nand/raw/au1550nd.c                  |  26 ++---
 drivers/mtd/nand/raw/bcm47xxnflash/main.c        |   4 +-
 drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c |  18 ++--
 drivers/mtd/nand/raw/bf5xx_nand.c                |  32 +++---
 drivers/mtd/nand/raw/brcmnand/brcmnand.c         |  32 +++---
 drivers/mtd/nand/raw/cafe_nand.c                 |  24 ++---
 drivers/mtd/nand/raw/cmx270_nand.c               |  12 +--
 drivers/mtd/nand/raw/cs553x_nand.c               |  20 ++--
 drivers/mtd/nand/raw/davinci_nand.c              |  14 +--
 drivers/mtd/nand/raw/denali.c                    |  12 +--
 drivers/mtd/nand/raw/diskonchip.c                |  68 ++++++-------
 drivers/mtd/nand/raw/docg4.c                     |  36 +++----
 drivers/mtd/nand/raw/fsl_elbc_nand.c             |  26 ++---
 drivers/mtd/nand/raw/fsl_ifc_nand.c              |  28 +++---
 drivers/mtd/nand/raw/fsl_upm.c                   |  12 +--
 drivers/mtd/nand/raw/fsmc_nand.c                 |  24 ++---
 drivers/mtd/nand/raw/gpio.c                      |   6 +-
 drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c        |   2 +-
 drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c       |  38 +++----
 drivers/mtd/nand/raw/hisi504_nand.c              |  24 ++---
 drivers/mtd/nand/raw/jz4740_nand.c               |  12 +--
 drivers/mtd/nand/raw/jz4780_nand.c               |   8 +-
 drivers/mtd/nand/raw/lpc32xx_mlc.c               |  16 +--
 drivers/mtd/nand/raw/lpc32xx_slc.c               |  20 ++--
 drivers/mtd/nand/raw/mpc5121_nfc.c               |  26 ++---
 drivers/mtd/nand/raw/mtk_nand.c                  |  38 +++----
 drivers/mtd/nand/raw/mxc_nand.c                  |  52 +++++-----
 drivers/mtd/nand/raw/nand_base.c                 | 120 +++++++++++------------
 drivers/mtd/nand/raw/nand_bbt.c                  |  34 +++----
 drivers/mtd/nand/raw/nand_bch.c                  |   6 +-
 drivers/mtd/nand/raw/nand_ecc.c                  |   4 +-
 drivers/mtd/nand/raw/nandsim.c                   |  22 ++---
 drivers/mtd/nand/raw/ndfc.c                      |  18 ++--
 drivers/mtd/nand/raw/nuc900_nand.c               |   8 +-
 drivers/mtd/nand/raw/omap2.c                     |  20 ++--
 drivers/mtd/nand/raw/orion_nand.c                |   6 +-
 drivers/mtd/nand/raw/pasemi_nand.c               |  10 +-
 drivers/mtd/nand/raw/plat_nand.c                 |   4 +-
 drivers/mtd/nand/raw/pxa3xx_nand.c               |  36 +++----
 drivers/mtd/nand/raw/qcom_nandc.c                |  28 +++---
 drivers/mtd/nand/raw/r852.c                      |   8 +-
 drivers/mtd/nand/raw/s3c2410.c                   |  16 +--
 drivers/mtd/nand/raw/sh_flctl.c                  |  10 +-
 drivers/mtd/nand/raw/sharpsl.c                   |   8 +-
 drivers/mtd/nand/raw/sm_common.c                 |   2 +-
 drivers/mtd/nand/raw/socrates_nand.c             |  12 +--
 drivers/mtd/nand/raw/sunxi_nand.c                |  58 +++++------
 drivers/mtd/nand/raw/tmio_nand.c                 |   8 +-
 drivers/mtd/nand/raw/txx9ndfmc.c                 |  14 +--
 drivers/mtd/nand/raw/vf610_nfc.c                 |   4 +-
 drivers/mtd/nand/raw/xway_nand.c                 |  10 +-
 drivers/staging/mt29f_spinand/mt29f_spinand.c    |   6 +-
 include/linux/mtd/rawnand.h                      |   4 +-
 include/linux/mtd/sh_flctl.h                     |   2 +-
 77 files changed, 619 insertions(+), 619 deletions(-)

diff --git a/Documentation/DocBook/mtdnand.tmpl b/Documentation/DocBook/mtdnand.tmpl
index 35ec7155faa3..ae8ef3c53641 100644
--- a/Documentation/DocBook/mtdnand.tmpl
+++ b/Documentation/DocBook/mtdnand.tmpl
@@ -169,7 +169,7 @@
 			The NAND chip structure embeds an mtd structure
 			which will be registered to the MTD subsystem.
 			You can extract a pointer to the mtd structure
-			from a nand_chip pointer using the nand_to_mtd()
+			from a nand_chip pointer using the nandc_to_mtd()
 			helper.
 		</para>
 		<para>
@@ -237,7 +237,7 @@ static void board_hwcontrol(struct mtd_info *mtd, int cmd)
 		<programlisting>
 static void board_hwcontrol(struct mtd_info *mtd, int cmd)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	switch(cmd){
 		case NAND_CTL_SETCLE: this->IO_ADDR_W |= CLE_ADRR_BIT;  break;
 		case NAND_CTL_CLRCLE: this->IO_ADDR_W &amp;= ~CLE_ADRR_BIT; break;
@@ -283,7 +283,7 @@ static int __init board_init (void)
 		goto out;
 	}
 
-	board_mtd = nand_to_mtd(this);
+	board_mtd = nandc_to_mtd(this);
 
 	/* map physical address */
 	baseaddr = ioremap(CHIP_PHYSICAL_ADDRESS, 1024);
@@ -342,7 +342,7 @@ static void __exit board_cleanup (void)
 	iounmap(baseaddr);
 	
 	/* Free the MTD device structure */
-	kfree (mtd_to_nand(board_mtd));
+	kfree (mtd_to_nandc(board_mtd));
 }
 module_exit(board_cleanup);
 #endif
@@ -398,7 +398,7 @@ static void board_select_chip (struct mtd_info *mtd, int chip)
 		<programlisting>
 static void board_select_chip (struct mtd_info *mtd, int chip)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	
 	/* Deselect all chips */
 	this->IO_ADDR_R &amp;= ~BOARD_NAND_ADDR_MASK;
diff --git a/arch/arm/mach-ep93xx/snappercl15.c b/arch/arm/mach-ep93xx/snappercl15.c
index 8b29398f4dc7..7996609ae516 100644
--- a/arch/arm/mach-ep93xx/snappercl15.c
+++ b/arch/arm/mach-ep93xx/snappercl15.c
@@ -49,7 +49,7 @@
 static void snappercl15_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
 				      unsigned int ctrl)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	static u16 nand_state = SNAPPERCL15_NAND_WPN;
 	u16 set;
 
@@ -76,7 +76,7 @@ static void snappercl15_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
 
 static int snappercl15_nand_dev_ready(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	return !!(__raw_readw(NAND_CTRL_ADDR(chip)) & SNAPPERCL15_NAND_RDY);
 }
diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c
index 9def3b98945e..7627e874e568 100644
--- a/arch/arm/mach-ep93xx/ts72xx.c
+++ b/arch/arm/mach-ep93xx/ts72xx.c
@@ -74,7 +74,7 @@ static void __init ts72xx_map_io(void)
 static void ts72xx_nand_hwcontrol(struct mtd_info *mtd,
 				  int cmd, unsigned int ctrl)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	if (ctrl & NAND_CTRL_CHANGE) {
 		void __iomem *addr = chip->IO_ADDR_R;
@@ -96,7 +96,7 @@ static void ts72xx_nand_hwcontrol(struct mtd_info *mtd,
 
 static int ts72xx_nand_device_ready(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	void __iomem *addr = chip->IO_ADDR_R;
 
 	addr += (1 << TS72XX_NAND_BUSY_ADDR_LINE);
diff --git a/arch/arm/mach-imx/mach-qong.c b/arch/arm/mach-imx/mach-qong.c
index 42a700053103..3aa1ab95d535 100644
--- a/arch/arm/mach-imx/mach-qong.c
+++ b/arch/arm/mach-imx/mach-qong.c
@@ -131,7 +131,7 @@ static void qong_init_nor_mtd(void)
  */
 static void qong_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 
 	if (cmd == NAND_CMD_NONE)
 		return;
diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c
index 93b89291c06b..e951d78b133a 100644
--- a/arch/arm/mach-ixp4xx/ixdp425-setup.c
+++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c
@@ -76,7 +76,7 @@ static struct mtd_partition ixdp425_partitions[] = {
 static void
 ixdp425_flash_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	int offset = (int)nand_get_controller_data(this);
 
 	if (ctrl & NAND_CTRL_CHANGE) {
diff --git a/arch/arm/mach-omap1/board-nand.c b/arch/arm/mach-omap1/board-nand.c
index 1bffbb4e050f..662f2e402a23 100644
--- a/arch/arm/mach-omap1/board-nand.c
+++ b/arch/arm/mach-omap1/board-nand.c
@@ -22,7 +22,7 @@
 
 void omap1_nand_cmd_ctl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	unsigned long mask;
 
 	if (cmd == NAND_CMD_NONE)
diff --git a/arch/arm/mach-orion5x/ts78xx-setup.c b/arch/arm/mach-orion5x/ts78xx-setup.c
index 4632e674e9c5..824f3feccb47 100644
--- a/arch/arm/mach-orion5x/ts78xx-setup.c
+++ b/arch/arm/mach-orion5x/ts78xx-setup.c
@@ -176,7 +176,7 @@ static void ts78xx_ts_rtc_unload(void)
 static void ts78xx_ts_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
 			unsigned int ctrl)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 
 	if (ctrl & NAND_CTRL_CHANGE) {
 		unsigned char bits;
@@ -200,7 +200,7 @@ static int ts78xx_ts_nand_dev_ready(struct mtd_info *mtd)
 static void ts78xx_ts_nand_write_buf(struct mtd_info *mtd,
 			const uint8_t *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	void __iomem *io_base = chip->IO_ADDR_W;
 	unsigned long off = ((unsigned long)buf & 3);
 	int sz;
@@ -227,7 +227,7 @@ static void ts78xx_ts_nand_write_buf(struct mtd_info *mtd,
 static void ts78xx_ts_nand_read_buf(struct mtd_info *mtd,
 			uint8_t *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	void __iomem *io_base = chip->IO_ADDR_R;
 	unsigned long off = ((unsigned long)buf & 3);
 	int sz;
diff --git a/arch/arm/mach-pxa/balloon3.c b/arch/arm/mach-pxa/balloon3.c
index 38afb6fa1dcf..ce4e1f747c8d 100644
--- a/arch/arm/mach-pxa/balloon3.c
+++ b/arch/arm/mach-pxa/balloon3.c
@@ -572,7 +572,7 @@ static inline void balloon3_i2c_init(void) {}
 #if defined(CONFIG_MTD_NAND_PLATFORM)||defined(CONFIG_MTD_NAND_PLATFORM_MODULE)
 static void balloon3_nand_cmd_ctl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	uint8_t balloon3_ctl_set = 0, balloon3_ctl_clr = 0;
 
 	if (ctrl & NAND_CTRL_CHANGE) {
diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c
index a6c5f5b96e47..ac4c9714e2f6 100644
--- a/arch/arm/mach-pxa/em-x270.c
+++ b/arch/arm/mach-pxa/em-x270.c
@@ -289,7 +289,7 @@ static void nand_cs_off(void)
 static void em_x270_nand_cmd_ctl(struct mtd_info *mtd, int dat,
 				 unsigned int ctrl)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	unsigned long nandaddr = (unsigned long)this->IO_ADDR_W;
 
 	dsb();
diff --git a/arch/arm/mach-pxa/palmtx.c b/arch/arm/mach-pxa/palmtx.c
index 47e3e38e9bec..d7782217cf76 100644
--- a/arch/arm/mach-pxa/palmtx.c
+++ b/arch/arm/mach-pxa/palmtx.c
@@ -250,7 +250,7 @@ static inline void palmtx_keys_init(void) {}
 static void palmtx_nand_cmd_ctl(struct mtd_info *mtd, int cmd,
 				 unsigned int ctrl)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	char __iomem *nandaddr = this->IO_ADDR_W;
 
 	if (cmd == NAND_CMD_NONE)
diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c
index ab3034fd1c5b..3aa49a78ca81 100644
--- a/arch/blackfin/mach-bf537/boards/stamp.c
+++ b/arch/blackfin/mach-bf537/boards/stamp.c
@@ -404,7 +404,7 @@ static struct mtd_partition bfin_plat_nand_partitions[] = {
 #define BFIN_NAND_PLAT_ALE 1
 static void bfin_plat_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 
 	if (cmd == NAND_CMD_NONE)
 		return;
diff --git a/arch/blackfin/mach-bf561/boards/acvilon.c b/arch/blackfin/mach-bf561/boards/acvilon.c
index 696cc9d7820a..da00a178676e 100644
--- a/arch/blackfin/mach-bf561/boards/acvilon.c
+++ b/arch/blackfin/mach-bf561/boards/acvilon.c
@@ -267,7 +267,7 @@ static struct mtd_partition bfin_plat_nand_partitions[] = {
 static void bfin_plat_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
 				    unsigned int ctrl)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 
 	if (cmd == NAND_CMD_NONE)
 		return;
diff --git a/arch/cris/arch-v32/drivers/mach-a3/nandflash.c b/arch/cris/arch-v32/drivers/mach-a3/nandflash.c
index 925a98eb6d68..95655cc22090 100644
--- a/arch/cris/arch-v32/drivers/mach-a3/nandflash.c
+++ b/arch/cris/arch-v32/drivers/mach-a3/nandflash.c
@@ -51,7 +51,7 @@ static void crisv32_hwcontrol(struct mtd_info *mtd, int cmd,
 {
 	unsigned long flags;
 	reg_pio_rw_dout dout;
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 
 	local_irq_save(flags);
 
@@ -147,7 +147,7 @@ struct mtd_info *__init crisv32_nand_flash_probe(void)
 
 	/* Get pointer to private data */
 	this = &wrapper->chip;
-	crisv32_mtd = nand_to_mtd(this);
+	crisv32_mtd = nandc_to_mtd(this);
 
 	/* Set address of NAND IO lines */
 	this->IO_ADDR_R = read_cs;
diff --git a/arch/cris/arch-v32/drivers/mach-fs/nandflash.c b/arch/cris/arch-v32/drivers/mach-fs/nandflash.c
index 53b56a429dde..3acc5008a8c2 100644
--- a/arch/cris/arch-v32/drivers/mach-fs/nandflash.c
+++ b/arch/cris/arch-v32/drivers/mach-fs/nandflash.c
@@ -50,7 +50,7 @@ static void crisv32_hwcontrol(struct mtd_info *mtd, int cmd,
 {
 	unsigned long flags;
 	reg_gio_rw_pa_dout dout;
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 
 	local_irq_save(flags);
 
@@ -128,7 +128,7 @@ struct mtd_info *__init crisv32_nand_flash_probe(void)
 
 	/* Get pointer to private data */
 	this = &wrapper->chip;
-	crisv32_mtd = nand_to_mtd(this);
+	crisv32_mtd = nandc_to_mtd(this);
 
 	pa_oe.oe |= 1 << CE_BIT;
 	pa_oe.oe |= 1 << ALE_BIT;
diff --git a/arch/mips/alchemy/devboards/db1200.c b/arch/mips/alchemy/devboards/db1200.c
index 83831002c832..c0135c94123f 100644
--- a/arch/mips/alchemy/devboards/db1200.c
+++ b/arch/mips/alchemy/devboards/db1200.c
@@ -200,7 +200,7 @@ static struct i2c_board_info db1200_i2c_devs[] __initdata = {
 static void au1200_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
 				 unsigned int ctrl)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	unsigned long ioaddr = (unsigned long)this->IO_ADDR_W;
 
 	ioaddr &= 0xffffff00;
diff --git a/arch/mips/alchemy/devboards/db1300.c b/arch/mips/alchemy/devboards/db1300.c
index 06c18a80a129..a92141d1a96f 100644
--- a/arch/mips/alchemy/devboards/db1300.c
+++ b/arch/mips/alchemy/devboards/db1300.c
@@ -150,7 +150,7 @@ static void __init db1300_gpio_config(void)
 static void au1300_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
 				 unsigned int ctrl)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	unsigned long ioaddr = (unsigned long)this->IO_ADDR_W;
 
 	ioaddr &= 0xffffff00;
diff --git a/arch/mips/alchemy/devboards/db1550.c b/arch/mips/alchemy/devboards/db1550.c
index 421bd5793f7e..3c5a803e38fe 100644
--- a/arch/mips/alchemy/devboards/db1550.c
+++ b/arch/mips/alchemy/devboards/db1550.c
@@ -128,7 +128,7 @@ static struct i2c_board_info db1550_i2c_devs[] __initdata = {
 static void au1550_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
 				 unsigned int ctrl)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	unsigned long ioaddr = (unsigned long)this->IO_ADDR_W;
 
 	ioaddr &= 0xffffff00;
diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c
index 258fd03c9ef5..28f3984da44f 100644
--- a/arch/mips/jz4740/board-qi_lb60.c
+++ b/arch/mips/jz4740/board-qi_lb60.c
@@ -138,7 +138,7 @@ static void qi_lb60_nand_ident(struct platform_device *pdev,
 		struct mtd_info *mtd, struct mtd_partition **partitions,
 		int *num_partitions)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	if (chip->page_shift == 12) {
 		*partitions = qi_lb60_partitions_2gb;
diff --git a/arch/mips/pnx833x/common/platform.c b/arch/mips/pnx833x/common/platform.c
index a7a4e9f5146d..df8db2d08e28 100644
--- a/arch/mips/pnx833x/common/platform.c
+++ b/arch/mips/pnx833x/common/platform.c
@@ -180,7 +180,7 @@ static struct platform_device pnx833x_sata_device = {
 static void
 pnx833x_flash_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	unsigned long nandaddr = (unsigned long)this->IO_ADDR_W;
 
 	if (cmd == NAND_CMD_NONE)
diff --git a/arch/mips/rb532/devices.c b/arch/mips/rb532/devices.c
index 32ea3e6731d6..914b01e2dfcf 100644
--- a/arch/mips/rb532/devices.c
+++ b/arch/mips/rb532/devices.c
@@ -148,7 +148,7 @@ static int rb532_dev_ready(struct mtd_info *mtd)
 
 static void rb532_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	unsigned char orbits, nandbits;
 
 	if (ctrl & NAND_CTRL_CHANGE) {
diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c
index 0bcbe58b11e9..08bb54d5cade 100644
--- a/arch/sh/boards/mach-migor/setup.c
+++ b/arch/sh/boards/mach-migor/setup.c
@@ -166,7 +166,7 @@ static struct mtd_partition migor_nand_flash_partitions[] = {
 static void migor_nand_flash_cmd_ctl(struct mtd_info *mtd, int cmd,
 				     unsigned int ctrl)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	if (cmd == NAND_CMD_NONE)
 		return;
diff --git a/drivers/mtd/nand/raw/ams-delta.c b/drivers/mtd/nand/raw/ams-delta.c
index 0972493b6cd2..c8b8d8b93f74 100644
--- a/drivers/mtd/nand/raw/ams-delta.c
+++ b/drivers/mtd/nand/raw/ams-delta.c
@@ -64,7 +64,7 @@ static struct mtd_partition partition_info[] = {
 
 static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	void __iomem *io_base = (void __iomem *)nand_get_controller_data(this);
 
 	writew(0, io_base + OMAP_MPUIO_IO_CNTL);
@@ -77,7 +77,7 @@ static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte)
 static u_char ams_delta_read_byte(struct mtd_info *mtd)
 {
 	u_char res;
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	void __iomem *io_base = (void __iomem *)nand_get_controller_data(this);
 
 	gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NRE, 0);
@@ -190,7 +190,7 @@ static int ams_delta_init(struct platform_device *pdev)
 		goto out;
 	}
 
-	ams_delta_mtd = nand_to_mtd(this);
+	ams_delta_mtd = nandc_to_mtd(this);
 	ams_delta_mtd->owner = THIS_MODULE;
 
 	/*
@@ -271,7 +271,7 @@ static int ams_delta_cleanup(struct platform_device *pdev)
 	iounmap(io_base);
 
 	/* Free the MTD device structure */
-	kfree(mtd_to_nand(ams_delta_mtd));
+	kfree(mtd_to_nandc(ams_delta_mtd));
 
 	return 0;
 }
diff --git a/drivers/mtd/nand/raw/atmel_nand.c b/drivers/mtd/nand/raw/atmel_nand.c
index fbb7e5da2541..f72bb35b53c1 100644
--- a/drivers/mtd/nand/raw/atmel_nand.c
+++ b/drivers/mtd/nand/raw/atmel_nand.c
@@ -194,7 +194,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_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
 
 	if (ctrl & NAND_CTRL_CHANGE) {
@@ -217,7 +217,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_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
 
 	return gpio_get_value(host->board.rdy_pin) ^
@@ -227,7 +227,7 @@ static int atmel_nand_device_ready(struct mtd_info *mtd)
 /* Set up for hardware ready pin and enable pin. */
 static int atmel_nand_set_enable_ready_pins(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct atmel_nand_host *host = nand_get_controller_data(chip);
 	int res = 0;
 
@@ -279,7 +279,7 @@ static int atmel_nand_set_enable_ready_pins(struct mtd_info *mtd)
  */
 static void atmel_read_buf8(struct mtd_info *mtd, u8 *buf, int len)
 {
-	struct nand_chip	*nand_chip = mtd_to_nand(mtd);
+	struct nand_chip	*nand_chip = mtd_to_nandc(mtd);
 	struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
 
 	if (host->nfc && host->nfc->use_nfc_sram && host->nfc->data_in_sram) {
@@ -292,7 +292,7 @@ static void atmel_read_buf8(struct mtd_info *mtd, u8 *buf, int len)
 
 static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len)
 {
-	struct nand_chip	*nand_chip = mtd_to_nand(mtd);
+	struct nand_chip	*nand_chip = mtd_to_nandc(mtd);
 	struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
 
 	if (host->nfc && host->nfc->use_nfc_sram && host->nfc->data_in_sram) {
@@ -305,14 +305,14 @@ static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len)
 
 static void atmel_write_buf8(struct mtd_info *mtd, const u8 *buf, int len)
 {
-	struct nand_chip	*nand_chip = mtd_to_nand(mtd);
+	struct nand_chip	*nand_chip = mtd_to_nandc(mtd);
 
 	__raw_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_to_nand(mtd);
+	struct nand_chip	*nand_chip = mtd_to_nandc(mtd);
 
 	__raw_writesw(nand_chip->IO_ADDR_W, buf, len / 2);
 }
@@ -329,7 +329,7 @@ static int nfc_set_sram_bank(struct atmel_nand_host *host, unsigned int bank)
 		return -EINVAL;
 
 	if (bank) {
-		struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
+		struct mtd_info *mtd = nandc_to_mtd(&host->nand_chip);
 
 		/* Only for a 2k-page or lower flash, NFC can handle 2 banks */
 		if (mtd->writesize > 2048)
@@ -366,7 +366,7 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
 	dma_addr_t dma_src_addr, dma_dst_addr, phys_addr;
 	struct dma_async_tx_descriptor *tx = NULL;
 	dma_cookie_t cookie;
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct atmel_nand_host *host = nand_get_controller_data(chip);
 	void *p = buf;
 	int err = -EIO;
@@ -439,7 +439,7 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
 
 static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	if (use_dma && len > mtd->oobsize)
 		/* only use DMA for bigger than oob size: better performances */
@@ -454,7 +454,7 @@ static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len)
 
 static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	if (use_dma && len > mtd->oobsize)
 		/* only use DMA for bigger than oob size: better performances */
@@ -530,7 +530,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_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
 	int i;
 	uint32_t value;
@@ -547,7 +547,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_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
 	int16_t __iomem *alpha_to = host->pmecc_alpha_to;
 	int16_t __iomem *index_of = host->pmecc_index_of;
@@ -589,7 +589,7 @@ static void pmecc_substitute(struct mtd_info *mtd)
 
 static void pmecc_get_sigma(struct mtd_info *mtd)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
 
 	int16_t *lmu = host->pmecc_lmu;
@@ -747,7 +747,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_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
 	unsigned long end_time;
 	const int cap = host->pmecc_corr_cap;
@@ -799,7 +799,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_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
 	int i = 0;
 	int byte_pos, bit_pos, sector_size, pos;
@@ -848,7 +848,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_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
 	int i, err_nbr;
 	uint8_t *buf_pos;
@@ -1001,7 +1001,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_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
 	int eccbytes = mtd_ooblayout_count_eccbytes(mtd);
 	uint32_t val = 0;
@@ -1178,7 +1178,7 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
 					 struct atmel_nand_host *host)
 {
 	struct nand_chip *nand_chip = &host->nand_chip;
-	struct mtd_info *mtd = nand_to_mtd(nand_chip);
+	struct mtd_info *mtd = nandc_to_mtd(nand_chip);
 	struct resource *regs, *regs_pmerr, *regs_rom;
 	uint16_t *galois_table;
 	int cap, sector_size, err_no;
@@ -1327,7 +1327,7 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
 static int atmel_nand_calculate(struct mtd_info *mtd,
 		const u_char *dat, unsigned char *ecc_code)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
 	unsigned int ecc_value;
 
@@ -1432,7 +1432,7 @@ static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
 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_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
 	unsigned int ecc_status;
 	unsigned int ecc_word, ecc_bit;
@@ -1498,7 +1498,7 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
  */
 static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
 
 	if (host->board.need_reset_workaround)
@@ -1619,7 +1619,7 @@ static int atmel_hw_nand_init_params(struct platform_device *pdev,
 					 struct atmel_nand_host *host)
 {
 	struct nand_chip *nand_chip = &host->nand_chip;
-	struct mtd_info *mtd = nand_to_mtd(nand_chip);
+	struct mtd_info *mtd = nandc_to_mtd(nand_chip);
 	struct resource		*regs;
 
 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
@@ -1805,7 +1805,7 @@ static int nfc_send_command(struct atmel_nand_host *host,
 static int nfc_device_ready(struct mtd_info *mtd)
 {
 	u32 status, mask;
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
 
 	status = nfc_read_status(host);
@@ -1821,7 +1821,7 @@ static int nfc_device_ready(struct mtd_info *mtd)
 
 static void nfc_select_chip(struct mtd_info *mtd, int chip)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
 
 	if (chip == -1)
@@ -1833,7 +1833,7 @@ static void nfc_select_chip(struct mtd_info *mtd, int chip)
 static int nfc_make_addr(struct mtd_info *mtd, int command, int column,
 		int page_addr, unsigned int *addr1234, unsigned int *cycle0)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	int acycle = 0;
 	unsigned char addr_bytes[8];
@@ -1873,7 +1873,7 @@ static int nfc_make_addr(struct mtd_info *mtd, int command, int column,
 static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
 				int column, int page_addr)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct atmel_nand_host *host = nand_get_controller_data(chip);
 	unsigned long timeout;
 	unsigned int nfc_addr_cmd = 0;
@@ -2060,7 +2060,7 @@ static int nfc_sram_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 
 static int nfc_sram_init(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct atmel_nand_host *host = nand_get_controller_data(chip);
 	int res = 0;
 
@@ -2147,7 +2147,7 @@ static int atmel_nand_probe(struct platform_device *pdev)
 	host->io_phys = (dma_addr_t)mem->start;
 
 	nand_chip = &host->nand_chip;
-	mtd = nand_to_mtd(nand_chip);
+	mtd = nandc_to_mtd(nand_chip);
 	host->dev = &pdev->dev;
 	if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
 		nand_set_flash_node(nand_chip, pdev->dev.of_node);
@@ -2334,7 +2334,7 @@ static int atmel_nand_probe(struct platform_device *pdev)
 static int atmel_nand_remove(struct platform_device *pdev)
 {
 	struct atmel_nand_host *host = platform_get_drvdata(pdev);
-	struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
+	struct mtd_info *mtd = nandc_to_mtd(&host->nand_chip);
 
 	nand_release(mtd);
 
diff --git a/drivers/mtd/nand/raw/au1550nd.c b/drivers/mtd/nand/raw/au1550nd.c
index 9d4a28fa6b73..c4dd144f25e0 100644
--- a/drivers/mtd/nand/raw/au1550nd.c
+++ b/drivers/mtd/nand/raw/au1550nd.c
@@ -38,7 +38,7 @@ struct au1550nd_ctx {
  */
 static u_char au_read_byte(struct mtd_info *mtd)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	u_char ret = readb(this->IO_ADDR_R);
 	wmb(); /* drain writebuffer */
 	return ret;
@@ -53,7 +53,7 @@ static u_char au_read_byte(struct mtd_info *mtd)
  */
 static void au_write_byte(struct mtd_info *mtd, u_char byte)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	writeb(byte, this->IO_ADDR_W);
 	wmb(); /* drain writebuffer */
 }
@@ -66,7 +66,7 @@ static void au_write_byte(struct mtd_info *mtd, u_char byte)
  */
 static u_char au_read_byte16(struct mtd_info *mtd)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	u_char ret = (u_char) cpu_to_le16(readw(this->IO_ADDR_R));
 	wmb(); /* drain writebuffer */
 	return ret;
@@ -81,7 +81,7 @@ static u_char au_read_byte16(struct mtd_info *mtd)
  */
 static void au_write_byte16(struct mtd_info *mtd, u_char byte)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	writew(le16_to_cpu((u16) byte), this->IO_ADDR_W);
 	wmb(); /* drain writebuffer */
 }
@@ -94,7 +94,7 @@ static void au_write_byte16(struct mtd_info *mtd, u_char byte)
  */
 static u16 au_read_word(struct mtd_info *mtd)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	u16 ret = readw(this->IO_ADDR_R);
 	wmb(); /* drain writebuffer */
 	return ret;
@@ -111,7 +111,7 @@ static u16 au_read_word(struct mtd_info *mtd)
 static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
 {
 	int i;
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 
 	for (i = 0; i < len; i++) {
 		writeb(buf[i], this->IO_ADDR_W);
@@ -130,7 +130,7 @@ static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
 static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 {
 	int i;
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 
 	for (i = 0; i < len; i++) {
 		buf[i] = readb(this->IO_ADDR_R);
@@ -149,7 +149,7 @@ static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len)
 {
 	int i;
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	u16 *p = (u16 *) buf;
 	len >>= 1;
 
@@ -171,7 +171,7 @@ static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len)
 static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
 {
 	int i;
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	u16 *p = (u16 *) buf;
 	len >>= 1;
 
@@ -196,7 +196,7 @@ static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
 
 static void au1550_hwcontrol(struct mtd_info *mtd, int cmd)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct au1550nd_ctx *ctx = container_of(this, struct au1550nd_ctx,
 						chip);
 
@@ -267,7 +267,7 @@ static void au1550_select_chip(struct mtd_info *mtd, int chip)
  */
 static void au1550_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct au1550nd_ctx *ctx = container_of(this, struct au1550nd_ctx,
 						chip);
 	int ce_override = 0, i;
@@ -440,7 +440,7 @@ static int au1550nd_probe(struct platform_device *pdev)
 	}
 
 	this = &ctx->chip;
-	mtd = nand_to_mtd(this);
+	mtd = nandc_to_mtd(this);
 	mtd->dev.parent = &pdev->dev;
 
 	/* figure out which CS# r->start belongs to */
@@ -496,7 +496,7 @@ static int au1550nd_remove(struct platform_device *pdev)
 	struct au1550nd_ctx *ctx = platform_get_drvdata(pdev);
 	struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
-	nand_release(nand_to_mtd(&ctx->chip));
+	nand_release(nandc_to_mtd(&ctx->chip));
 	iounmap(ctx->base);
 	release_mem_region(r->start, 0x1000);
 	kfree(ctx);
diff --git a/drivers/mtd/nand/raw/bcm47xxnflash/main.c b/drivers/mtd/nand/raw/bcm47xxnflash/main.c
index fb31429b70a9..3c10466f3bf3 100644
--- a/drivers/mtd/nand/raw/bcm47xxnflash/main.c
+++ b/drivers/mtd/nand/raw/bcm47xxnflash/main.c
@@ -35,7 +35,7 @@ static int bcm47xxnflash_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	nand_set_controller_data(&b47n->nand_chip, b47n);
-	mtd = nand_to_mtd(&b47n->nand_chip);
+	mtd = nandc_to_mtd(&b47n->nand_chip);
 	mtd->dev.parent = &pdev->dev;
 	b47n->cc = container_of(nflash, struct bcma_drv_cc, nflash);
 
@@ -65,7 +65,7 @@ static int bcm47xxnflash_remove(struct platform_device *pdev)
 {
 	struct bcm47xxnflash *nflash = platform_get_drvdata(pdev);
 
-	nand_release(nand_to_mtd(&nflash->nand_chip));
+	nand_release(nandc_to_mtd(&nflash->nand_chip));
 
 	return 0;
 }
diff --git a/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c
index f1da4ea88f2c..93e1f61b7b77 100644
--- a/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c
+++ b/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c
@@ -89,7 +89,7 @@ static int bcm47xxnflash_ops_bcm4706_poll(struct bcma_drv_cc *cc)
 static void bcm47xxnflash_ops_bcm4706_read(struct mtd_info *mtd, uint8_t *buf,
 					   int len)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
 
 	u32 ctlcode;
@@ -139,7 +139,7 @@ static void bcm47xxnflash_ops_bcm4706_read(struct mtd_info *mtd, uint8_t *buf,
 static void bcm47xxnflash_ops_bcm4706_write(struct mtd_info *mtd,
 					    const uint8_t *buf, int len)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
 	struct bcma_drv_cc *cc = b47n->cc;
 
@@ -173,7 +173,7 @@ static void bcm47xxnflash_ops_bcm4706_write(struct mtd_info *mtd,
 static void bcm47xxnflash_ops_bcm4706_cmd_ctrl(struct mtd_info *mtd, int cmd,
 					       unsigned int ctrl)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
 	u32 code = 0;
 
@@ -199,7 +199,7 @@ static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd,
 
 static int bcm47xxnflash_ops_bcm4706_dev_ready(struct mtd_info *mtd)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
 
 	return !!(bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_CTL) & NCTL_READY);
@@ -216,7 +216,7 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
 					      unsigned command, int column,
 					      int page_addr)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
 	struct bcma_drv_cc *cc = b47n->cc;
 	u32 ctlcode;
@@ -312,7 +312,7 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
 
 static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
 	struct bcma_drv_cc *cc = b47n->cc;
 	u32 tmp = 0;
@@ -341,7 +341,7 @@ static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd)
 static void bcm47xxnflash_ops_bcm4706_read_buf(struct mtd_info *mtd,
 					       uint8_t *buf, int len)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
 
 	switch (b47n->curr_command) {
@@ -357,7 +357,7 @@ static void bcm47xxnflash_ops_bcm4706_read_buf(struct mtd_info *mtd,
 static void bcm47xxnflash_ops_bcm4706_write_buf(struct mtd_info *mtd,
 						const uint8_t *buf, int len)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
 
 	switch (b47n->curr_command) {
@@ -421,7 +421,7 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
 			(w4 << 24 | w3 << 18 | w2 << 12 | w1 << 6 | w0));
 
 	/* Scan NAND */
-	err = nand_scan(nand_to_mtd(&b47n->nand_chip), 1);
+	err = nand_scan(nandc_to_mtd(&b47n->nand_chip), 1);
 	if (err) {
 		pr_err("Could not scan NAND flash: %d\n", err);
 		goto exit;
diff --git a/drivers/mtd/nand/raw/bf5xx_nand.c b/drivers/mtd/nand/raw/bf5xx_nand.c
index 5655dca6ce43..84d673f7cf36 100644
--- a/drivers/mtd/nand/raw/bf5xx_nand.c
+++ b/drivers/mtd/nand/raw/bf5xx_nand.c
@@ -162,9 +162,9 @@ struct bf5xx_nand_info {
 /*
  * Conversion functions
  */
-static struct bf5xx_nand_info *mtd_to_nand_info(struct mtd_info *mtd)
+static struct bf5xx_nand_info *mtd_to_nandc_info(struct mtd_info *mtd)
 {
-	return container_of(mtd_to_nand(mtd), struct bf5xx_nand_info,
+	return container_of(mtd_to_nandc(mtd), struct bf5xx_nand_info,
 			    chip);
 }
 
@@ -230,7 +230,7 @@ static int bf5xx_nand_devready(struct mtd_info *mtd)
 static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat,
 					u_char *read_ecc, u_char *calc_ecc)
 {
-	struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
+	struct bf5xx_nand_info *info = mtd_to_nandc_info(mtd);
 	u32 syndrome[5];
 	u32 calced, stored;
 	int i;
@@ -309,7 +309,7 @@ static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat,
 static int bf5xx_nand_correct_data(struct mtd_info *mtd, u_char *dat,
 					u_char *read_ecc, u_char *calc_ecc)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	int ret, bitflips = 0;
 
 	ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
@@ -341,8 +341,8 @@ static void bf5xx_nand_enable_hwecc(struct mtd_info *mtd, int mode)
 static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd,
 		const u_char *dat, u_char *ecc_code)
 {
-	struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct bf5xx_nand_info *info = mtd_to_nandc_info(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	u16 ecc0, ecc1;
 	u32 code[2];
 	u8 *p;
@@ -478,8 +478,8 @@ static irqreturn_t bf5xx_nand_dma_irq(int irq, void *dev_id)
 static void bf5xx_nand_dma_rw(struct mtd_info *mtd,
 				uint8_t *buf, int is_read)
 {
-	struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct bf5xx_nand_info *info = mtd_to_nandc_info(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	unsigned short val;
 
 	dev_dbg(info->device, " mtd->%p, buf->%p, is_read %d\n",
@@ -544,8 +544,8 @@ static void bf5xx_nand_dma_rw(struct mtd_info *mtd,
 static void bf5xx_nand_dma_read_buf(struct mtd_info *mtd,
 					uint8_t *buf, int len)
 {
-	struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct bf5xx_nand_info *info = mtd_to_nandc_info(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	dev_dbg(info->device, "mtd->%p, buf->%p, int %d\n", mtd, buf, len);
 
@@ -558,8 +558,8 @@ static void bf5xx_nand_dma_read_buf(struct mtd_info *mtd,
 static void bf5xx_nand_dma_write_buf(struct mtd_info *mtd,
 				const uint8_t *buf, int len)
 {
-	struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct bf5xx_nand_info *info = mtd_to_nandc_info(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	dev_dbg(info->device, "mtd->%p, buf->%p, len %d\n", mtd, buf, len);
 
@@ -673,7 +673,7 @@ static int bf5xx_nand_hw_init(struct bf5xx_nand_info *info)
  */
 static int bf5xx_nand_add_partition(struct bf5xx_nand_info *info)
 {
-	struct mtd_info *mtd = nand_to_mtd(&info->chip);
+	struct mtd_info *mtd = nandc_to_mtd(&info->chip);
 	struct mtd_partition *parts = info->platform->partitions;
 	int nr = info->platform->nr_partitions;
 
@@ -688,7 +688,7 @@ static int bf5xx_nand_remove(struct platform_device *pdev)
 	 * and their partitions, then go through freeing the
 	 * resources used
 	 */
-	nand_release(nand_to_mtd(&info->chip));
+	nand_release(nandc_to_mtd(&info->chip));
 
 	peripheral_free_list(bfin_nfc_pin_req);
 	bf5xx_nand_dma_remove(info);
@@ -698,7 +698,7 @@ static int bf5xx_nand_remove(struct platform_device *pdev)
 
 static int bf5xx_nand_scan(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	int ret;
 
 	ret = nand_scan_ident(mtd, 1, NULL);
@@ -768,7 +768,7 @@ static int bf5xx_nand_probe(struct platform_device *pdev)
 
 	/* initialise chip data struct */
 	chip = &info->chip;
-	mtd = nand_to_mtd(&info->chip);
+	mtd = nandc_to_mtd(&info->chip);
 
 	if (plat->data_width)
 		chip->options |= NAND_BUSWIDTH_16;
diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
index 98453816a0a2..62545f25c87e 100644
--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
@@ -844,7 +844,7 @@ static inline bool is_hamming_ecc(struct brcmnand_controller *ctrl,
 static int brcmnand_hamming_ooblayout_ecc(struct mtd_info *mtd, int section,
 					  struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct brcmnand_host *host = nand_get_controller_data(chip);
 	struct brcmnand_cfg *cfg = &host->hwcfg;
 	int sas = cfg->spare_area_size << cfg->sector_size_1k;
@@ -862,7 +862,7 @@ static int brcmnand_hamming_ooblayout_ecc(struct mtd_info *mtd, int section,
 static int brcmnand_hamming_ooblayout_free(struct mtd_info *mtd, int section,
 					   struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct brcmnand_host *host = nand_get_controller_data(chip);
 	struct brcmnand_cfg *cfg = &host->hwcfg;
 	int sas = cfg->spare_area_size << cfg->sector_size_1k;
@@ -902,7 +902,7 @@ static const struct mtd_ooblayout_ops brcmnand_hamming_ooblayout_ops = {
 static int brcmnand_bch_ooblayout_ecc(struct mtd_info *mtd, int section,
 				      struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct brcmnand_host *host = nand_get_controller_data(chip);
 	struct brcmnand_cfg *cfg = &host->hwcfg;
 	int sas = cfg->spare_area_size << cfg->sector_size_1k;
@@ -920,7 +920,7 @@ static int brcmnand_bch_ooblayout_ecc(struct mtd_info *mtd, int section,
 static int brcmnand_bch_ooblayout_free_lp(struct mtd_info *mtd, int section,
 					  struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct brcmnand_host *host = nand_get_controller_data(chip);
 	struct brcmnand_cfg *cfg = &host->hwcfg;
 	int sas = cfg->spare_area_size << cfg->sector_size_1k;
@@ -946,7 +946,7 @@ static int brcmnand_bch_ooblayout_free_lp(struct mtd_info *mtd, int section,
 static int brcmnand_bch_ooblayout_free_sp(struct mtd_info *mtd, int section,
 					  struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct brcmnand_host *host = nand_get_controller_data(chip);
 	struct brcmnand_cfg *cfg = &host->hwcfg;
 	int sas = cfg->spare_area_size << cfg->sector_size_1k;
@@ -979,7 +979,7 @@ static const struct mtd_ooblayout_ops brcmnand_bch_sp_ooblayout_ops = {
 static int brcmstb_choose_ecc_layout(struct brcmnand_host *host)
 {
 	struct brcmnand_cfg *p = &host->hwcfg;
-	struct mtd_info *mtd = nand_to_mtd(&host->chip);
+	struct mtd_info *mtd = nandc_to_mtd(&host->chip);
 	struct nand_ecc_ctrl *ecc = &host->chip.ecc;
 	unsigned int ecc_level = p->ecc_level;
 	int sas = p->spare_area_size << p->sector_size_1k;
@@ -1018,7 +1018,7 @@ static int brcmstb_choose_ecc_layout(struct brcmnand_host *host)
 
 static void brcmnand_wp(struct mtd_info *mtd, int wp)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct brcmnand_host *host = nand_get_controller_data(chip);
 	struct brcmnand_controller *ctrl = host->ctrl;
 
@@ -1184,7 +1184,7 @@ static void brcmnand_cmd_ctrl(struct mtd_info *mtd, int dat,
 
 static int brcmnand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct brcmnand_host *host = nand_get_controller_data(chip);
 	struct brcmnand_controller *ctrl = host->ctrl;
 	unsigned long timeo = msecs_to_jiffies(100);
@@ -1219,7 +1219,7 @@ static int brcmnand_low_level_op(struct brcmnand_host *host,
 				 enum brcmnand_llop_type type, u32 data,
 				 bool last_op)
 {
-	struct mtd_info *mtd = nand_to_mtd(&host->chip);
+	struct mtd_info *mtd = nandc_to_mtd(&host->chip);
 	struct nand_chip *chip = &host->chip;
 	struct brcmnand_controller *ctrl = host->ctrl;
 	u32 tmp;
@@ -1258,7 +1258,7 @@ static int brcmnand_low_level_op(struct brcmnand_host *host,
 static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
 			     int column, int page_addr)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct brcmnand_host *host = nand_get_controller_data(chip);
 	struct brcmnand_controller *ctrl = host->ctrl;
 	u64 addr = (u64)page_addr << chip->page_shift;
@@ -1364,7 +1364,7 @@ static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
 
 static uint8_t brcmnand_read_byte(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct brcmnand_host *host = nand_get_controller_data(chip);
 	struct brcmnand_controller *ctrl = host->ctrl;
 	uint8_t ret = 0;
@@ -1431,7 +1431,7 @@ static void brcmnand_write_buf(struct mtd_info *mtd, const uint8_t *buf,
 				   int len)
 {
 	int i;
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct brcmnand_host *host = nand_get_controller_data(chip);
 
 	switch (host->last_cmd) {
@@ -2028,7 +2028,7 @@ static inline int get_blk_adr_bytes(u64 size, u32 writesize)
 
 static int brcmnand_setup_dev(struct brcmnand_host *host)
 {
-	struct mtd_info *mtd = nand_to_mtd(&host->chip);
+	struct mtd_info *mtd = nandc_to_mtd(&host->chip);
 	struct nand_chip *chip = &host->chip;
 	struct brcmnand_controller *ctrl = host->ctrl;
 	struct brcmnand_cfg *cfg = &host->hwcfg;
@@ -2168,7 +2168,7 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
 		return -ENXIO;
 	}
 
-	mtd = nand_to_mtd(&host->chip);
+	mtd = nandc_to_mtd(&host->chip);
 	chip = &host->chip;
 
 	nand_set_flash_node(chip, dn);
@@ -2312,7 +2312,7 @@ static int brcmnand_resume(struct device *dev)
 
 	list_for_each_entry(host, &ctrl->host_list, node) {
 		struct nand_chip *chip = &host->chip;
-		struct mtd_info *mtd = nand_to_mtd(chip);
+		struct mtd_info *mtd = nandc_to_mtd(chip);
 
 		brcmnand_save_restore_cs_config(host, 1);
 
@@ -2544,7 +2544,7 @@ int brcmnand_remove(struct platform_device *pdev)
 	struct brcmnand_host *host;
 
 	list_for_each_entry(host, &ctrl->host_list, node)
-		nand_release(nand_to_mtd(&host->chip));
+		nand_release(nandc_to_mtd(&host->chip));
 
 	clk_disable_unprepare(ctrl->clk);
 
diff --git a/drivers/mtd/nand/raw/cafe_nand.c b/drivers/mtd/nand/raw/cafe_nand.c
index 93880171740a..30538a9bba4e 100644
--- a/drivers/mtd/nand/raw/cafe_nand.c
+++ b/drivers/mtd/nand/raw/cafe_nand.c
@@ -101,7 +101,7 @@ static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
 
 static int cafe_device_ready(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct cafe_priv *cafe = nand_get_controller_data(chip);
 	int result = !!(cafe_readl(cafe, NAND_STATUS) & 0x40000000);
 	uint32_t irqs = cafe_readl(cafe, NAND_IRQ);
@@ -118,7 +118,7 @@ static int cafe_device_ready(struct mtd_info *mtd)
 
 static void cafe_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct cafe_priv *cafe = nand_get_controller_data(chip);
 
 	if (usedma)
@@ -134,7 +134,7 @@ static void cafe_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 
 static void cafe_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct cafe_priv *cafe = nand_get_controller_data(chip);
 
 	if (usedma)
@@ -149,7 +149,7 @@ static void cafe_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 
 static uint8_t cafe_read_byte(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct cafe_priv *cafe = nand_get_controller_data(chip);
 	uint8_t d;
 
@@ -162,7 +162,7 @@ static uint8_t cafe_read_byte(struct mtd_info *mtd)
 static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
 			      int column, int page_addr)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct cafe_priv *cafe = nand_get_controller_data(chip);
 	int adrbytes = 0;
 	uint32_t ctl1;
@@ -318,7 +318,7 @@ static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
 
 static void cafe_select_chip(struct mtd_info *mtd, int chipnr)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct cafe_priv *cafe = nand_get_controller_data(chip);
 
 	cafe_dev_dbg(&cafe->pdev->dev, "select_chip %d\n", chipnr);
@@ -334,7 +334,7 @@ static void cafe_select_chip(struct mtd_info *mtd, int chipnr)
 static irqreturn_t cafe_nand_interrupt(int irq, void *id)
 {
 	struct mtd_info *mtd = id;
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct cafe_priv *cafe = nand_get_controller_data(chip);
 	uint32_t irqs = cafe_readl(cafe, NAND_IRQ);
 	cafe_writel(cafe, irqs & ~0x90000000, NAND_IRQ);
@@ -462,7 +462,7 @@ static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
 static int cafe_ooblayout_ecc(struct mtd_info *mtd, int section,
 			      struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	if (section)
 		return -ERANGE;
@@ -476,7 +476,7 @@ static int cafe_ooblayout_ecc(struct mtd_info *mtd, int section,
 static int cafe_ooblayout_free(struct mtd_info *mtd, int section,
 			       struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	if (section)
 		return -ERANGE;
@@ -630,7 +630,7 @@ static int cafe_nand_probe(struct pci_dev *pdev,
 	if (!cafe)
 		return  -ENOMEM;
 
-	mtd = nand_to_mtd(&cafe->nand);
+	mtd = nandc_to_mtd(&cafe->nand);
 	mtd->dev.parent = &pdev->dev;
 	nand_set_controller_data(&cafe->nand, cafe);
 
@@ -819,7 +819,7 @@ static int cafe_nand_probe(struct pci_dev *pdev,
 static void cafe_nand_remove(struct pci_dev *pdev)
 {
 	struct mtd_info *mtd = pci_get_drvdata(pdev);
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct cafe_priv *cafe = nand_get_controller_data(chip);
 
 	/* Disable NAND IRQ in global IRQ mask register */
@@ -847,7 +847,7 @@ static int cafe_nand_resume(struct pci_dev *pdev)
 {
 	uint32_t ctrl;
 	struct mtd_info *mtd = pci_get_drvdata(pdev);
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct cafe_priv *cafe = nand_get_controller_data(chip);
 
        /* Start off by resetting the NAND controller completely */
diff --git a/drivers/mtd/nand/raw/cmx270_nand.c b/drivers/mtd/nand/raw/cmx270_nand.c
index 2efe6a56557f..d7bd5f48acab 100644
--- a/drivers/mtd/nand/raw/cmx270_nand.c
+++ b/drivers/mtd/nand/raw/cmx270_nand.c
@@ -53,7 +53,7 @@ static struct mtd_partition partition_info[] = {
 
 static u_char cmx270_read_byte(struct mtd_info *mtd)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 
 	return (readl(this->IO_ADDR_R) >> 16);
 }
@@ -61,7 +61,7 @@ static u_char cmx270_read_byte(struct mtd_info *mtd)
 static void cmx270_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
 {
 	int i;
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 
 	for (i=0; i<len; i++)
 		writel((*buf++ << 16), this->IO_ADDR_W);
@@ -70,7 +70,7 @@ static void cmx270_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
 static void cmx270_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 {
 	int i;
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 
 	for (i=0; i<len; i++)
 		*buf++ = readl(this->IO_ADDR_R) >> 16;
@@ -94,7 +94,7 @@ static void nand_cs_off(void)
 static void cmx270_hwcontrol(struct mtd_info *mtd, int dat,
 			     unsigned int ctrl)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	unsigned int nandaddr = (unsigned int)this->IO_ADDR_W;
 
 	dsb();
@@ -173,7 +173,7 @@ static int __init cmx270_init(void)
 		goto err_ioremap;
 	}
 
-	cmx270_nand_mtd = nand_to_mtd(this);
+	cmx270_nand_mtd = nandc_to_mtd(this);
 
 	/* Link the private data with the MTD structure */
 	cmx270_nand_mtd->owner = THIS_MODULE;
@@ -237,7 +237,7 @@ static void __exit cmx270_cleanup(void)
 
 	iounmap(cmx270_nand_io);
 
-	kfree(mtd_to_nand(cmx270_nand_mtd));
+	kfree(mtd_to_nandc(cmx270_nand_mtd));
 }
 module_exit(cmx270_cleanup);
 
diff --git a/drivers/mtd/nand/raw/cs553x_nand.c b/drivers/mtd/nand/raw/cs553x_nand.c
index 8fafb4b4488d..2ba279878903 100644
--- a/drivers/mtd/nand/raw/cs553x_nand.c
+++ b/drivers/mtd/nand/raw/cs553x_nand.c
@@ -97,7 +97,7 @@
 
 static void cs553x_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 
 	while (unlikely(len > 0x800)) {
 		memcpy_fromio(buf, this->IO_ADDR_R, 0x800);
@@ -109,7 +109,7 @@ static void cs553x_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 
 static void cs553x_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 
 	while (unlikely(len > 0x800)) {
 		memcpy_toio(this->IO_ADDR_R, buf, 0x800);
@@ -121,13 +121,13 @@ static void cs553x_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
 
 static unsigned char cs553x_read_byte(struct mtd_info *mtd)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	return readb(this->IO_ADDR_R);
 }
 
 static void cs553x_write_byte(struct mtd_info *mtd, u_char byte)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	int i = 100000;
 
 	while (i && readb(this->IO_ADDR_R + MM_NAND_STS) & CS_NAND_CTLR_BUSY) {
@@ -140,7 +140,7 @@ static void cs553x_write_byte(struct mtd_info *mtd, u_char byte)
 static void cs553x_hwcontrol(struct mtd_info *mtd, int cmd,
 			     unsigned int ctrl)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	void __iomem *mmio_base = this->IO_ADDR_R;
 	if (ctrl & NAND_CTRL_CHANGE) {
 		unsigned char ctl = (ctrl & ~NAND_CTRL_CHANGE ) ^ 0x01;
@@ -152,7 +152,7 @@ static void cs553x_hwcontrol(struct mtd_info *mtd, int cmd,
 
 static int cs553x_device_ready(struct mtd_info *mtd)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	void __iomem *mmio_base = this->IO_ADDR_R;
 	unsigned char foo = readb(mmio_base + MM_NAND_STS);
 
@@ -161,7 +161,7 @@ static int cs553x_device_ready(struct mtd_info *mtd)
 
 static void cs_enable_hwecc(struct mtd_info *mtd, int mode)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	void __iomem *mmio_base = this->IO_ADDR_R;
 
 	writeb(0x07, mmio_base + MM_NAND_ECC_CTL);
@@ -170,7 +170,7 @@ static void cs_enable_hwecc(struct mtd_info *mtd, int mode)
 static int cs_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
 {
 	uint32_t ecc;
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	void __iomem *mmio_base = this->IO_ADDR_R;
 
 	ecc = readl(mmio_base + MM_NAND_STS);
@@ -203,7 +203,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
 		goto out;
 	}
 
-	new_mtd = nand_to_mtd(this);
+	new_mtd = nandc_to_mtd(this);
 
 	/* Link the private data with the MTD structure */
 	new_mtd->owner = THIS_MODULE;
@@ -335,7 +335,7 @@ static void __exit cs553x_cleanup(void)
 		if (!mtd)
 			continue;
 
-		this = mtd_to_nand(mtd);
+		this = mtd_to_nandc(mtd);
 		mmio_base = this->IO_ADDR_R;
 
 		/* Release resources, unregister device */
diff --git a/drivers/mtd/nand/raw/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c
index 29034e378b5b..95b8109d9f47 100644
--- a/drivers/mtd/nand/raw/davinci_nand.c
+++ b/drivers/mtd/nand/raw/davinci_nand.c
@@ -79,7 +79,7 @@ static bool ecc4_busy;
 
 static inline struct davinci_nand_info *to_davinci_nand(struct mtd_info *mtd)
 {
-	return container_of(mtd_to_nand(mtd), struct davinci_nand_info, chip);
+	return container_of(mtd_to_nandc(mtd), struct davinci_nand_info, chip);
 }
 
 static inline unsigned int davinci_nand_readl(struct davinci_nand_info *info,
@@ -105,7 +105,7 @@ static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd,
 {
 	struct davinci_nand_info	*info = to_davinci_nand(mtd);
 	uint32_t			addr = info->current_cs;
-	struct nand_chip		*nand = mtd_to_nand(mtd);
+	struct nand_chip		*nand = mtd_to_nandc(mtd);
 
 	/* Did the control lines change? */
 	if (ctrl & NAND_CTRL_CHANGE) {
@@ -191,7 +191,7 @@ static int nand_davinci_calculate_1bit(struct mtd_info *mtd,
 static int nand_davinci_correct_1bit(struct mtd_info *mtd, u_char *dat,
 				     u_char *read_ecc, u_char *calc_ecc)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	uint32_t eccNand = read_ecc[0] | (read_ecc[1] << 8) |
 					  (read_ecc[2] << 16);
 	uint32_t eccCalc = calc_ecc[0] | (calc_ecc[1] << 8) |
@@ -441,7 +441,7 @@ static int nand_davinci_correct_4bit(struct mtd_info *mtd,
  */
 static void nand_davinci_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	if ((0x03 & ((unsigned)buf)) == 0 && (0x03 & len) == 0)
 		ioread32_rep(chip->IO_ADDR_R, buf, len >> 2);
@@ -454,7 +454,7 @@ static void nand_davinci_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 static void nand_davinci_write_buf(struct mtd_info *mtd,
 		const uint8_t *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	if ((0x03 & ((unsigned)buf)) == 0 && (0x03 & len) == 0)
 		iowrite32_rep(chip->IO_ADDR_R, buf, len >> 2);
@@ -654,7 +654,7 @@ static int nand_davinci_probe(struct platform_device *pdev)
 	info->base		= base;
 	info->vaddr		= vaddr;
 
-	mtd			= nand_to_mtd(&info->chip);
+	mtd			= nandc_to_mtd(&info->chip);
 	mtd->dev.parent		= &pdev->dev;
 	nand_set_flash_node(&info->chip, pdev->dev.of_node);
 
@@ -840,7 +840,7 @@ static int nand_davinci_remove(struct platform_device *pdev)
 		ecc4_busy = false;
 	spin_unlock_irq(&davinci_nand_lock);
 
-	nand_release(nand_to_mtd(&info->chip));
+	nand_release(nandc_to_mtd(&info->chip));
 
 	clk_disable_unprepare(info->clk);
 
diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c
index 0476ae8776d9..3cbbcc682726 100644
--- a/drivers/mtd/nand/raw/denali.c
+++ b/drivers/mtd/nand/raw/denali.c
@@ -77,7 +77,7 @@ MODULE_PARM_DESC(onfi_timing_mode,
  */
 static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd)
 {
-	return container_of(mtd_to_nand(mtd), struct denali_nand_info, nand);
+	return container_of(mtd_to_nandc(mtd), struct denali_nand_info, nand);
 }
 
 /*
@@ -990,7 +990,7 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf,
 				 */
 				if (err_byte < ECC_SECTOR_SIZE) {
 					struct mtd_info *mtd =
-						nand_to_mtd(&denali->nand);
+						nandc_to_mtd(&denali->nand);
 					int offset;
 
 					offset = (err_sector *
@@ -1380,7 +1380,7 @@ static int denali_ooblayout_ecc(struct mtd_info *mtd, int section,
 				struct mtd_oob_region *oobregion)
 {
 	struct denali_nand_info *denali = mtd_to_denali(mtd);
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	if (section)
 		return -ERANGE;
@@ -1395,7 +1395,7 @@ static int denali_ooblayout_free(struct mtd_info *mtd, int section,
 				 struct mtd_oob_region *oobregion)
 {
 	struct denali_nand_info *denali = mtd_to_denali(mtd);
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	if (section)
 		return -ERANGE;
@@ -1461,7 +1461,7 @@ static void denali_drv_init(struct denali_nand_info *denali)
 
 int denali_init(struct denali_nand_info *denali)
 {
-	struct mtd_info *mtd = nand_to_mtd(&denali->nand);
+	struct mtd_info *mtd = nandc_to_mtd(&denali->nand);
 	int ret;
 
 	if (denali->platform == INTEL_CE4100) {
@@ -1647,7 +1647,7 @@ EXPORT_SYMBOL(denali_init);
 /* driver exit point */
 void denali_remove(struct denali_nand_info *denali)
 {
-	struct mtd_info *mtd = nand_to_mtd(&denali->nand);
+	struct mtd_info *mtd = nandc_to_mtd(&denali->nand);
 	/*
 	 * Pre-compute DMA buffer size to avoid any problems in case
 	 * nand_release() ever changes in a way that mtd->writesize and
diff --git a/drivers/mtd/nand/raw/diskonchip.c b/drivers/mtd/nand/raw/diskonchip.c
index c3aa53caab5c..1257365abec0 100644
--- a/drivers/mtd/nand/raw/diskonchip.c
+++ b/drivers/mtd/nand/raw/diskonchip.c
@@ -295,7 +295,7 @@ static inline int DoC_WaitReady(struct doc_priv *doc)
 
 static void doc2000_write_byte(struct mtd_info *mtd, u_char datum)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 	void __iomem *docptr = doc->virtadr;
 
@@ -307,7 +307,7 @@ static void doc2000_write_byte(struct mtd_info *mtd, u_char datum)
 
 static u_char doc2000_read_byte(struct mtd_info *mtd)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 	void __iomem *docptr = doc->virtadr;
 	u_char ret;
@@ -322,7 +322,7 @@ static u_char doc2000_read_byte(struct mtd_info *mtd)
 
 static void doc2000_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 	void __iomem *docptr = doc->virtadr;
 	int i;
@@ -339,7 +339,7 @@ static void doc2000_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
 
 static void doc2000_readbuf(struct mtd_info *mtd, u_char *buf, int len)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 	void __iomem *docptr = doc->virtadr;
 	int i;
@@ -354,7 +354,7 @@ static void doc2000_readbuf(struct mtd_info *mtd, u_char *buf, int len)
 
 static void doc2000_readbuf_dword(struct mtd_info *mtd, u_char *buf, int len)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 	void __iomem *docptr = doc->virtadr;
 	int i;
@@ -375,7 +375,7 @@ static void doc2000_readbuf_dword(struct mtd_info *mtd, u_char *buf, int len)
 
 static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 	uint16_t ret;
 
@@ -421,7 +421,7 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
 
 static void __init doc2000_count_chips(struct mtd_info *mtd)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 	uint16_t mfrid;
 	int i;
@@ -457,7 +457,7 @@ static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this)
 
 static void doc2001_write_byte(struct mtd_info *mtd, u_char datum)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 	void __iomem *docptr = doc->virtadr;
 
@@ -468,7 +468,7 @@ static void doc2001_write_byte(struct mtd_info *mtd, u_char datum)
 
 static u_char doc2001_read_byte(struct mtd_info *mtd)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 	void __iomem *docptr = doc->virtadr;
 
@@ -482,7 +482,7 @@ static u_char doc2001_read_byte(struct mtd_info *mtd)
 
 static void doc2001_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 	void __iomem *docptr = doc->virtadr;
 	int i;
@@ -495,7 +495,7 @@ static void doc2001_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
 
 static void doc2001_readbuf(struct mtd_info *mtd, u_char *buf, int len)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 	void __iomem *docptr = doc->virtadr;
 	int i;
@@ -512,7 +512,7 @@ static void doc2001_readbuf(struct mtd_info *mtd, u_char *buf, int len)
 
 static u_char doc2001plus_read_byte(struct mtd_info *mtd)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 	void __iomem *docptr = doc->virtadr;
 	u_char ret;
@@ -527,7 +527,7 @@ static u_char doc2001plus_read_byte(struct mtd_info *mtd)
 
 static void doc2001plus_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 	void __iomem *docptr = doc->virtadr;
 	int i;
@@ -545,7 +545,7 @@ static void doc2001plus_writebuf(struct mtd_info *mtd, const u_char *buf, int le
 
 static void doc2001plus_readbuf(struct mtd_info *mtd, u_char *buf, int len)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 	void __iomem *docptr = doc->virtadr;
 	int i;
@@ -576,7 +576,7 @@ static void doc2001plus_readbuf(struct mtd_info *mtd, u_char *buf, int len)
 
 static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 	void __iomem *docptr = doc->virtadr;
 	int floor = 0;
@@ -603,7 +603,7 @@ static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
 
 static void doc200x_select_chip(struct mtd_info *mtd, int chip)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 	void __iomem *docptr = doc->virtadr;
 	int floor = 0;
@@ -634,7 +634,7 @@ static void doc200x_select_chip(struct mtd_info *mtd, int chip)
 static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
 			      unsigned int ctrl)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 	void __iomem *docptr = doc->virtadr;
 
@@ -657,7 +657,7 @@ static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
 
 static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 	void __iomem *docptr = doc->virtadr;
 
@@ -763,7 +763,7 @@ static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int colu
 
 static int doc200x_dev_ready(struct mtd_info *mtd)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 	void __iomem *docptr = doc->virtadr;
 
@@ -803,7 +803,7 @@ static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs)
 
 static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 	void __iomem *docptr = doc->virtadr;
 
@@ -822,7 +822,7 @@ static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode)
 
 static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 	void __iomem *docptr = doc->virtadr;
 
@@ -842,7 +842,7 @@ static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode)
 /* This code is only called on write */
 static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, unsigned char *ecc_code)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 	void __iomem *docptr = doc->virtadr;
 	int i;
@@ -903,7 +903,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,
 				u_char *read_ecc, u_char *isnull)
 {
 	int i, ret = 0;
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 	void __iomem *docptr = doc->virtadr;
 	uint8_t calc_ecc[6];
@@ -1004,7 +1004,7 @@ static const struct mtd_ooblayout_ops doc200x_ooblayout_ops = {
    mh1_page in the DOC private structure. */
 static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const char *id, int findmirror)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 	unsigned offs;
 	int ret;
@@ -1047,7 +1047,7 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const ch
 
 static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 	int ret = 0;
 	u_char *buf;
@@ -1149,7 +1149,7 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partitio
 /* This is a stripped-down copy of the code in inftlmount.c */
 static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 	int ret = 0;
 	u_char *buf;
@@ -1269,7 +1269,7 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partiti
 static int __init nftl_scan_bbt(struct mtd_info *mtd)
 {
 	int ret, numparts;
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 	struct mtd_partition parts[2];
 
@@ -1304,7 +1304,7 @@ static int __init nftl_scan_bbt(struct mtd_info *mtd)
 static int __init inftl_scan_bbt(struct mtd_info *mtd)
 {
 	int ret, numparts;
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 	struct mtd_partition parts[5];
 
@@ -1357,7 +1357,7 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd)
 
 static inline int __init doc2000_init(struct mtd_info *mtd)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 
 	this->read_byte = doc2000_read_byte;
@@ -1373,7 +1373,7 @@ static inline int __init doc2000_init(struct mtd_info *mtd)
 
 static inline int __init doc2001_init(struct mtd_info *mtd)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 
 	this->read_byte = doc2001_read_byte;
@@ -1403,7 +1403,7 @@ static inline int __init doc2001_init(struct mtd_info *mtd)
 
 static inline int __init doc2001plus_init(struct mtd_info *mtd)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct doc_priv *doc = nand_get_controller_data(this);
 
 	this->read_byte = doc2001plus_read_byte;
@@ -1520,7 +1520,7 @@ static int __init doc_probe(unsigned long physadr)
 	for (mtd = doclist; mtd; mtd = doc->nextdoc) {
 		unsigned char oldval;
 		unsigned char newval;
-		nand = mtd_to_nand(mtd);
+		nand = mtd_to_nandc(mtd);
 		doc = nand_get_controller_data(nand);
 		/* Use the alias resolution register to determine if this is
 		   in fact the same DOC aliased to a new address.  If writes
@@ -1561,7 +1561,7 @@ static int __init doc_probe(unsigned long physadr)
 		goto fail;
 	}
 
-	mtd			= nand_to_mtd(nand);
+	mtd			= nandc_to_mtd(nand);
 	doc			= (struct doc_priv *) (nand + 1);
 	nand->bbt_td		= (struct nand_bbt_descr *) (doc + 1);
 	nand->bbt_md		= nand->bbt_td + 1;
@@ -1640,7 +1640,7 @@ static void release_nanddoc(void)
 	struct doc_priv *doc;
 
 	for (mtd = doclist; mtd; mtd = nextmtd) {
-		nand = mtd_to_nand(mtd);
+		nand = mtd_to_nandc(mtd);
 		doc = nand_get_controller_data(nand);
 
 		nextmtd = doc->nextdoc;
diff --git a/drivers/mtd/nand/raw/docg4.c b/drivers/mtd/nand/raw/docg4.c
index e038130b7206..dd8e55633d75 100644
--- a/drivers/mtd/nand/raw/docg4.c
+++ b/drivers/mtd/nand/raw/docg4.c
@@ -264,7 +264,7 @@ static inline void write_nop(void __iomem *docptr)
 static void docg4_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 {
 	int i;
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	uint16_t *p = (uint16_t *) buf;
 	len >>= 1;
 
@@ -275,7 +275,7 @@ static void docg4_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 static void docg4_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
 {
 	int i;
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	uint16_t *p = (uint16_t *) buf;
 	len >>= 1;
 
@@ -340,7 +340,7 @@ static void docg4_select_chip(struct mtd_info *mtd, int chip)
 	 * Select among multiple cascaded chips ("floors").  Multiple floors are
 	 * not yet supported, so the only valid non-negative value is 0.
 	 */
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct docg4_priv *doc = nand_get_controller_data(nand);
 	void __iomem *docptr = doc->virtadr;
 
@@ -359,7 +359,7 @@ static void reset(struct mtd_info *mtd)
 {
 	/* full device reset */
 
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct docg4_priv *doc = nand_get_controller_data(nand);
 	void __iomem *docptr = doc->virtadr;
 
@@ -397,7 +397,7 @@ static int correct_data(struct mtd_info *mtd, uint8_t *buf, int page)
 	 * Up to four bitflips can be corrected.
 	 */
 
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct docg4_priv *doc = nand_get_controller_data(nand);
 	void __iomem *docptr = doc->virtadr;
 	int i, numerrs, errpos[4];
@@ -486,7 +486,7 @@ static int correct_data(struct mtd_info *mtd, uint8_t *buf, int page)
 
 static uint8_t docg4_read_byte(struct mtd_info *mtd)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct docg4_priv *doc = nand_get_controller_data(nand);
 
 	dev_dbg(doc->dev, "%s\n", __func__);
@@ -567,7 +567,7 @@ static int pageprog(struct mtd_info *mtd)
 	 * internal buffer out to the flash array, or some such.
 	 */
 
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct docg4_priv *doc = nand_get_controller_data(nand);
 	void __iomem *docptr = doc->virtadr;
 	int retval = 0;
@@ -604,7 +604,7 @@ static void sequence_reset(struct mtd_info *mtd)
 {
 	/* common starting sequence for all operations */
 
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct docg4_priv *doc = nand_get_controller_data(nand);
 	void __iomem *docptr = doc->virtadr;
 
@@ -621,7 +621,7 @@ static void read_page_prologue(struct mtd_info *mtd, uint32_t docg4_addr)
 {
 	/* first step in reading a page */
 
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct docg4_priv *doc = nand_get_controller_data(nand);
 	void __iomem *docptr = doc->virtadr;
 
@@ -648,7 +648,7 @@ static void write_page_prologue(struct mtd_info *mtd, uint32_t docg4_addr)
 {
 	/* first step in writing a page */
 
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct docg4_priv *doc = nand_get_controller_data(nand);
 	void __iomem *docptr = doc->virtadr;
 
@@ -713,7 +713,7 @@ static void docg4_command(struct mtd_info *mtd, unsigned command, int column,
 {
 	/* handle standard nand commands */
 
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct docg4_priv *doc = nand_get_controller_data(nand);
 	uint32_t g4_addr = mtd_to_docg4_address(page_addr, column);
 
@@ -896,7 +896,7 @@ static int docg4_read_oob(struct mtd_info *mtd, struct nand_chip *nand,
 
 static int docg4_erase_block(struct mtd_info *mtd, int page)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct docg4_priv *doc = nand_get_controller_data(nand);
 	void __iomem *docptr = doc->virtadr;
 	uint16_t g4_page;
@@ -1038,7 +1038,7 @@ static int __init read_factory_bbt(struct mtd_info *mtd)
 	 * update the memory-based bbt accordingly.
 	 */
 
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct docg4_priv *doc = nand_get_controller_data(nand);
 	uint32_t g4_addr = mtd_to_docg4_address(DOCG4_FACTORY_BBT_PAGE, 0);
 	uint8_t *buf;
@@ -1111,7 +1111,7 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
 
 	int ret, i;
 	uint8_t *buf;
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct docg4_priv *doc = nand_get_controller_data(nand);
 	struct nand_bbt_descr *bbtd = nand->badblock_pattern;
 	int page = (int)(ofs >> nand->page_shift);
@@ -1224,7 +1224,7 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
 	 * things as well, such as call nand_set_defaults().
 	 */
 
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct docg4_priv *doc = nand_get_controller_data(nand);
 
 	mtd->size = DOCG4_CHIP_SIZE;
@@ -1282,7 +1282,7 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
 
 static int __init read_id_reg(struct mtd_info *mtd)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct docg4_priv *doc = nand_get_controller_data(nand);
 	void __iomem *docptr = doc->virtadr;
 	uint16_t id1, id2;
@@ -1333,7 +1333,7 @@ static int __init probe_docg4(struct platform_device *pdev)
 		goto fail_unmap;
 	}
 
-	mtd = nand_to_mtd(nand);
+	mtd = nandc_to_mtd(nand);
 	doc = (struct docg4_priv *) (nand + 1);
 	nand_set_controller_data(nand, doc);
 	mtd->dev.parent = &pdev->dev;
@@ -1389,7 +1389,7 @@ static int __exit cleanup_docg4(struct platform_device *pdev)
 	struct docg4_priv *doc = platform_get_drvdata(pdev);
 	nand_release(doc->mtd);
 	free_bch(doc->bch);
-	kfree(mtd_to_nand(doc->mtd));
+	kfree(mtd_to_nandc(doc->mtd));
 	iounmap(doc->virtadr);
 	return 0;
 }
diff --git a/drivers/mtd/nand/raw/fsl_elbc_nand.c b/drivers/mtd/nand/raw/fsl_elbc_nand.c
index 7d8453eb4d0f..6e215ac48b32 100644
--- a/drivers/mtd/nand/raw/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/raw/fsl_elbc_nand.c
@@ -82,7 +82,7 @@ struct fsl_elbc_fcm_ctrl {
 static int fsl_elbc_ooblayout_ecc(struct mtd_info *mtd, int section,
 				  struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
 
 	if (section >= chip->ecc.steps)
@@ -100,7 +100,7 @@ static int fsl_elbc_ooblayout_ecc(struct mtd_info *mtd, int section,
 static int fsl_elbc_ooblayout_free(struct mtd_info *mtd, int section,
 				   struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
 
 	if (section > chip->ecc.steps)
@@ -164,7 +164,7 @@ static struct nand_bbt_descr bbt_mirror_descr = {
  */
 static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
 	struct fsl_lbc_ctrl *ctrl = priv->ctrl;
 	struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
@@ -215,7 +215,7 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
  */
 static int fsl_elbc_run_command(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
 	struct fsl_lbc_ctrl *ctrl = priv->ctrl;
 	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
@@ -320,7 +320,7 @@ static void fsl_elbc_do_read(struct nand_chip *chip, int oob)
 static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
                              int column, int page_addr)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
 	struct fsl_lbc_ctrl *ctrl = priv->ctrl;
 	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
@@ -545,7 +545,7 @@ static void fsl_elbc_select_chip(struct mtd_info *mtd, int chip)
  */
 static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
 	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
 	unsigned int bufsize = mtd->writesize + mtd->oobsize;
@@ -583,7 +583,7 @@ static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
  */
 static u8 fsl_elbc_read_byte(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
 	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
 
@@ -600,7 +600,7 @@ static u8 fsl_elbc_read_byte(struct mtd_info *mtd)
  */
 static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
 	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
 	int avail;
@@ -639,7 +639,7 @@ static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
 
 static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
 	struct fsl_lbc_ctrl *ctrl = priv->ctrl;
 	struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
@@ -754,7 +754,7 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
 	struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
 	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
 	struct nand_chip *chip = &priv->chip;
-	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct mtd_info *mtd = nandc_to_mtd(chip);
 
 	dev_dbg(priv->dev, "eLBC Set Information for bank %d\n", priv->bank);
 
@@ -809,7 +809,7 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
 static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv)
 {
 	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
-	struct mtd_info *mtd = nand_to_mtd(&priv->chip);
+	struct mtd_info *mtd = nandc_to_mtd(&priv->chip);
 
 	nand_release(mtd);
 
@@ -899,9 +899,9 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
 		goto err;
 	}
 
-	mtd = nand_to_mtd(&priv->chip);
+	mtd = nandc_to_mtd(&priv->chip);
 	mtd->name = kasprintf(GFP_KERNEL, "%llx.flash", (u64)res.start);
-	if (!nand_to_mtd(&priv->chip)->name) {
+	if (!nandc_to_mtd(&priv->chip)->name) {
 		ret = -ENOMEM;
 		goto err;
 	}
diff --git a/drivers/mtd/nand/raw/fsl_ifc_nand.c b/drivers/mtd/nand/raw/fsl_ifc_nand.c
index bcf7f0b8abf9..0aa970045bbe 100644
--- a/drivers/mtd/nand/raw/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/raw/fsl_ifc_nand.c
@@ -96,7 +96,7 @@ static struct nand_bbt_descr bbt_mirror_descr = {
 static int fsl_ifc_ooblayout_ecc(struct mtd_info *mtd, int section,
 				 struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	if (section)
 		return -ERANGE;
@@ -110,7 +110,7 @@ static int fsl_ifc_ooblayout_ecc(struct mtd_info *mtd, int section,
 static int fsl_ifc_ooblayout_free(struct mtd_info *mtd, int section,
 				  struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	if (section > 1)
 		return -ERANGE;
@@ -150,7 +150,7 @@ static const struct mtd_ooblayout_ops fsl_ifc_ooblayout_ops = {
  */
 static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
 	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
 	struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
@@ -173,7 +173,7 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
 
 static int is_blank(struct mtd_info *mtd, unsigned int bufnum)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
 	u8 __iomem *addr = priv->vbase + bufnum * (mtd->writesize * 2);
 	u32 __iomem *mainarea = (u32 __iomem *)addr;
@@ -216,7 +216,7 @@ static int check_read_ecc(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl,
  */
 static void fsl_ifc_run_command(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
 	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
 	struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl;
@@ -333,7 +333,7 @@ static void fsl_ifc_do_read(struct nand_chip *chip,
 /* cmdfunc send commands to the IFC NAND Machine */
 static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
 			     int column, int page_addr) {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
 	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
 	struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
@@ -548,7 +548,7 @@ static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip)
  */
 static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
 	unsigned int bufsize = mtd->writesize + mtd->oobsize;
 
@@ -574,7 +574,7 @@ static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
  */
 static uint8_t fsl_ifc_read_byte(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
 	unsigned int offset;
 
@@ -597,7 +597,7 @@ static uint8_t fsl_ifc_read_byte(struct mtd_info *mtd)
  */
 static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
 	uint16_t data;
 
@@ -620,7 +620,7 @@ static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd)
  */
 static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
 	int avail;
 
@@ -706,7 +706,7 @@ static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 
 static int fsl_ifc_chip_init_tail(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
 
 	dev_dbg(priv->dev, "%s: nand->numchips = %d\n", __func__,
@@ -805,7 +805,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
 	struct fsl_ifc_global __iomem *ifc_global = ctrl->gregs;
 	struct fsl_ifc_runtime __iomem *ifc_runtime = ctrl->rregs;
 	struct nand_chip *chip = &priv->chip;
-	struct mtd_info *mtd = nand_to_mtd(&priv->chip);
+	struct mtd_info *mtd = nandc_to_mtd(&priv->chip);
 	u32 csor;
 
 	/* Fill in fsl_ifc_mtd structure */
@@ -906,7 +906,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
 
 static int fsl_ifc_chip_remove(struct fsl_ifc_mtd *priv)
 {
-	struct mtd_info *mtd = nand_to_mtd(&priv->chip);
+	struct mtd_info *mtd = nandc_to_mtd(&priv->chip);
 
 	nand_release(mtd);
 
@@ -1018,7 +1018,7 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
 		  IFC_NAND_EVTER_INTR_WPERIR_EN,
 		  &ifc->ifc_nand.nand_evter_intr_en);
 
-	mtd = nand_to_mtd(&priv->chip);
+	mtd = nandc_to_mtd(&priv->chip);
 	mtd->name = kasprintf(GFP_KERNEL, "%llx.flash", (u64)res.start);
 	if (!mtd->name) {
 		ret = -ENOMEM;
diff --git a/drivers/mtd/nand/raw/fsl_upm.c b/drivers/mtd/nand/raw/fsl_upm.c
index a88e2cf66e0f..23c513348f46 100644
--- a/drivers/mtd/nand/raw/fsl_upm.c
+++ b/drivers/mtd/nand/raw/fsl_upm.c
@@ -48,7 +48,7 @@ struct fsl_upm_nand {
 
 static inline struct fsl_upm_nand *to_fsl_upm_nand(struct mtd_info *mtdinfo)
 {
-	return container_of(mtd_to_nand(mtdinfo), struct fsl_upm_nand,
+	return container_of(mtd_to_nandc(mtdinfo), struct fsl_upm_nand,
 			    chip);
 }
 
@@ -66,7 +66,7 @@ static int fun_chip_ready(struct mtd_info *mtd)
 static void fun_wait_rnb(struct fsl_upm_nand *fun)
 {
 	if (fun->rnb_gpio[fun->mchip_number] >= 0) {
-		struct mtd_info *mtd = nand_to_mtd(&fun->chip);
+		struct mtd_info *mtd = nandc_to_mtd(&fun->chip);
 		int cnt = 1000000;
 
 		while (--cnt && !fun_chip_ready(mtd))
@@ -80,7 +80,7 @@ static void fun_wait_rnb(struct fsl_upm_nand *fun)
 
 static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
 	u32 mar;
 
@@ -110,7 +110,7 @@ static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
 
 static void fun_select_chip(struct mtd_info *mtd, int mchip_nr)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
 
 	if (mchip_nr == -1) {
@@ -158,7 +158,7 @@ static int fun_chip_init(struct fsl_upm_nand *fun,
 			 const struct device_node *upm_np,
 			 const struct resource *io_res)
 {
-	struct mtd_info *mtd = nand_to_mtd(&fun->chip);
+	struct mtd_info *mtd = nandc_to_mtd(&fun->chip);
 	int ret;
 	struct device_node *flash_np;
 
@@ -323,7 +323,7 @@ static int fun_probe(struct platform_device *ofdev)
 static int fun_remove(struct platform_device *ofdev)
 {
 	struct fsl_upm_nand *fun = dev_get_drvdata(&ofdev->dev);
-	struct mtd_info *mtd = nand_to_mtd(&fun->chip);
+	struct mtd_info *mtd = nandc_to_mtd(&fun->chip);
 	int i;
 
 	nand_release(mtd);
diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c
index 5c08694aa153..e63d54468205 100644
--- a/drivers/mtd/nand/raw/fsmc_nand.c
+++ b/drivers/mtd/nand/raw/fsmc_nand.c
@@ -42,7 +42,7 @@
 static int fsmc_ecc1_ooblayout_ecc(struct mtd_info *mtd, int section,
 				   struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	if (section >= chip->ecc.steps)
 		return -ERANGE;
@@ -56,7 +56,7 @@ static int fsmc_ecc1_ooblayout_ecc(struct mtd_info *mtd, int section,
 static int fsmc_ecc1_ooblayout_free(struct mtd_info *mtd, int section,
 				    struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	if (section >= chip->ecc.steps)
 		return -ERANGE;
@@ -85,7 +85,7 @@ static const struct mtd_ooblayout_ops fsmc_ecc1_ooblayout_ops = {
 static int fsmc_ecc4_ooblayout_ecc(struct mtd_info *mtd, int section,
 				   struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	if (section >= chip->ecc.steps)
 		return -ERANGE;
@@ -103,7 +103,7 @@ static int fsmc_ecc4_ooblayout_ecc(struct mtd_info *mtd, int section,
 static int fsmc_ecc4_ooblayout_free(struct mtd_info *mtd, int section,
 				    struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	if (section >= chip->ecc.steps)
 		return -ERANGE;
@@ -174,13 +174,13 @@ struct fsmc_nand_data {
 
 static inline struct fsmc_nand_data *mtd_to_fsmc(struct mtd_info *mtd)
 {
-	return container_of(mtd_to_nand(mtd), struct fsmc_nand_data, nand);
+	return container_of(mtd_to_nandc(mtd), struct fsmc_nand_data, nand);
 }
 
 /* Assert CS signal based on chipnr */
 static void fsmc_select_chip(struct mtd_info *mtd, int chipnr)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct fsmc_nand_data *host;
 
 	host = mtd_to_fsmc(mtd);
@@ -209,7 +209,7 @@ static void fsmc_select_chip(struct mtd_info *mtd, int chipnr)
  */
 static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
 	void __iomem *regs = host->regs_va;
 	unsigned int bank = host->bank;
@@ -476,7 +476,7 @@ static int dma_xfer(struct fsmc_nand_data *host, void *buffer, int len,
 static void fsmc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 {
 	int i;
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	if (IS_ALIGNED((uint32_t)buf, sizeof(uint32_t)) &&
 			IS_ALIGNED(len, sizeof(uint32_t))) {
@@ -499,7 +499,7 @@ static void fsmc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 static void fsmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 {
 	int i;
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	if (IS_ALIGNED((uint32_t)buf, sizeof(uint32_t)) &&
 			IS_ALIGNED(len, sizeof(uint32_t))) {
@@ -630,7 +630,7 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
 static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat,
 			     uint8_t *read_ecc, uint8_t *calc_ecc)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
 	void __iomem *regs = host->regs_va;
 	unsigned int bank = host->bank;
@@ -858,7 +858,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
 		init_completion(&host->dma_access_complete);
 
 	/* Link all private pointers */
-	mtd = nand_to_mtd(&host->nand);
+	mtd = nandc_to_mtd(&host->nand);
 	nand = &host->nand;
 	nand_set_controller_data(nand, host);
 	nand_set_flash_node(nand, np);
@@ -1038,7 +1038,7 @@ static int fsmc_nand_remove(struct platform_device *pdev)
 	struct fsmc_nand_data *host = platform_get_drvdata(pdev);
 
 	if (host) {
-		nand_release(nand_to_mtd(&host->nand));
+		nand_release(nandc_to_mtd(&host->nand));
 
 		if (host->mode == USE_DMA_ACCESS) {
 			dma_release_channel(host->write_dma_chan);
diff --git a/drivers/mtd/nand/raw/gpio.c b/drivers/mtd/nand/raw/gpio.c
index 21b19efe1ac7..0016a27b2fdb 100644
--- a/drivers/mtd/nand/raw/gpio.c
+++ b/drivers/mtd/nand/raw/gpio.c
@@ -41,7 +41,7 @@ struct gpiomtd {
 
 static inline struct gpiomtd *gpio_nand_getpriv(struct mtd_info *mtd)
 {
-	return container_of(mtd_to_nand(mtd), struct gpiomtd, nand_chip);
+	return container_of(mtd_to_nandc(mtd), struct gpiomtd, nand_chip);
 }
 
 
@@ -197,7 +197,7 @@ static int gpio_nand_remove(struct platform_device *pdev)
 {
 	struct gpiomtd *gpiomtd = platform_get_drvdata(pdev);
 
-	nand_release(nand_to_mtd(&gpiomtd->nand_chip));
+	nand_release(nandc_to_mtd(&gpiomtd->nand_chip));
 
 	if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
 		gpio_set_value(gpiomtd->plat.gpio_nwp, 0);
@@ -278,7 +278,7 @@ static int gpio_nand_probe(struct platform_device *pdev)
 	chip->chip_delay	= gpiomtd->plat.chip_delay;
 	chip->cmd_ctrl		= gpio_nand_cmd_ctrl;
 
-	mtd			= nand_to_mtd(chip);
+	mtd			= nandc_to_mtd(chip);
 	mtd->dev.parent		= &pdev->dev;
 
 	platform_set_drvdata(pdev, gpiomtd);
diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c
index 0f68a99fc4ad..bf37661e7368 100644
--- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c
+++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c
@@ -919,7 +919,7 @@ static int enable_edo_mode(struct gpmi_nand_data *this, int mode)
 {
 	struct resources  *r = &this->resources;
 	struct nand_chip *nand = &this->nand;
-	struct mtd_info	 *mtd = nand_to_mtd(nand);
+	struct mtd_info	 *mtd = nandc_to_mtd(nand);
 	uint8_t *feature;
 	unsigned long rate;
 	int ret;
diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
index 6c062b8251d2..c1ec57327ff5 100644
--- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
@@ -49,7 +49,7 @@ static struct nand_bbt_descr gpmi_bbt_descr = {
 static int gpmi_ooblayout_ecc(struct mtd_info *mtd, int section,
 			      struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct gpmi_nand_data *this = nand_get_controller_data(chip);
 	struct bch_geometry *geo = &this->bch_geometry;
 
@@ -65,7 +65,7 @@ static int gpmi_ooblayout_ecc(struct mtd_info *mtd, int section,
 static int gpmi_ooblayout_free(struct mtd_info *mtd, int section,
 			       struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct gpmi_nand_data *this = nand_get_controller_data(chip);
 	struct bch_geometry *geo = &this->bch_geometry;
 
@@ -140,7 +140,7 @@ static irqreturn_t bch_irq(int irq, void *cookie)
 static inline int get_ecc_strength(struct gpmi_nand_data *this)
 {
 	struct bch_geometry *geo = &this->bch_geometry;
-	struct mtd_info	*mtd = nand_to_mtd(&this->nand);
+	struct mtd_info	*mtd = nandc_to_mtd(&this->nand);
 	int ecc_strength;
 
 	ecc_strength = ((mtd->oobsize - geo->metadata_size) * 8)
@@ -173,7 +173,7 @@ static int set_geometry_by_ecc_info(struct gpmi_nand_data *this)
 {
 	struct bch_geometry *geo = &this->bch_geometry;
 	struct nand_chip *chip = &this->nand;
-	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct mtd_info *mtd = nandc_to_mtd(chip);
 	unsigned int block_mark_bit_offset;
 
 	if (!(chip->ecc_strength_ds > 0 && chip->ecc_step_ds > 0))
@@ -283,7 +283,7 @@ static int set_geometry_by_ecc_info(struct gpmi_nand_data *this)
 static int legacy_set_geometry(struct gpmi_nand_data *this)
 {
 	struct bch_geometry *geo = &this->bch_geometry;
-	struct mtd_info *mtd = nand_to_mtd(&this->nand);
+	struct mtd_info *mtd = nandc_to_mtd(&this->nand);
 	unsigned int metadata_size;
 	unsigned int status_size;
 	unsigned int block_mark_bit_offset;
@@ -834,7 +834,7 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this)
 {
 	struct bch_geometry *geo = &this->bch_geometry;
 	struct device *dev = this->dev;
-	struct mtd_info *mtd = nand_to_mtd(&this->nand);
+	struct mtd_info *mtd = nandc_to_mtd(&this->nand);
 
 	/* [1] Allocate a command buffer. PAGE_SIZE is enough. */
 	this->cmd_buffer = kzalloc(PAGE_SIZE, GFP_DMA | GFP_KERNEL);
@@ -886,7 +886,7 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this)
 
 static void gpmi_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct gpmi_nand_data *this = nand_get_controller_data(chip);
 	int ret;
 
@@ -920,7 +920,7 @@ static void gpmi_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl)
 
 static int gpmi_dev_ready(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct gpmi_nand_data *this = nand_get_controller_data(chip);
 
 	return gpmi_is_ready(this, this->current_chip);
@@ -928,7 +928,7 @@ static int gpmi_dev_ready(struct mtd_info *mtd)
 
 static void gpmi_select_chip(struct mtd_info *mtd, int chipnr)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct gpmi_nand_data *this = nand_get_controller_data(chip);
 
 	if ((this->current_chip < 0) && (chipnr >= 0))
@@ -941,7 +941,7 @@ static void gpmi_select_chip(struct mtd_info *mtd, int chipnr)
 
 static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct gpmi_nand_data *this = nand_get_controller_data(chip);
 
 	dev_dbg(this->dev, "len is %d\n", len);
@@ -953,7 +953,7 @@ static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 
 static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct gpmi_nand_data *this = nand_get_controller_data(chip);
 
 	dev_dbg(this->dev, "len is %d\n", len);
@@ -965,7 +965,7 @@ static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 
 static uint8_t gpmi_read_byte(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct gpmi_nand_data *this = nand_get_controller_data(chip);
 	uint8_t *buf = this->data_buffer_dma;
 
@@ -1637,7 +1637,7 @@ static int gpmi_ecc_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
 
 static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct gpmi_nand_data *this = nand_get_controller_data(chip);
 	int ret = 0;
 	uint8_t *block_mark;
@@ -1700,7 +1700,7 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
 	struct boot_rom_geometry *rom_geo = &this->rom_geometry;
 	struct device *dev = this->dev;
 	struct nand_chip *chip = &this->nand;
-	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct mtd_info *mtd = nandc_to_mtd(chip);
 	unsigned int search_area_size_in_strides;
 	unsigned int stride;
 	unsigned int page;
@@ -1755,7 +1755,7 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
 	struct device *dev = this->dev;
 	struct boot_rom_geometry *rom_geo = &this->rom_geometry;
 	struct nand_chip *chip = &this->nand;
-	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct mtd_info *mtd = nandc_to_mtd(chip);
 	unsigned int block_size_in_pages;
 	unsigned int search_area_size_in_strides;
 	unsigned int search_area_size_in_pages;
@@ -1834,7 +1834,7 @@ static int mx23_boot_init(struct gpmi_nand_data  *this)
 {
 	struct device *dev = this->dev;
 	struct nand_chip *chip = &this->nand;
-	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct mtd_info *mtd = nandc_to_mtd(chip);
 	unsigned int block_count;
 	unsigned int block;
 	int     chipnr;
@@ -1930,14 +1930,14 @@ static int gpmi_set_geometry(struct gpmi_nand_data *this)
 
 static void gpmi_nand_exit(struct gpmi_nand_data *this)
 {
-	nand_release(nand_to_mtd(&this->nand));
+	nand_release(nandc_to_mtd(&this->nand));
 	gpmi_free_dma_buffer(this);
 }
 
 static int gpmi_init_last(struct gpmi_nand_data *this)
 {
 	struct nand_chip *chip = &this->nand;
-	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct mtd_info *mtd = nandc_to_mtd(chip);
 	struct nand_ecc_ctrl *ecc = &chip->ecc;
 	struct bch_geometry *bch_geo = &this->bch_geometry;
 	int ret;
@@ -1986,7 +1986,7 @@ static int gpmi_init_last(struct gpmi_nand_data *this)
 static int gpmi_nand_init(struct gpmi_nand_data *this)
 {
 	struct nand_chip *chip = &this->nand;
-	struct mtd_info  *mtd = nand_to_mtd(chip);
+	struct mtd_info  *mtd = nandc_to_mtd(chip);
 	int ret;
 
 	/* init current chip */
diff --git a/drivers/mtd/nand/raw/hisi504_nand.c b/drivers/mtd/nand/raw/hisi504_nand.c
index a287d73bb17e..81a941c8a20b 100644
--- a/drivers/mtd/nand/raw/hisi504_nand.c
+++ b/drivers/mtd/nand/raw/hisi504_nand.c
@@ -188,7 +188,7 @@ static void wait_controller_finished(struct hinfc_host *host)
 static void hisi_nfc_dma_transfer(struct hinfc_host *host, int todev)
 {
 	struct nand_chip *chip = &host->chip;
-	struct mtd_info	*mtd = nand_to_mtd(chip);
+	struct mtd_info	*mtd = nandc_to_mtd(chip);
 	unsigned long val;
 	int ret;
 
@@ -260,7 +260,7 @@ static int hisi_nfc_send_cmd_pageprog(struct hinfc_host *host)
 
 static int hisi_nfc_send_cmd_readstart(struct hinfc_host *host)
 {
-	struct mtd_info	*mtd = nand_to_mtd(&host->chip);
+	struct mtd_info	*mtd = nandc_to_mtd(&host->chip);
 
 	if ((host->addr_value[0] == host->cache_addr_value[0]) &&
 	    (host->addr_value[1] == host->cache_addr_value[1]))
@@ -355,7 +355,7 @@ static int hisi_nfc_send_cmd_reset(struct hinfc_host *host, int chipselect)
 
 static void hisi_nfc_select_chip(struct mtd_info *mtd, int chipselect)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct hinfc_host *host = nand_get_controller_data(chip);
 
 	if (chipselect < 0)
@@ -366,7 +366,7 @@ static void hisi_nfc_select_chip(struct mtd_info *mtd, int chipselect)
 
 static uint8_t hisi_nfc_read_byte(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct hinfc_host *host = nand_get_controller_data(chip);
 
 	if (host->command == NAND_CMD_STATUS)
@@ -382,7 +382,7 @@ static uint8_t hisi_nfc_read_byte(struct mtd_info *mtd)
 
 static u16 hisi_nfc_read_word(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct hinfc_host *host = nand_get_controller_data(chip);
 
 	host->offset += 2;
@@ -392,7 +392,7 @@ static u16 hisi_nfc_read_word(struct mtd_info *mtd)
 static void
 hisi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct hinfc_host *host = nand_get_controller_data(chip);
 
 	memcpy(host->buffer + host->offset, buf, len);
@@ -401,7 +401,7 @@ hisi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 
 static void hisi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct hinfc_host *host = nand_get_controller_data(chip);
 
 	memcpy(buf, host->buffer + host->offset, len);
@@ -410,7 +410,7 @@ static void hisi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 
 static void set_addr(struct mtd_info *mtd, int column, int page_addr)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct hinfc_host *host = nand_get_controller_data(chip);
 	unsigned int command = host->command;
 
@@ -446,7 +446,7 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr)
 static void hisi_nfc_cmdfunc(struct mtd_info *mtd, unsigned command, int column,
 		int page_addr)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct hinfc_host *host = nand_get_controller_data(chip);
 	int is_cache_invalid = 1;
 	unsigned int flag = 0;
@@ -660,7 +660,7 @@ static int hisi_nfc_ecc_probe(struct hinfc_host *host)
 	int size, strength, ecc_bits;
 	struct device *dev = host->dev;
 	struct nand_chip *chip = &host->chip;
-	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct mtd_info *mtd = nandc_to_mtd(chip);
 
 	size = chip->ecc.size;
 	strength = chip->ecc.strength;
@@ -728,7 +728,7 @@ static int hisi_nfc_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, host);
 	chip = &host->chip;
-	mtd  = nand_to_mtd(chip);
+	mtd  = nandc_to_mtd(chip);
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
@@ -831,7 +831,7 @@ static int hisi_nfc_probe(struct platform_device *pdev)
 static int hisi_nfc_remove(struct platform_device *pdev)
 {
 	struct hinfc_host *host = platform_get_drvdata(pdev);
-	struct mtd_info *mtd = nand_to_mtd(&host->chip);
+	struct mtd_info *mtd = nandc_to_mtd(&host->chip);
 
 	nand_release(mtd);
 
diff --git a/drivers/mtd/nand/raw/jz4740_nand.c b/drivers/mtd/nand/raw/jz4740_nand.c
index e813ec11ee84..99fb8f47b508 100644
--- a/drivers/mtd/nand/raw/jz4740_nand.c
+++ b/drivers/mtd/nand/raw/jz4740_nand.c
@@ -75,13 +75,13 @@ struct jz_nand {
 
 static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd)
 {
-	return container_of(mtd_to_nand(mtd), struct jz_nand, chip);
+	return container_of(mtd_to_nandc(mtd), struct jz_nand, chip);
 }
 
 static void jz_nand_select_chip(struct mtd_info *mtd, int chipnr)
 {
 	struct jz_nand *nand = mtd_to_jz_nand(mtd);
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	uint32_t ctrl;
 	int banknr;
 
@@ -103,7 +103,7 @@ static void jz_nand_select_chip(struct mtd_info *mtd, int chipnr)
 static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
 {
 	struct jz_nand *nand = mtd_to_jz_nand(mtd);
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	uint32_t reg;
 	void __iomem *bank_base = nand->bank_base[nand->selected_bank];
 
@@ -315,7 +315,7 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
 	char res_name[6];
 	uint32_t ctrl;
 	struct nand_chip *chip = &nand->chip;
-	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct mtd_info *mtd = nandc_to_mtd(chip);
 
 	/* Request GPIO port. */
 	gpio = JZ_GPIO_MEM_CS0 + bank - 1;
@@ -413,7 +413,7 @@ static int jz_nand_probe(struct platform_device *pdev)
 	}
 
 	chip		= &nand->chip;
-	mtd		= nand_to_mtd(chip);
+	mtd		= nandc_to_mtd(chip);
 	mtd->dev.parent = &pdev->dev;
 	mtd->name	= "jz4740-nand";
 
@@ -520,7 +520,7 @@ static int jz_nand_remove(struct platform_device *pdev)
 	struct jz_nand *nand = platform_get_drvdata(pdev);
 	size_t i;
 
-	nand_release(nand_to_mtd(&nand->chip));
+	nand_release(nandc_to_mtd(&nand->chip));
 
 	/* Deassert and disable all chips */
 	writel(0, nand->base + JZ_REG_NAND_CTRL);
diff --git a/drivers/mtd/nand/raw/jz4780_nand.c b/drivers/mtd/nand/raw/jz4780_nand.c
index 2f725bd83de8..7db5da056939 100644
--- a/drivers/mtd/nand/raw/jz4780_nand.c
+++ b/drivers/mtd/nand/raw/jz4780_nand.c
@@ -62,7 +62,7 @@ struct jz4780_nand_chip {
 
 static inline struct jz4780_nand_chip *to_jz4780_nand_chip(struct mtd_info *mtd)
 {
-	return container_of(mtd_to_nand(mtd), struct jz4780_nand_chip, chip);
+	return container_of(mtd_to_nandc(mtd), struct jz4780_nand_chip, chip);
 }
 
 static inline struct jz4780_nand_controller *to_jz4780_nand_controller(struct nand_hw_control *ctrl)
@@ -160,7 +160,7 @@ static int jz4780_nand_ecc_correct(struct mtd_info *mtd, u8 *dat,
 static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *dev)
 {
 	struct nand_chip *chip = &nand->chip;
-	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct mtd_info *mtd = nandc_to_mtd(chip);
 	struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(chip->controller);
 	int eccbytes;
 
@@ -262,7 +262,7 @@ static int jz4780_nand_init_chip(struct platform_device *pdev,
 	}
 
 	chip = &nand->chip;
-	mtd = nand_to_mtd(chip);
+	mtd = nandc_to_mtd(chip);
 	mtd->name = devm_kasprintf(dev, GFP_KERNEL, "%s.%d", dev_name(dev),
 				   cs->bank);
 	if (!mtd->name)
@@ -308,7 +308,7 @@ static void jz4780_nand_cleanup_chips(struct jz4780_nand_controller *nfc)
 
 	while (!list_empty(&nfc->chips)) {
 		chip = list_first_entry(&nfc->chips, struct jz4780_nand_chip, chip_list);
-		nand_release(nand_to_mtd(&chip->chip));
+		nand_release(nandc_to_mtd(&chip->chip));
 		list_del(&chip->chip_list);
 	}
 }
diff --git a/drivers/mtd/nand/raw/lpc32xx_mlc.c b/drivers/mtd/nand/raw/lpc32xx_mlc.c
index b212bb0fd902..c7d66b565495 100644
--- a/drivers/mtd/nand/raw/lpc32xx_mlc.c
+++ b/drivers/mtd/nand/raw/lpc32xx_mlc.c
@@ -141,7 +141,7 @@ struct lpc32xx_nand_cfg_mlc {
 static int lpc32xx_ooblayout_ecc(struct mtd_info *mtd, int section,
 				 struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 
 	if (section >= nand_chip->ecc.steps)
 		return -ERANGE;
@@ -155,7 +155,7 @@ static int lpc32xx_ooblayout_ecc(struct mtd_info *mtd, int section,
 static int lpc32xx_ooblayout_free(struct mtd_info *mtd, int section,
 				  struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 
 	if (section >= nand_chip->ecc.steps)
 		return -ERANGE;
@@ -288,7 +288,7 @@ static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host)
 static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
 				  unsigned int ctrl)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct lpc32xx_nand_host *host = nand_get_controller_data(nand_chip);
 
 	if (cmd != NAND_CMD_NONE) {
@@ -304,7 +304,7 @@ static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
  */
 static int lpc32xx_nand_device_ready(struct mtd_info *mtd)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct lpc32xx_nand_host *host = nand_get_controller_data(nand_chip);
 
 	if ((readb(MLC_ISR(host->io_base)) &
@@ -402,7 +402,7 @@ static void lpc32xx_dma_complete_func(void *completion)
 static int lpc32xx_xmit_dma(struct mtd_info *mtd, void *mem, int len,
 			    enum dma_transfer_direction dir)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
 	struct dma_async_tx_descriptor *desc;
 	int flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
@@ -579,7 +579,7 @@ static void lpc32xx_ecc_enable(struct mtd_info *mtd, int mode)
 
 static int lpc32xx_dma_setup(struct lpc32xx_nand_host *host)
 {
-	struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
+	struct mtd_info *mtd = nandc_to_mtd(&host->nand_chip);
 	dma_cap_mask_t mask;
 
 	if (!host->pdata || !host->pdata->dma_filter) {
@@ -674,7 +674,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
 	host->io_base_phy = rc->start;
 
 	nand_chip = &host->nand_chip;
-	mtd = nand_to_mtd(nand_chip);
+	mtd = nandc_to_mtd(nand_chip);
 	if (pdev->dev.of_node)
 		host->ncfg = lpc32xx_parse_dt(&pdev->dev);
 	if (!host->ncfg) {
@@ -828,7 +828,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
 static int lpc32xx_nand_remove(struct platform_device *pdev)
 {
 	struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
-	struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
+	struct mtd_info *mtd = nandc_to_mtd(&host->nand_chip);
 
 	nand_release(mtd);
 	free_irq(host->irq, host);
diff --git a/drivers/mtd/nand/raw/lpc32xx_slc.c b/drivers/mtd/nand/raw/lpc32xx_slc.c
index 018d783d37cd..20520df33460 100644
--- a/drivers/mtd/nand/raw/lpc32xx_slc.c
+++ b/drivers/mtd/nand/raw/lpc32xx_slc.c
@@ -282,7 +282,7 @@ static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
 	unsigned int ctrl)
 {
 	uint32_t tmp;
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
 
 	/* Does CE state need to be changed? */
@@ -306,7 +306,7 @@ static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
  */
 static int lpc32xx_nand_device_ready(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
 	int rdy = 0;
 
@@ -361,7 +361,7 @@ static int lpc32xx_nand_ecc_calculate(struct mtd_info *mtd,
  */
 static uint8_t lpc32xx_nand_read_byte(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
 
 	return (uint8_t)readl(SLC_DATA(host->io_base));
@@ -372,7 +372,7 @@ static uint8_t lpc32xx_nand_read_byte(struct mtd_info *mtd)
  */
 static void lpc32xx_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
 
 	/* Direct device read with no ECC */
@@ -385,7 +385,7 @@ static void lpc32xx_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
  */
 static void lpc32xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
 
 	/* Direct device write with no ECC */
@@ -450,7 +450,7 @@ static void lpc32xx_dma_complete_func(void *completion)
 static int lpc32xx_xmit_dma(struct mtd_info *mtd, dma_addr_t dma,
 			    void *mem, int len, enum dma_transfer_direction dir)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
 	struct dma_async_tx_descriptor *desc;
 	int flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
@@ -510,7 +510,7 @@ static int lpc32xx_xmit_dma(struct mtd_info *mtd, dma_addr_t dma,
 static int lpc32xx_xfer(struct mtd_info *mtd, uint8_t *buf, int eccsubpages,
 			int read)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
 	int i, status = 0;
 	unsigned long timeout;
@@ -736,7 +736,7 @@ static int lpc32xx_nand_write_page_raw_syndrome(struct mtd_info *mtd,
 
 static int lpc32xx_nand_dma_setup(struct lpc32xx_nand_host *host)
 {
-	struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
+	struct mtd_info *mtd = nandc_to_mtd(&host->nand_chip);
 	dma_cap_mask_t mask;
 
 	if (!host->pdata || !host->pdata->dma_filter) {
@@ -832,7 +832,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
 	host->pdata = dev_get_platdata(&pdev->dev);
 
 	chip = &host->nand_chip;
-	mtd = nand_to_mtd(chip);
+	mtd = nandc_to_mtd(chip);
 	nand_set_controller_data(chip, host);
 	nand_set_flash_node(chip, pdev->dev.of_node);
 	mtd->owner = THIS_MODULE;
@@ -959,7 +959,7 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
 {
 	uint32_t tmp;
 	struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
-	struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
+	struct mtd_info *mtd = nandc_to_mtd(&host->nand_chip);
 
 	nand_release(mtd);
 	dma_release_channel(host->dma_chan);
diff --git a/drivers/mtd/nand/raw/mpc5121_nfc.c b/drivers/mtd/nand/raw/mpc5121_nfc.c
index 2a1fa86fd123..40f5969ac098 100644
--- a/drivers/mtd/nand/raw/mpc5121_nfc.c
+++ b/drivers/mtd/nand/raw/mpc5121_nfc.c
@@ -134,7 +134,7 @@ static void mpc5121_nfc_done(struct mtd_info *mtd);
 /* Read NFC register */
 static inline u16 nfc_read(struct mtd_info *mtd, uint reg)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
 
 	return in_be16(prv->regs + reg);
@@ -143,7 +143,7 @@ static inline u16 nfc_read(struct mtd_info *mtd, uint reg)
 /* Write NFC register */
 static inline void nfc_write(struct mtd_info *mtd, uint reg, u16 val)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
 
 	out_be16(prv->regs + reg, val);
@@ -213,7 +213,7 @@ static inline void mpc5121_nfc_send_read_status(struct mtd_info *mtd)
 static irqreturn_t mpc5121_nfc_irq(int irq, void *data)
 {
 	struct mtd_info *mtd = data;
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
 
 	nfc_set(mtd, NFC_CONFIG1, NFC_INT_MASK);
@@ -225,7 +225,7 @@ static irqreturn_t mpc5121_nfc_irq(int irq, void *data)
 /* Wait for operation complete */
 static void mpc5121_nfc_done(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
 	int rv;
 
@@ -245,7 +245,7 @@ static void mpc5121_nfc_done(struct mtd_info *mtd)
 /* Do address cycle(s) */
 static void mpc5121_nfc_addr_cycle(struct mtd_info *mtd, int column, int page)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	u32 pagemask = chip->pagemask;
 
 	if (column != -1) {
@@ -280,7 +280,7 @@ static void mpc5121_nfc_select_chip(struct mtd_info *mtd, int chip)
 /* Init external chip select logic on ADS5121 board */
 static int ads5121_chipselect_init(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
 	struct device_node *dn;
 
@@ -302,7 +302,7 @@ static int ads5121_chipselect_init(struct mtd_info *mtd)
 /* Control chips select signal on ADS5121 board */
 static void ads5121_select_chip(struct mtd_info *mtd, int chip)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct mpc5121_nfc_prv *prv = nand_get_controller_data(nand);
 	u8 v;
 
@@ -332,7 +332,7 @@ static int mpc5121_nfc_dev_ready(struct mtd_info *mtd)
 static void mpc5121_nfc_command(struct mtd_info *mtd, unsigned command,
 							int column, int page)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
 
 	prv->column = (column >= 0) ? column : 0;
@@ -405,7 +405,7 @@ static void mpc5121_nfc_command(struct mtd_info *mtd, unsigned command,
 static void mpc5121_nfc_copy_spare(struct mtd_info *mtd, uint offset,
 						u8 *buffer, uint size, int wr)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct mpc5121_nfc_prv *prv = nand_get_controller_data(nand);
 	uint o, s, sbsize, blksize;
 
@@ -457,7 +457,7 @@ static void mpc5121_nfc_copy_spare(struct mtd_info *mtd, uint offset,
 static void mpc5121_nfc_buf_copy(struct mtd_info *mtd, u_char *buf, int len,
 									int wr)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
 	uint c = prv->column;
 	uint l;
@@ -535,7 +535,7 @@ static u16 mpc5121_nfc_read_word(struct mtd_info *mtd)
  */
 static int mpc5121_nfc_read_hw_config(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
 	struct mpc512x_reset_module *rm;
 	struct device_node *rmnode;
@@ -614,7 +614,7 @@ static int mpc5121_nfc_read_hw_config(struct mtd_info *mtd)
 /* Free driver resources */
 static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
 
 	if (prv->clk)
@@ -654,7 +654,7 @@ static int mpc5121_nfc_probe(struct platform_device *op)
 		return -ENOMEM;
 
 	chip = &prv->chip;
-	mtd = nand_to_mtd(chip);
+	mtd = nandc_to_mtd(chip);
 
 	mtd->dev.parent = dev;
 	nand_set_controller_data(chip, prv);
diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c
index 95f32ca88823..d3dd0cc99d2d 100644
--- a/drivers/mtd/nand/raw/mtk_nand.c
+++ b/drivers/mtd/nand/raw/mtk_nand.c
@@ -305,7 +305,7 @@ static int mtk_nfc_send_address(struct mtk_nfc *nfc, int addr)
 
 static int mtk_nfc_hw_runtime_config(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
 	struct mtk_nfc *nfc = nand_get_controller_data(chip);
 	u32 fmt, spare;
@@ -418,7 +418,7 @@ static int mtk_nfc_hw_runtime_config(struct mtd_info *mtd)
 
 static void mtk_nfc_select_chip(struct mtd_info *mtd, int chip)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct mtk_nfc *nfc = nand_get_controller_data(nand);
 	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(nand);
 
@@ -432,7 +432,7 @@ static void mtk_nfc_select_chip(struct mtd_info *mtd, int chip)
 
 static int mtk_nfc_dev_ready(struct mtd_info *mtd)
 {
-	struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
+	struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nandc(mtd));
 
 	if (nfi_readl(nfc, NFI_STA) & STA_BUSY)
 		return 0;
@@ -442,7 +442,7 @@ static int mtk_nfc_dev_ready(struct mtd_info *mtd)
 
 static void mtk_nfc_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
 {
-	struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
+	struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nandc(mtd));
 
 	if (ctrl & NAND_ALE) {
 		mtk_nfc_send_address(nfc, dat);
@@ -467,7 +467,7 @@ static inline void mtk_nfc_wait_ioready(struct mtk_nfc *nfc)
 
 static inline u8 mtk_nfc_read_byte(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct mtk_nfc *nfc = nand_get_controller_data(chip);
 	u32 reg;
 
@@ -504,7 +504,7 @@ static void mtk_nfc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
 
 static void mtk_nfc_write_byte(struct mtd_info *mtd, u8 byte)
 {
-	struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
+	struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nandc(mtd));
 	u32 reg;
 
 	reg = nfi_readl(nfc, NFI_STA) & NFI_FSM_MASK;
@@ -550,7 +550,7 @@ static void mtk_nfc_no_bad_mark_swap(struct mtd_info *a, u8 *b, int c)
 
 static void mtk_nfc_bad_mark_swap(struct mtd_info *mtd, u8 *buf, int raw)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct mtk_nfc_nand_chip *nand = to_mtk_nand(chip);
 	u32 bad_pos = nand->bad_mark.pos;
 
@@ -565,7 +565,7 @@ static void mtk_nfc_bad_mark_swap(struct mtd_info *mtd, u8 *buf, int raw)
 static int mtk_nfc_format_subpage(struct mtd_info *mtd, u32 offset,
 				  u32 len, const u8 *buf)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
 	struct mtk_nfc *nfc = nand_get_controller_data(chip);
 	struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
@@ -599,7 +599,7 @@ static int mtk_nfc_format_subpage(struct mtd_info *mtd, u32 offset,
 
 static void mtk_nfc_format_page(struct mtd_info *mtd, const u8 *buf)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
 	struct mtk_nfc *nfc = nand_get_controller_data(chip);
 	struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
@@ -812,7 +812,7 @@ static int mtk_nfc_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
 
 static int mtk_nfc_update_ecc_stats(struct mtd_info *mtd, u8 *buf, u32 sectors)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct mtk_nfc *nfc = nand_get_controller_data(chip);
 	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
 	struct mtk_ecc_stats stats;
@@ -1063,7 +1063,7 @@ static void mtk_nfc_disable_clk(struct mtk_nfc_clk *clk)
 static int mtk_nfc_ooblayout_free(struct mtd_info *mtd, int section,
 				  struct mtd_oob_region *oob_region)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
 	struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
 	u32 eccsteps;
@@ -1082,7 +1082,7 @@ static int mtk_nfc_ooblayout_free(struct mtd_info *mtd, int section,
 static int mtk_nfc_ooblayout_ecc(struct mtd_info *mtd, int section,
 				 struct mtd_oob_region *oob_region)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
 	u32 eccsteps;
 
@@ -1103,7 +1103,7 @@ static const struct mtd_ooblayout_ops mtk_nfc_ooblayout_ops = {
 
 static void mtk_nfc_set_fdm(struct mtk_nfc_fdm *fdm, struct mtd_info *mtd)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct mtk_nfc_nand_chip *chip = to_mtk_nand(nand);
 	u32 ecc_bytes;
 
@@ -1120,7 +1120,7 @@ static void mtk_nfc_set_fdm(struct mtk_nfc_fdm *fdm, struct mtd_info *mtd)
 static void mtk_nfc_set_bad_mark_ctl(struct mtk_nfc_bad_mark_ctl *bm_ctl,
 				     struct mtd_info *mtd)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 
 	if (mtd->writesize == 512) {
 		bm_ctl->bm_swap = mtk_nfc_no_bad_mark_swap;
@@ -1133,7 +1133,7 @@ static void mtk_nfc_set_bad_mark_ctl(struct mtk_nfc_bad_mark_ctl *bm_ctl,
 
 static void mtk_nfc_set_spare_per_sector(u32 *sps, struct mtd_info *mtd)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	u32 spare[] = {16, 26, 27, 28, 32, 36, 40, 44,
 			48, 49, 50, 51, 52, 62, 63, 64};
 	u32 eccsteps, i;
@@ -1163,7 +1163,7 @@ static void mtk_nfc_set_spare_per_sector(u32 *sps, struct mtd_info *mtd)
 
 static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	u32 spare;
 	int free;
 
@@ -1287,7 +1287,7 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
 	nand->ecc.read_oob_raw = mtk_nfc_read_oob_std;
 	nand->ecc.read_oob = mtk_nfc_read_oob_std;
 
-	mtd = nand_to_mtd(nand);
+	mtd = nandc_to_mtd(nand);
 	mtd->owner = THIS_MODULE;
 	mtd->dev.parent = dev;
 	mtd->name = MTK_NAME;
@@ -1451,7 +1451,7 @@ static int mtk_nfc_remove(struct platform_device *pdev)
 	while (!list_empty(&nfc->chips)) {
 		chip = list_first_entry(&nfc->chips, struct mtk_nfc_nand_chip,
 					node);
-		nand_release(nand_to_mtd(&chip->nand));
+		nand_release(nandc_to_mtd(&chip->nand));
 		list_del(&chip->node);
 	}
 
@@ -1491,7 +1491,7 @@ static int mtk_nfc_resume(struct device *dev)
 	/* reset NAND chip if VCC was powered off */
 	list_for_each_entry(chip, &nfc->chips, node) {
 		nand = &chip->nand;
-		mtd = nand_to_mtd(nand);
+		mtd = nandc_to_mtd(nand);
 		for (i = 0; i < chip->nsels; i++) {
 			nand->select_chip(mtd, i);
 			nand->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
diff --git a/drivers/mtd/nand/raw/mxc_nand.c b/drivers/mtd/nand/raw/mxc_nand.c
index 58a960540369..f45d0cb12291 100644
--- a/drivers/mtd/nand/raw/mxc_nand.c
+++ b/drivers/mtd/nand/raw/mxc_nand.c
@@ -466,7 +466,7 @@ static void send_addr_v1_v2(struct mxc_nand_host *host, uint16_t addr, int islas
 
 static void send_page_v3(struct mtd_info *mtd, unsigned int ops)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
 	uint32_t tmp;
 
@@ -482,7 +482,7 @@ static void send_page_v3(struct mtd_info *mtd, unsigned int ops)
 
 static void send_page_v2(struct mtd_info *mtd, unsigned int ops)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
 
 	/* NANDFC buffer 0 is used for page read/write */
@@ -496,7 +496,7 @@ static void send_page_v2(struct mtd_info *mtd, unsigned int ops)
 
 static void send_page_v1(struct mtd_info *mtd, unsigned int ops)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
 	int bufs, i;
 
@@ -597,7 +597,7 @@ static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode)
 static int mxc_nand_correct_data_v1(struct mtd_info *mtd, u_char *dat,
 				 u_char *read_ecc, u_char *calc_ecc)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
 
 	/*
@@ -618,7 +618,7 @@ static int mxc_nand_correct_data_v1(struct mtd_info *mtd, u_char *dat,
 static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat,
 				 u_char *read_ecc, u_char *calc_ecc)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
 	u32 ecc_stat, err;
 	int no_subpages = 1;
@@ -656,7 +656,7 @@ static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
 
 static u_char mxc_nand_read_byte(struct mtd_info *mtd)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
 	uint8_t ret;
 
@@ -680,7 +680,7 @@ static u_char mxc_nand_read_byte(struct mtd_info *mtd)
 
 static uint16_t mxc_nand_read_word(struct mtd_info *mtd)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
 	uint16_t ret;
 
@@ -696,7 +696,7 @@ static uint16_t mxc_nand_read_word(struct mtd_info *mtd)
 static void mxc_nand_write_buf(struct mtd_info *mtd,
 				const u_char *buf, int len)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
 	u16 col = host->buf_start;
 	int n = mtd->oobsize + mtd->writesize - col;
@@ -714,7 +714,7 @@ static void mxc_nand_write_buf(struct mtd_info *mtd,
  */
 static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
 	u16 col = host->buf_start;
 	int n = mtd->oobsize + mtd->writesize - col;
@@ -730,7 +730,7 @@ static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
  * deselect of the NAND chip */
 static void mxc_nand_select_chip_v1_v3(struct mtd_info *mtd, int chip)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
 
 	if (chip == -1) {
@@ -751,7 +751,7 @@ static void mxc_nand_select_chip_v1_v3(struct mtd_info *mtd, int chip)
 
 static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
 
 	if (chip == -1) {
@@ -784,7 +784,7 @@ static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip)
  */
 static void copy_spare(struct mtd_info *mtd, bool bfrom)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct mxc_nand_host *host = nand_get_controller_data(this);
 	u16 i, oob_chunk_size;
 	u16 num_chunks = mtd->writesize / 512;
@@ -827,7 +827,7 @@ static void copy_spare(struct mtd_info *mtd, bool bfrom)
  */
 static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
 
 	/* Write out column address, if necessary */
@@ -880,7 +880,7 @@ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
 static int mxc_v1_ooblayout_ecc(struct mtd_info *mtd, int section,
 				struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 
 	if (section >= nand_chip->ecc.steps)
 		return -ERANGE;
@@ -894,7 +894,7 @@ static int mxc_v1_ooblayout_ecc(struct mtd_info *mtd, int section,
 static int mxc_v1_ooblayout_free(struct mtd_info *mtd, int section,
 				 struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 
 	if (section > nand_chip->ecc.steps)
 		return -ERANGE;
@@ -928,7 +928,7 @@ static const struct mtd_ooblayout_ops mxc_v1_ooblayout_ops = {
 static int mxc_v2_ooblayout_ecc(struct mtd_info *mtd, int section,
 				struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	int stepsize = nand_chip->ecc.bytes == 9 ? 16 : 26;
 
 	if (section >= nand_chip->ecc.steps)
@@ -943,7 +943,7 @@ static int mxc_v2_ooblayout_ecc(struct mtd_info *mtd, int section,
 static int mxc_v2_ooblayout_free(struct mtd_info *mtd, int section,
 				 struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	int stepsize = nand_chip->ecc.bytes == 9 ? 16 : 26;
 
 	if (section >= nand_chip->ecc.steps)
@@ -989,7 +989,7 @@ static int get_eccsize(struct mtd_info *mtd)
 
 static void preset_v1(struct mtd_info *mtd)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
 	uint16_t config1 = 0;
 
@@ -1019,7 +1019,7 @@ static int mxc_nand_v2_setup_data_interface(struct mtd_info *mtd,
 					const struct nand_data_interface *conf,
 					bool check_only)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
 	int tRC_min_ns, tRC_ps, ret;
 	unsigned long rate, rate_round;
@@ -1093,7 +1093,7 @@ static int mxc_nand_v2_setup_data_interface(struct mtd_info *mtd,
 
 static void preset_v2(struct mtd_info *mtd)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
 	uint16_t config1 = 0;
 
@@ -1139,7 +1139,7 @@ static void preset_v2(struct mtd_info *mtd)
 
 static void preset_v3(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct mxc_nand_host *host = nand_get_controller_data(chip);
 	uint32_t config2, config3;
 	int i, addr_phases;
@@ -1210,7 +1210,7 @@ static void preset_v3(struct mtd_info *mtd)
 static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
 				int column, int page_addr)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
 
 	pr_debug("mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n",
@@ -1322,7 +1322,7 @@ static int mxc_nand_onfi_set_features(struct mtd_info *mtd,
 				      struct nand_chip *chip, int addr,
 				      u8 *subfeature_param)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
 	int i;
 
@@ -1348,7 +1348,7 @@ static int mxc_nand_onfi_get_features(struct mtd_info *mtd,
 				      struct nand_chip *chip, int addr,
 				      u8 *subfeature_param)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
 	int i;
 
@@ -1629,7 +1629,7 @@ static int mxcnd_probe(struct platform_device *pdev)
 	host->dev = &pdev->dev;
 	/* structures must be linked */
 	this = &host->nand;
-	mtd = nand_to_mtd(this);
+	mtd = nandc_to_mtd(this);
 	mtd->dev.parent = &pdev->dev;
 	mtd->name = DRIVER_NAME;
 
@@ -1834,7 +1834,7 @@ static int mxcnd_remove(struct platform_device *pdev)
 {
 	struct mxc_nand_host *host = platform_get_drvdata(pdev);
 
-	nand_release(nand_to_mtd(&host->nand));
+	nand_release(nandc_to_mtd(&host->nand));
 	if (host->clk_act)
 		clk_disable_unprepare(host->clk);
 
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 286abd768454..6d8ab58d4eb5 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -56,7 +56,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
 static int nand_ooblayout_ecc_sp(struct mtd_info *mtd, int section,
 				 struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct nand_ecc_ctrl *ecc = &chip->ecc;
 
 	if (section > 1)
@@ -105,7 +105,7 @@ EXPORT_SYMBOL_GPL(nand_ooblayout_sp_ops);
 static int nand_ooblayout_ecc_lp(struct mtd_info *mtd, int section,
 				 struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct nand_ecc_ctrl *ecc = &chip->ecc;
 
 	if (section)
@@ -120,7 +120,7 @@ static int nand_ooblayout_ecc_lp(struct mtd_info *mtd, int section,
 static int nand_ooblayout_free_lp(struct mtd_info *mtd, int section,
 				  struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct nand_ecc_ctrl *ecc = &chip->ecc;
 
 	if (section)
@@ -141,7 +141,7 @@ EXPORT_SYMBOL_GPL(nand_ooblayout_lp_ops);
 static int check_offs_len(struct mtd_info *mtd,
 					loff_t ofs, uint64_t len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	int ret = 0;
 
 	/* Start address must align on block boundary */
@@ -167,7 +167,7 @@ static int check_offs_len(struct mtd_info *mtd,
  */
 static void nand_release_device(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	/* Release the controller and the chip */
 	spin_lock(&chip->controller->lock);
@@ -185,7 +185,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_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	return readb(chip->IO_ADDR_R);
 }
 
@@ -198,7 +198,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_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R));
 }
 
@@ -210,7 +210,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_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	return readw(chip->IO_ADDR_R);
 }
 
@@ -223,7 +223,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_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	switch (chipnr) {
 	case -1:
@@ -246,7 +246,7 @@ static void nand_select_chip(struct mtd_info *mtd, int chipnr)
  */
 static void nand_write_byte(struct mtd_info *mtd, uint8_t byte)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	chip->write_buf(mtd, &byte, 1);
 }
@@ -260,7 +260,7 @@ static void nand_write_byte(struct mtd_info *mtd, uint8_t byte)
  */
 static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	uint16_t word = byte;
 
 	/*
@@ -292,7 +292,7 @@ static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte)
  */
 static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	iowrite8_rep(chip->IO_ADDR_W, buf, len);
 }
@@ -307,7 +307,7 @@ static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
  */
 static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	ioread8_rep(chip->IO_ADDR_R, buf, len);
 }
@@ -322,7 +322,7 @@ static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
  */
 static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	u16 *p = (u16 *) buf;
 
 	iowrite16_rep(chip->IO_ADDR_W, p, len >> 1);
@@ -338,7 +338,7 @@ static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
  */
 static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	u16 *p = (u16 *) buf;
 
 	ioread16_rep(chip->IO_ADDR_R, p, len >> 1);
@@ -354,7 +354,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 page, res = 0, i = 0;
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	u16 bad;
 
 	if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
@@ -400,7 +400,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
  */
 static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct mtd_oob_ops ops;
 	uint8_t buf[2] = { 0, 0 };
 	int ret = 0, res, i = 0;
@@ -450,7 +450,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
 */
 static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	int res, ret = 0;
 
 	if (!(chip->bbt_options & NAND_BBT_NO_OOB_BBM)) {
@@ -491,7 +491,7 @@ static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
  */
 static int nand_check_wp(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	/* Broken xD cards report WP despite being writable */
 	if (chip->options & NAND_BROKEN_XD)
@@ -511,7 +511,7 @@ static int nand_check_wp(struct mtd_info *mtd)
  */
 static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	if (!chip->bbt)
 		return 0;
@@ -530,7 +530,7 @@ static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs)
  */
 static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int allowbbt)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	if (!chip->bbt)
 		return chip->block_bad(mtd, ofs);
@@ -549,7 +549,7 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int allowbbt)
  */
 static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	int i;
 
 	/* Wait for the device to get ready */
@@ -569,7 +569,7 @@ static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo)
  */
 void nand_wait_ready(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	unsigned long timeo = 400;
 
 	if (in_interrupt() || oops_in_progress)
@@ -597,7 +597,7 @@ EXPORT_SYMBOL_GPL(nand_wait_ready);
  */
 static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo)
 {
-	register struct nand_chip *chip = mtd_to_nand(mtd);
+	register struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	timeo = jiffies + msecs_to_jiffies(timeo);
 	do {
@@ -620,7 +620,7 @@ static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo)
 static void nand_command(struct mtd_info *mtd, unsigned int command,
 			 int column, int page_addr)
 {
-	register struct nand_chip *chip = mtd_to_nand(mtd);
+	register struct nand_chip *chip = mtd_to_nandc(mtd);
 	int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;
 
 	/* Write out the command to the device */
@@ -723,7 +723,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_to_nand(mtd);
+	register struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	/* Emulate NAND_CMD_READOOB */
 	if (command == NAND_CMD_READOOB) {
@@ -850,7 +850,7 @@ static void panic_nand_get_device(struct nand_chip *chip,
 static int
 nand_get_device(struct mtd_info *mtd, int new_state)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	spinlock_t *lock = &chip->controller->lock;
 	wait_queue_head_t *wq = &chip->controller->wq;
 	DECLARE_WAITQUEUE(wait, current);
@@ -960,7 +960,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
  */
 static int nand_reset_data_interface(struct nand_chip *chip)
 {
-	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct mtd_info *mtd = nandc_to_mtd(chip);
 	const struct nand_data_interface *conf;
 	int ret;
 
@@ -1003,7 +1003,7 @@ static int nand_reset_data_interface(struct nand_chip *chip)
  */
 static int nand_setup_data_interface(struct nand_chip *chip)
 {
-	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct mtd_info *mtd = nandc_to_mtd(chip);
 	int ret;
 
 	if (!chip->setup_data_interface || !chip->data_interface)
@@ -1046,7 +1046,7 @@ static int nand_setup_data_interface(struct nand_chip *chip)
  */
 static int nand_init_data_interface(struct nand_chip *chip)
 {
-	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct mtd_info *mtd = nandc_to_mtd(chip);
 	int modes, mode, ret;
 
 	if (!chip->setup_data_interface)
@@ -1100,7 +1100,7 @@ static void nand_release_data_interface(struct nand_chip *chip)
  */
 int nand_reset(struct nand_chip *chip)
 {
-	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct mtd_info *mtd = nandc_to_mtd(chip);
 	int ret;
 
 	ret = nand_reset_data_interface(chip);
@@ -1133,7 +1133,7 @@ static int __nand_unlock(struct mtd_info *mtd, loff_t ofs,
 {
 	int ret = 0;
 	int status, page;
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	/* Submit address of first page to unlock */
 	page = ofs >> chip->page_shift;
@@ -1168,7 +1168,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 {
 	int ret = 0;
 	int chipnr;
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	pr_debug("%s: start = 0x%012llx, len = %llu\n",
 			__func__, (unsigned long long)ofs, len);
@@ -1231,7 +1231,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_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	pr_debug("%s: start = 0x%012llx, len = %llu\n",
 			__func__, (unsigned long long)ofs, len);
@@ -1833,7 +1833,7 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
 static uint8_t *nand_transfer_oob(struct mtd_info *mtd, uint8_t *oob,
 				  struct mtd_oob_ops *ops, size_t len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	int ret;
 
 	switch (ops->mode) {
@@ -1866,7 +1866,7 @@ static uint8_t *nand_transfer_oob(struct mtd_info *mtd, uint8_t *oob,
  */
 static int nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	pr_debug("setting READ RETRY mode %d\n", retry_mode);
 
@@ -1891,7 +1891,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_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	int ret = 0;
 	uint32_t readlen = ops->len;
 	uint32_t oobreadlen = ops->ooblen;
@@ -2072,8 +2072,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
  *
  * Get hold of the chip and call nand_do_read.
  */
-static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
-		     size_t *retlen, uint8_t *buf)
+static int nandc_read(struct mtd_info *mtd, loff_t from, size_t len,
+		      size_t *retlen, uint8_t *buf)
 {
 	struct mtd_oob_ops ops;
 	int ret;
@@ -2236,7 +2236,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_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct mtd_ecc_stats stats;
 	int readlen = ops->ooblen;
 	int len;
@@ -2678,7 +2678,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_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	int ret;
 
 	/*
@@ -2720,7 +2720,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_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	uint32_t writelen = ops->len;
 
 	uint32_t oobwritelen = ops->ooblen;
@@ -2849,7 +2849,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
 static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
 			    size_t *retlen, const uint8_t *buf)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct mtd_oob_ops ops;
 	int ret;
 
@@ -2880,8 +2880,8 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
  *
  * NAND write with ECC.
  */
-static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
-			  size_t *retlen, const uint8_t *buf)
+static int nandc_write(struct mtd_info *mtd, loff_t to, size_t len,
+		       size_t *retlen, const uint8_t *buf)
 {
 	struct mtd_oob_ops ops;
 	int ret;
@@ -2909,7 +2909,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_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	pr_debug("%s: to = 0x%08x, len = %i\n",
 			 __func__, (unsigned int)to, (int)ops->ooblen);
@@ -3031,7 +3031,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,
  */
 static int single_erase(struct mtd_info *mtd, int page)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	/* Send commands to erase a block */
 	chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
 	chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
@@ -3046,7 +3046,7 @@ static int single_erase(struct mtd_info *mtd, int page)
  *
  * Erase one ore more blocks.
  */
-static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
+static int nandc_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
 	return nand_erase_nand(mtd, instr, 0);
 }
@@ -3063,7 +3063,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_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	loff_t len;
 
 	pr_debug("%s: start = 0x%012llx, len = %llu\n",
@@ -3189,7 +3189,7 @@ static void nand_sync(struct mtd_info *mtd)
  */
 static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	int chipnr = (int)(offs >> chip->chip_shift);
 	int ret;
 
@@ -3291,7 +3291,7 @@ static int nand_suspend(struct mtd_info *mtd)
  */
 static void nand_resume(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	if (chip->state == FL_PM_SUSPENDED)
 		nand_release_device(mtd);
@@ -3462,7 +3462,7 @@ static int nand_flash_detect_ext_param_page(struct mtd_info *mtd,
 
 static int nand_setup_read_retry_micron(struct mtd_info *mtd, int retry_mode)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode};
 
 	return chip->onfi_set_features(mtd, chip, ONFI_FEATURE_ADDR_READ_RETRY,
@@ -4295,7 +4295,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
 		    struct nand_flash_dev *table)
 {
 	int i, nand_maf_id, nand_dev_id;
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct nand_flash_dev *type;
 	int ret;
 
@@ -4363,7 +4363,7 @@ EXPORT_SYMBOL(nand_scan_ident);
 
 static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct nand_ecc_ctrl *ecc = &chip->ecc;
 
 	if (WARN_ON(ecc->mode != NAND_ECC_SOFT))
@@ -4473,7 +4473,7 @@ static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
  */
 static bool nand_ecc_strength_good(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct nand_ecc_ctrl *ecc = &chip->ecc;
 	int corr, ds_corr;
 
@@ -4501,7 +4501,7 @@ static bool nand_ecc_strength_good(struct mtd_info *mtd)
  */
 int nand_scan_tail(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct nand_ecc_ctrl *ecc = &chip->ecc;
 	struct nand_buffers *nbuf;
 	int ret;
@@ -4726,11 +4726,11 @@ int nand_scan_tail(struct mtd_info *mtd)
 	mtd->type = nand_is_slc(chip) ? MTD_NANDFLASH : MTD_MLCNANDFLASH;
 	mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM :
 						MTD_CAP_NANDFLASH;
-	mtd->_erase = nand_erase;
+	mtd->_erase = nandc_erase;
 	mtd->_point = NULL;
 	mtd->_unpoint = NULL;
-	mtd->_read = nand_read;
-	mtd->_write = nand_write;
+	mtd->_read = nandc_read;
+	mtd->_write = nandc_write;
 	mtd->_panic_write = panic_nand_write;
 	mtd->_read_oob = nand_read_oob;
 	mtd->_write_oob = nand_write_oob;
@@ -4830,7 +4830,7 @@ EXPORT_SYMBOL_GPL(nand_cleanup);
 void nand_release(struct mtd_info *mtd)
 {
 	mtd_device_unregister(mtd);
-	nand_cleanup(mtd_to_nand(mtd));
+	nand_cleanup(mtd_to_nandc(mtd));
 }
 EXPORT_SYMBOL_GPL(nand_release);
 
diff --git a/drivers/mtd/nand/raw/nand_bbt.c b/drivers/mtd/nand/raw/nand_bbt.c
index 2915b6739bf8..3f2e785f4bfb 100644
--- a/drivers/mtd/nand/raw/nand_bbt.c
+++ b/drivers/mtd/nand/raw/nand_bbt.c
@@ -172,7 +172,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_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	size_t retlen, len, totlen;
 	loff_t from;
 	int bits = td->options & NAND_BBT_NRBITS_MSK;
@@ -263,7 +263,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_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	int res = 0, i;
 
 	if (td->options & NAND_BBT_PERCHIP) {
@@ -388,7 +388,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_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 
 	/* Read the primary version, if available */
 	if (td->options & NAND_BBT_VERSION) {
@@ -454,7 +454,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_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	int i, numblocks, numpages;
 	int startblock;
 	loff_t from;
@@ -523,7 +523,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_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	int i, chips;
 	int startblock, block, dir;
 	int scanlen = mtd->writesize + mtd->oobsize;
@@ -683,7 +683,7 @@ static void mark_bbt_block_bad(struct nand_chip *this,
 			       struct nand_bbt_descr *td,
 			       int chip, int block)
 {
-	struct mtd_info *mtd = nand_to_mtd(this);
+	struct mtd_info *mtd = nandc_to_mtd(this);
 	loff_t to;
 	int res;
 
@@ -712,7 +712,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_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct erase_info einfo;
 	int i, res, chip = 0;
 	int bits, page, offs, numblocks, sft, sftmsk;
@@ -896,7 +896,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_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 
 	return create_bbt(mtd, this->buffers->databuf, bd, -1);
 }
@@ -915,7 +915,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_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct nand_bbt_descr *td = this->bbt_td;
 	struct nand_bbt_descr *md = this->bbt_md;
 	struct nand_bbt_descr *rd, *rd2;
@@ -1039,7 +1039,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_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	int i, j, chips, block, nrblocks, update;
 	uint8_t oldval;
 
@@ -1099,7 +1099,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_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	u32 pattern_len;
 	u32 bits;
 	u32 table_size;
@@ -1151,7 +1151,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_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	int len, res;
 	uint8_t *buf;
 	struct nand_bbt_descr *td = this->bbt_td;
@@ -1224,7 +1224,7 @@ static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
  */
 static int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	int len, res = 0;
 	int chip, chipsel;
 	uint8_t *buf;
@@ -1358,7 +1358,7 @@ static int nand_create_badblock_pattern(struct nand_chip *this)
  */
 int nand_default_bbt(struct mtd_info *mtd)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	int ret;
 
 	/* Is a flash based bad block table requested? */
@@ -1394,7 +1394,7 @@ int nand_default_bbt(struct mtd_info *mtd)
  */
 int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	int block;
 
 	block = (int)(offs >> this->bbt_erase_shift);
@@ -1409,7 +1409,7 @@ int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs)
  */
 int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	int block, res;
 
 	block = (int)(offs >> this->bbt_erase_shift);
@@ -1436,7 +1436,7 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
  */
 int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	int block, ret = 0;
 
 	block = (int)(offs >> this->bbt_erase_shift);
diff --git a/drivers/mtd/nand/raw/nand_bch.c b/drivers/mtd/nand/raw/nand_bch.c
index 505441c9373b..ee3a82ea1a93 100644
--- a/drivers/mtd/nand/raw/nand_bch.c
+++ b/drivers/mtd/nand/raw/nand_bch.c
@@ -50,7 +50,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_to_nand(mtd);
+	const struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct nand_bch_control *nbc = chip->ecc.priv;
 	unsigned int i;
 
@@ -77,7 +77,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_to_nand(mtd);
+	const struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct nand_bch_control *nbc = chip->ecc.priv;
 	unsigned int *errloc = nbc->errloc;
 	int i, count;
@@ -120,7 +120,7 @@ EXPORT_SYMBOL(nand_bch_correct_data);
  */
 struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	unsigned int m, t, eccsteps, i;
 	struct nand_bch_control *nbc = NULL;
 	unsigned char *erased_page;
diff --git a/drivers/mtd/nand/raw/nand_ecc.c b/drivers/mtd/nand/raw/nand_ecc.c
index 7613a0388044..7c582b301e8b 100644
--- a/drivers/mtd/nand/raw/nand_ecc.c
+++ b/drivers/mtd/nand/raw/nand_ecc.c
@@ -424,7 +424,7 @@ int nand_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
 		       unsigned char *code)
 {
 	__nand_calculate_ecc(buf,
-			mtd_to_nand(mtd)->ecc.size, code);
+			mtd_to_nandc(mtd)->ecc.size, code);
 
 	return 0;
 }
@@ -524,7 +524,7 @@ int nand_correct_data(struct mtd_info *mtd, unsigned char *buf,
 		      unsigned char *read_ecc, unsigned char *calc_ecc)
 {
 	return __nand_correct_data(buf, read_ecc, calc_ecc,
-				   mtd_to_nand(mtd)->ecc.size);
+				   mtd_to_nandc(mtd)->ecc.size);
 }
 EXPORT_SYMBOL(nand_correct_data);
 
diff --git a/drivers/mtd/nand/raw/nandsim.c b/drivers/mtd/nand/raw/nandsim.c
index 9c16635b5338..020bd7e9cea0 100644
--- a/drivers/mtd/nand/raw/nandsim.c
+++ b/drivers/mtd/nand/raw/nandsim.c
@@ -666,7 +666,7 @@ static char __init *get_partition_name(int i)
  */
 static int __init init_nandsim(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct nandsim   *ns   = nand_get_controller_data(chip);
 	int i, ret = 0;
 	uint64_t remains;
@@ -1908,7 +1908,7 @@ static void switch_state(struct nandsim *ns)
 
 static u_char ns_nand_read_byte(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct nandsim *ns = nand_get_controller_data(chip);
 	u_char outb = 0x00;
 
@@ -1970,7 +1970,7 @@ static u_char ns_nand_read_byte(struct mtd_info *mtd)
 
 static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct nandsim *ns = nand_get_controller_data(chip);
 
 	/* Sanity and correctness checks */
@@ -2125,7 +2125,7 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
 
 static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct nandsim *ns = nand_get_controller_data(chip);
 
 	ns->lines.cle = bitmask & NAND_CLE ? 1 : 0;
@@ -2144,7 +2144,7 @@ static int ns_device_ready(struct mtd_info *mtd)
 
 static uint16_t ns_nand_read_word(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	NS_DBG("read_word\n");
 
@@ -2153,7 +2153,7 @@ static uint16_t ns_nand_read_word(struct mtd_info *mtd)
 
 static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct nandsim *ns = nand_get_controller_data(chip);
 
 	/* Check that chip is expecting data input */
@@ -2181,7 +2181,7 @@ static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
 
 static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct nandsim *ns = nand_get_controller_data(chip);
 
 	/* Sanity and correctness checks */
@@ -2203,7 +2203,7 @@ static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 		int i;
 
 		for (i = 0; i < len; i++)
-			buf[i] = mtd_to_nand(mtd)->read_byte(mtd);
+			buf[i] = mtd_to_nandc(mtd)->read_byte(mtd);
 
 		return;
 	}
@@ -2247,7 +2247,7 @@ static int __init ns_init_module(void)
 		NS_ERR("unable to allocate core structures.\n");
 		return -ENOMEM;
 	}
-	nsmtd       = nand_to_mtd(chip);
+	nsmtd       = nandc_to_mtd(chip);
 	nand        = (struct nandsim *)(chip + 1);
 	nand_set_controller_data(chip, (void *)nand);
 
@@ -2411,7 +2411,7 @@ module_init(ns_init_module);
  */
 static void __exit ns_cleanup_module(void)
 {
-	struct nand_chip *chip = mtd_to_nand(nsmtd);
+	struct nand_chip *chip = mtd_to_nandc(nsmtd);
 	struct nandsim *ns = nand_get_controller_data(chip);
 	int i;
 
@@ -2420,7 +2420,7 @@ static void __exit ns_cleanup_module(void)
 	nand_release(nsmtd); /* Unregister driver */
 	for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i)
 		kfree(ns->partitions[i].name);
-	kfree(mtd_to_nand(nsmtd));        /* Free other structures */
+	kfree(mtd_to_nandc(nsmtd));        /* Free other structures */
 	free_lists();
 }
 
diff --git a/drivers/mtd/nand/raw/ndfc.c b/drivers/mtd/nand/raw/ndfc.c
index d8a806894937..79a5cca84b0b 100644
--- a/drivers/mtd/nand/raw/ndfc.c
+++ b/drivers/mtd/nand/raw/ndfc.c
@@ -47,7 +47,7 @@ static struct ndfc_controller ndfc_ctrl[NDFC_MAX_CS];
 static void ndfc_select_chip(struct mtd_info *mtd, int chip)
 {
 	uint32_t ccr;
-	struct nand_chip *nchip = mtd_to_nand(mtd);
+	struct nand_chip *nchip = mtd_to_nandc(mtd);
 	struct ndfc_controller *ndfc = nand_get_controller_data(nchip);
 
 	ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
@@ -61,7 +61,7 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip)
 
 static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct ndfc_controller *ndfc = nand_get_controller_data(chip);
 
 	if (cmd == NAND_CMD_NONE)
@@ -75,7 +75,7 @@ static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
 
 static int ndfc_ready(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct ndfc_controller *ndfc = nand_get_controller_data(chip);
 
 	return in_be32(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY;
@@ -84,7 +84,7 @@ static int ndfc_ready(struct mtd_info *mtd)
 static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
 {
 	uint32_t ccr;
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct ndfc_controller *ndfc = nand_get_controller_data(chip);
 
 	ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
@@ -96,7 +96,7 @@ static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
 static int ndfc_calculate_ecc(struct mtd_info *mtd,
 			      const u_char *dat, u_char *ecc_code)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct ndfc_controller *ndfc = nand_get_controller_data(chip);
 	uint32_t ecc;
 	uint8_t *p = (uint8_t *)&ecc;
@@ -120,7 +120,7 @@ static int ndfc_calculate_ecc(struct mtd_info *mtd,
  */
 static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct ndfc_controller *ndfc = nand_get_controller_data(chip);
 	uint32_t *p = (uint32_t *) buf;
 
@@ -130,7 +130,7 @@ static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 
 static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct ndfc_controller *ndfc = nand_get_controller_data(chip);
 	uint32_t *p = (uint32_t *) buf;
 
@@ -146,7 +146,7 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc,
 {
 	struct device_node *flash_np;
 	struct nand_chip *chip = &ndfc->chip;
-	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct mtd_info *mtd = nandc_to_mtd(chip);
 	int ret;
 
 	chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA;
@@ -256,7 +256,7 @@ static int ndfc_probe(struct platform_device *ofdev)
 static int ndfc_remove(struct platform_device *ofdev)
 {
 	struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev);
-	struct mtd_info *mtd = nand_to_mtd(&ndfc->chip);
+	struct mtd_info *mtd = nandc_to_mtd(&ndfc->chip);
 
 	nand_release(mtd);
 	kfree(mtd->name);
diff --git a/drivers/mtd/nand/raw/nuc900_nand.c b/drivers/mtd/nand/raw/nuc900_nand.c
index 7bb4d2ea9342..ee19784a3f71 100644
--- a/drivers/mtd/nand/raw/nuc900_nand.c
+++ b/drivers/mtd/nand/raw/nuc900_nand.c
@@ -63,7 +63,7 @@ struct nuc900_nand {
 
 static inline struct nuc900_nand *mtd_to_nuc900(struct mtd_info *mtd)
 {
-	return container_of(mtd_to_nand(mtd), struct nuc900_nand, chip);
+	return container_of(mtd_to_nandc(mtd), struct nuc900_nand, chip);
 }
 
 static const struct mtd_partition partitions[] = {
@@ -132,7 +132,7 @@ static int nuc900_nand_devready(struct mtd_info *mtd)
 static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command,
 				   int column, int page_addr)
 {
-	register struct nand_chip *chip = mtd_to_nand(mtd);
+	register struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct nuc900_nand *nand = mtd_to_nuc900(mtd);
 
 	if (command == NAND_CMD_READOOB) {
@@ -243,7 +243,7 @@ static int nuc900_nand_probe(struct platform_device *pdev)
 	if (!nuc900_nand)
 		return -ENOMEM;
 	chip = &(nuc900_nand->chip);
-	mtd = nand_to_mtd(chip);
+	mtd = nandc_to_mtd(chip);
 
 	mtd->dev.parent		= &pdev->dev;
 	spin_lock_init(&nuc900_nand->lock);
@@ -284,7 +284,7 @@ static int nuc900_nand_remove(struct platform_device *pdev)
 {
 	struct nuc900_nand *nuc900_nand = platform_get_drvdata(pdev);
 
-	nand_release(nand_to_mtd(&nuc900_nand->chip));
+	nand_release(nandc_to_mtd(&nuc900_nand->chip));
 	clk_disable(nuc900_nand->clk);
 
 	return 0;
diff --git a/drivers/mtd/nand/raw/omap2.c b/drivers/mtd/nand/raw/omap2.c
index 5283898e9589..169b9c8db99e 100644
--- a/drivers/mtd/nand/raw/omap2.c
+++ b/drivers/mtd/nand/raw/omap2.c
@@ -184,7 +184,7 @@ struct omap_nand_info {
 
 static inline struct omap_nand_info *mtd_to_omap(struct mtd_info *mtd)
 {
-	return container_of(mtd_to_nand(mtd), struct omap_nand_info, nand);
+	return container_of(mtd_to_nandc(mtd), struct omap_nand_info, nand);
 }
 
 /**
@@ -279,7 +279,7 @@ static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
  */
 static void omap_read_buf8(struct mtd_info *mtd, u_char *buf, int len)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 
 	ioread8_rep(nand->IO_ADDR_R, buf, len);
 }
@@ -313,7 +313,7 @@ static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len)
  */
 static void omap_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 
 	ioread16_rep(nand->IO_ADDR_R, buf, len / 2);
 }
@@ -944,7 +944,7 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
 static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
 {
 	struct omap_nand_info *info = mtd_to_omap(mtd);
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	unsigned int dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
 	u32 val;
 
@@ -990,7 +990,7 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
  */
 static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct omap_nand_info *info = mtd_to_omap(mtd);
 	unsigned long timeo = jiffies;
 	int status, state = this->state;
@@ -1042,7 +1042,7 @@ static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd, int mode)
 	unsigned int dev_width, nsectors;
 	struct omap_nand_info *info = mtd_to_omap(mtd);
 	enum omap_ecc ecc_opt = info->ecc_opt;
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	u32 val, wr_mode;
 	unsigned int ecc_size1, ecc_size0;
 
@@ -1757,7 +1757,7 @@ static const struct mtd_ooblayout_ops omap_ooblayout_ops = {
 static int omap_sw_ooblayout_ecc(struct mtd_info *mtd, int section,
 				 struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	int off = BADBLOCK_MARKER_LENGTH;
 
 	if (section >= chip->ecc.steps)
@@ -1776,7 +1776,7 @@ static int omap_sw_ooblayout_ecc(struct mtd_info *mtd, int section,
 static int omap_sw_ooblayout_free(struct mtd_info *mtd, int section,
 				  struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	int off = BADBLOCK_MARKER_LENGTH;
 
 	if (section)
@@ -1851,7 +1851,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 	}
 
 	nand_chip		= &info->nand;
-	mtd			= nand_to_mtd(nand_chip);
+	mtd			= nandc_to_mtd(nand_chip);
 	mtd->dev.parent		= &pdev->dev;
 	nand_chip->ecc.priv	= NULL;
 	nand_set_flash_node(nand_chip, dev->of_node);
@@ -2181,7 +2181,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 static int omap_nand_remove(struct platform_device *pdev)
 {
 	struct mtd_info *mtd = platform_get_drvdata(pdev);
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct omap_nand_info *info = mtd_to_omap(mtd);
 	if (nand_chip->ecc.priv) {
 		nand_bch_free(nand_chip->ecc.priv);
diff --git a/drivers/mtd/nand/raw/orion_nand.c b/drivers/mtd/nand/raw/orion_nand.c
index e68c4231e8b7..e002f66b9693 100644
--- a/drivers/mtd/nand/raw/orion_nand.c
+++ b/drivers/mtd/nand/raw/orion_nand.c
@@ -25,7 +25,7 @@
 
 static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
 {
-	struct nand_chip *nc = mtd_to_nand(mtd);
+	struct nand_chip *nc = mtd_to_nandc(mtd);
 	struct orion_nand_data *board = nand_get_controller_data(nc);
 	u32 offs;
 
@@ -47,7 +47,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_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	void __iomem *io_base = chip->IO_ADDR_R;
 	uint64_t *buf64;
 	int i = 0;
@@ -89,7 +89,7 @@ static int __init orion_nand_probe(struct platform_device *pdev)
 			GFP_KERNEL);
 	if (!nc)
 		return -ENOMEM;
-	mtd = nand_to_mtd(nc);
+	mtd = nandc_to_mtd(nc);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	io_base = devm_ioremap_resource(&pdev->dev, res);
diff --git a/drivers/mtd/nand/raw/pasemi_nand.c b/drivers/mtd/nand/raw/pasemi_nand.c
index 372b9736ac02..80e5328ddfd5 100644
--- a/drivers/mtd/nand/raw/pasemi_nand.c
+++ b/drivers/mtd/nand/raw/pasemi_nand.c
@@ -45,7 +45,7 @@ static const char driver_name[] = "pasemi-nand";
 
 static void pasemi_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	while (len > 0x800) {
 		memcpy_fromio(buf, chip->IO_ADDR_R, 0x800);
@@ -57,7 +57,7 @@ static void pasemi_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 
 static void pasemi_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	while (len > 0x800) {
 		memcpy_toio(chip->IO_ADDR_R, buf, 0x800);
@@ -70,7 +70,7 @@ static void pasemi_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
 static void pasemi_hwcontrol(struct mtd_info *mtd, int cmd,
 			     unsigned int ctrl)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	if (cmd == NAND_CMD_NONE)
 		return;
@@ -117,7 +117,7 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
 		goto out;
 	}
 
-	pasemi_nand_mtd = nand_to_mtd(chip);
+	pasemi_nand_mtd = nandc_to_mtd(chip);
 
 	/* Link the private data with the MTD structure */
 	pasemi_nand_mtd->dev.parent = dev;
@@ -189,7 +189,7 @@ static int pasemi_nand_remove(struct platform_device *ofdev)
 	if (!pasemi_nand_mtd)
 		return 0;
 
-	chip = mtd_to_nand(pasemi_nand_mtd);
+	chip = mtd_to_nandc(pasemi_nand_mtd);
 
 	/* Release resources, unregister device */
 	nand_release(pasemi_nand_mtd);
diff --git a/drivers/mtd/nand/raw/plat_nand.c b/drivers/mtd/nand/raw/plat_nand.c
index d5c3c894c60d..af483bb0ae0d 100644
--- a/drivers/mtd/nand/raw/plat_nand.c
+++ b/drivers/mtd/nand/raw/plat_nand.c
@@ -57,7 +57,7 @@ static int plat_nand_probe(struct platform_device *pdev)
 		return PTR_ERR(data->io_base);
 
 	nand_set_flash_node(&data->chip, pdev->dev.of_node);
-	mtd = nand_to_mtd(&data->chip);
+	mtd = nandc_to_mtd(&data->chip);
 	mtd->dev.parent = &pdev->dev;
 
 	data->chip.IO_ADDR_R = data->io_base;
@@ -115,7 +115,7 @@ static int plat_nand_remove(struct platform_device *pdev)
 	struct plat_nand_data *data = platform_get_drvdata(pdev);
 	struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev);
 
-	nand_release(nand_to_mtd(&data->chip));
+	nand_release(nandc_to_mtd(&data->chip));
 	if (pdata->ctrl.remove)
 		pdata->ctrl.remove(pdev);
 
diff --git a/drivers/mtd/nand/raw/pxa3xx_nand.c b/drivers/mtd/nand/raw/pxa3xx_nand.c
index 4feec4ea3082..503e69c8d45e 100644
--- a/drivers/mtd/nand/raw/pxa3xx_nand.c
+++ b/drivers/mtd/nand/raw/pxa3xx_nand.c
@@ -326,7 +326,7 @@ static struct pxa3xx_nand_flash builtin_flash_types[] = {
 static int pxa3xx_ooblayout_ecc(struct mtd_info *mtd, int section,
 				struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
 	struct pxa3xx_nand_info *info = host->info_data;
 	int nchunks = mtd->writesize / info->chunk_size;
@@ -344,7 +344,7 @@ static int pxa3xx_ooblayout_ecc(struct mtd_info *mtd, int section,
 static int pxa3xx_ooblayout_free(struct mtd_info *mtd, int section,
 				 struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
 	struct pxa3xx_nand_info *info = host->info_data;
 	int nchunks = mtd->writesize / info->chunk_size;
@@ -509,7 +509,7 @@ static int pxa3xx_nand_init_timings_compat(struct pxa3xx_nand_host *host,
 	struct nand_chip *chip = &host->chip;
 	struct pxa3xx_nand_info *info = host->info_data;
 	const struct pxa3xx_nand_flash *f = NULL;
-	struct mtd_info *mtd = nand_to_mtd(&host->chip);
+	struct mtd_info *mtd = nandc_to_mtd(&host->chip);
 	int i, id, ntypes;
 
 	ntypes = ARRAY_SIZE(builtin_flash_types);
@@ -931,7 +931,7 @@ static void set_command_address(struct pxa3xx_nand_info *info,
 static void prepare_start_command(struct pxa3xx_nand_info *info, int command)
 {
 	struct pxa3xx_nand_host *host = info->host[info->cs];
-	struct mtd_info *mtd = nand_to_mtd(&host->chip);
+	struct mtd_info *mtd = nandc_to_mtd(&host->chip);
 
 	/* reset data and oob column point to handle data */
 	info->buf_start		= 0;
@@ -984,7 +984,7 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
 	struct mtd_info *mtd;
 
 	host = info->host[info->cs];
-	mtd = nand_to_mtd(&host->chip);
+	mtd = nandc_to_mtd(&host->chip);
 	addr_cycle = 0;
 	exec_cmd = 1;
 
@@ -1168,7 +1168,7 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
 static void nand_cmdfunc(struct mtd_info *mtd, unsigned command,
 			 int column, int page_addr)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
 	struct pxa3xx_nand_info *info = host->info_data;
 	int exec_cmd;
@@ -1217,7 +1217,7 @@ static void nand_cmdfunc_extended(struct mtd_info *mtd,
 				  const unsigned command,
 				  int column, int page_addr)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
 	struct pxa3xx_nand_info *info = host->info_data;
 	int exec_cmd, ext_cmd_type;
@@ -1373,7 +1373,7 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
 
 static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
 	struct pxa3xx_nand_info *info = host->info_data;
 	char retval = 0xFF;
@@ -1387,7 +1387,7 @@ static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd)
 
 static u16 pxa3xx_nand_read_word(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
 	struct pxa3xx_nand_info *info = host->info_data;
 	u16 retval = 0xFFFF;
@@ -1401,7 +1401,7 @@ static u16 pxa3xx_nand_read_word(struct mtd_info *mtd)
 
 static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
 	struct pxa3xx_nand_info *info = host->info_data;
 	int real_len = min_t(size_t, len, info->buf_count - info->buf_start);
@@ -1413,7 +1413,7 @@ static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 static void pxa3xx_nand_write_buf(struct mtd_info *mtd,
 		const uint8_t *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
 	struct pxa3xx_nand_info *info = host->info_data;
 	int real_len = min_t(size_t, len, info->buf_count - info->buf_start);
@@ -1429,7 +1429,7 @@ static void pxa3xx_nand_select_chip(struct mtd_info *mtd, int chip)
 
 static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
 	struct pxa3xx_nand_info *info = host->info_data;
 
@@ -1480,7 +1480,7 @@ static void pxa3xx_nand_config_tail(struct pxa3xx_nand_info *info)
 {
 	struct pxa3xx_nand_host *host = info->host[info->cs];
 	struct nand_chip *chip = &host->chip;
-	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct mtd_info *mtd = nandc_to_mtd(chip);
 
 	info->reg_ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0;
 	info->reg_ndcr |= (chip->page_shift == 6) ? NDCR_PG_PER_BLK : 0;
@@ -1569,7 +1569,7 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
 			struct mtd_info *mtd,
 			int strength, int ecc_stepsize, int page_size)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct nand_ecc_ctrl *ecc = &chip->ecc;
 
 	if (strength == 1 && ecc_stepsize == 512 && page_size == 2048) {
@@ -1651,7 +1651,7 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
 
 static int pxa3xx_nand_scan(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
 	struct pxa3xx_nand_info *info = host->info_data;
 	struct platform_device *pdev = info->pdev;
@@ -1788,7 +1788,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
 		host = (void *)&info[1] + sizeof(*host) * cs;
 		chip = &host->chip;
 		nand_set_controller_data(chip, host);
-		mtd = nand_to_mtd(chip);
+		mtd = nandc_to_mtd(chip);
 		info->host[cs] = host;
 		host->cs = cs;
 		host->info_data = info;
@@ -1906,7 +1906,7 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)
 	clk_disable_unprepare(info->clk);
 
 	for (cs = 0; cs < pdata->num_cs; cs++)
-		nand_release(nand_to_mtd(&info->host[cs]->chip));
+		nand_release(nandc_to_mtd(&info->host[cs]->chip));
 	return 0;
 }
 
@@ -1968,7 +1968,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
 	info = platform_get_drvdata(pdev);
 	probe_success = 0;
 	for (cs = 0; cs < pdata->num_cs; cs++) {
-		struct mtd_info *mtd = nand_to_mtd(&info->host[cs]->chip);
+		struct mtd_info *mtd = nandc_to_mtd(&info->host[cs]->chip);
 
 		/*
 		 * The mtd name matches the one used in 'mtdparts' kernel
diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c
index a77c66f4d8bc..20a79f966f2c 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -873,7 +873,7 @@ static void post_command(struct qcom_nand_host *host, int command)
 static void qcom_nandc_command(struct mtd_info *mtd, unsigned int command,
 			       int column, int page_addr)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct qcom_nand_host *host = to_qcom_nand_host(chip);
 	struct nand_ecc_ctrl *ecc = &chip->ecc;
 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
@@ -1008,7 +1008,7 @@ static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf,
 {
 	struct nand_chip *chip = &host->chip;
 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct mtd_info *mtd = nandc_to_mtd(chip);
 	struct nand_ecc_ctrl *ecc = &chip->ecc;
 	unsigned int max_bitflips = 0;
 	struct read_stats *buf;
@@ -1481,7 +1481,7 @@ static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
 
 static int qcom_nandc_block_bad(struct mtd_info *mtd, loff_t ofs)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct qcom_nand_host *host = to_qcom_nand_host(chip);
 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
 	struct nand_ecc_ctrl *ecc = &chip->ecc;
@@ -1521,7 +1521,7 @@ static int qcom_nandc_block_bad(struct mtd_info *mtd, loff_t ofs)
 
 static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct qcom_nand_host *host = to_qcom_nand_host(chip);
 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
 	struct nand_ecc_ctrl *ecc = &chip->ecc;
@@ -1571,7 +1571,7 @@ static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs)
  */
 static uint8_t qcom_nandc_read_byte(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct qcom_nand_host *host = to_qcom_nand_host(chip);
 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
 	u8 *buf = nandc->data_buffer;
@@ -1593,7 +1593,7 @@ static uint8_t qcom_nandc_read_byte(struct mtd_info *mtd)
 
 static void qcom_nandc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
 	int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
 
@@ -1604,7 +1604,7 @@ static void qcom_nandc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 static void qcom_nandc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
 				 int len)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
 	int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
 
@@ -1616,7 +1616,7 @@ static void qcom_nandc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
 /* we support only one external chip for now */
 static void qcom_nandc_select_chip(struct mtd_info *mtd, int chipnr)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
 
 	if (chipnr <= 0)
@@ -1713,7 +1713,7 @@ static void qcom_nandc_select_chip(struct mtd_info *mtd, int chipnr)
 static int qcom_nand_ooblayout_ecc(struct mtd_info *mtd, int section,
 				   struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct qcom_nand_host *host = to_qcom_nand_host(chip);
 	struct nand_ecc_ctrl *ecc = &chip->ecc;
 
@@ -1735,7 +1735,7 @@ static int qcom_nand_ooblayout_ecc(struct mtd_info *mtd, int section,
 static int qcom_nand_ooblayout_free(struct mtd_info *mtd, int section,
 				     struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct qcom_nand_host *host = to_qcom_nand_host(chip);
 	struct nand_ecc_ctrl *ecc = &chip->ecc;
 
@@ -1756,7 +1756,7 @@ static const struct mtd_ooblayout_ops qcom_nand_ooblayout_ops = {
 static int qcom_nand_host_setup(struct qcom_nand_host *host)
 {
 	struct nand_chip *chip = &host->chip;
-	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct mtd_info *mtd = nandc_to_mtd(chip);
 	struct nand_ecc_ctrl *ecc = &chip->ecc;
 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
 	int cwperpage, bad_block_byte;
@@ -1988,7 +1988,7 @@ static int qcom_nand_host_init(struct qcom_nand_controller *nandc,
 			       struct device_node *dn)
 {
 	struct nand_chip *chip = &host->chip;
-	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct mtd_info *mtd = nandc_to_mtd(chip);
 	struct device *dev = nandc->dev;
 	int ret;
 
@@ -2152,7 +2152,7 @@ static int qcom_nandc_probe(struct platform_device *pdev)
 
 err_cs_init:
 	list_for_each_entry(host, &nandc->host_list, node)
-		nand_release(nand_to_mtd(&host->chip));
+		nand_release(nandc_to_mtd(&host->chip));
 err_setup:
 	clk_disable_unprepare(nandc->aon_clk);
 err_aon_clk:
@@ -2169,7 +2169,7 @@ static int qcom_nandc_remove(struct platform_device *pdev)
 	struct qcom_nand_host *host;
 
 	list_for_each_entry(host, &nandc->host_list, node)
-		nand_release(nand_to_mtd(&host->chip));
+		nand_release(nandc_to_mtd(&host->chip));
 
 	qcom_nandc_unalloc(nandc);
 
diff --git a/drivers/mtd/nand/raw/r852.c b/drivers/mtd/nand/raw/r852.c
index fc9287af4614..f63f9a5143c7 100644
--- a/drivers/mtd/nand/raw/r852.c
+++ b/drivers/mtd/nand/raw/r852.c
@@ -64,7 +64,7 @@ static inline void r852_write_reg_dword(struct r852_device *dev,
 /* returns pointer to our private structure */
 static inline struct r852_device *r852_get_dev(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	return nand_get_controller_data(chip);
 }
 
@@ -634,7 +634,7 @@ static void r852_update_media_status(struct r852_device *dev)
  */
 static int r852_register_nand_device(struct r852_device *dev)
 {
-	struct mtd_info *mtd = nand_to_mtd(dev->chip);
+	struct mtd_info *mtd = nandc_to_mtd(dev->chip);
 
 	WARN_ON(dev->card_registred);
 
@@ -669,7 +669,7 @@ static int r852_register_nand_device(struct r852_device *dev)
 
 static void r852_unregister_nand_device(struct r852_device *dev)
 {
-	struct mtd_info *mtd = nand_to_mtd(dev->chip);
+	struct mtd_info *mtd = nandc_to_mtd(dev->chip);
 
 	if (!dev->card_registred)
 		return;
@@ -1025,7 +1025,7 @@ static int r852_suspend(struct device *device)
 static int r852_resume(struct device *device)
 {
 	struct r852_device *dev = pci_get_drvdata(to_pci_dev(device));
-	struct mtd_info *mtd = nand_to_mtd(dev->chip);
+	struct mtd_info *mtd = nandc_to_mtd(dev->chip);
 
 	r852_disable_irqs(dev);
 	r852_card_update_present(dev);
diff --git a/drivers/mtd/nand/raw/s3c2410.c b/drivers/mtd/nand/raw/s3c2410.c
index 6ce9f867a123..b6648ee2280a 100644
--- a/drivers/mtd/nand/raw/s3c2410.c
+++ b/drivers/mtd/nand/raw/s3c2410.c
@@ -189,7 +189,7 @@ struct s3c2410_nand_info {
 
 static struct s3c2410_nand_mtd *s3c2410_nand_mtd_toours(struct mtd_info *mtd)
 {
-	return container_of(mtd_to_nand(mtd), struct s3c2410_nand_mtd,
+	return container_of(mtd_to_nandc(mtd), struct s3c2410_nand_mtd,
 			    chip);
 }
 
@@ -404,7 +404,7 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
 {
 	struct s3c2410_nand_info *info;
 	struct s3c2410_nand_mtd *nmtd;
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	unsigned long cur;
 
 	nmtd = nand_get_controller_data(this);
@@ -657,7 +657,7 @@ static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
 
 static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	readsb(this->IO_ADDR_R, buf, len);
 }
 
@@ -679,7 +679,7 @@ static void s3c2440_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 static void s3c2410_nand_write_buf(struct mtd_info *mtd, const u_char *buf,
 				   int len)
 {
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	writesb(this->IO_ADDR_W, buf, len);
 }
 
@@ -768,7 +768,7 @@ static int s3c24xx_nand_remove(struct platform_device *pdev)
 
 		for (mtdno = 0; mtdno < info->mtd_count; mtdno++, ptr++) {
 			pr_debug("releasing mtd %d (%p)\n", mtdno, ptr);
-			nand_release(nand_to_mtd(&ptr->chip));
+			nand_release(nandc_to_mtd(&ptr->chip));
 		}
 	}
 
@@ -785,7 +785,7 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
 				      struct s3c2410_nand_set *set)
 {
 	if (set) {
-		struct mtd_info *mtdinfo = nand_to_mtd(&mtd->chip);
+		struct mtd_info *mtdinfo = nandc_to_mtd(&mtd->chip);
 
 		mtdinfo->name = set->name;
 
@@ -943,7 +943,7 @@ static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
 	} else {
 		chip->ecc.size	    = 512;
 		chip->ecc.bytes	    = 3;
-		mtd_set_ooblayout(nand_to_mtd(chip), &s3c2410_ooblayout_ops);
+		mtd_set_ooblayout(nandc_to_mtd(chip), &s3c2410_ooblayout_ops);
 	}
 }
 
@@ -1033,7 +1033,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 	nmtd = info->mtds;
 
 	for (setno = 0; setno < nr_sets; setno++, nmtd++) {
-		struct mtd_info *mtd = nand_to_mtd(&nmtd->chip);
+		struct mtd_info *mtd = nandc_to_mtd(&nmtd->chip);
 
 		pr_debug("initialising set %d (%p, info %p)\n",
 			 setno, nmtd, info);
diff --git a/drivers/mtd/nand/raw/sh_flctl.c b/drivers/mtd/nand/raw/sh_flctl.c
index 492705fb23f2..c9baab2023c2 100644
--- a/drivers/mtd/nand/raw/sh_flctl.c
+++ b/drivers/mtd/nand/raw/sh_flctl.c
@@ -45,7 +45,7 @@
 static int flctl_4secc_ooblayout_sp_ecc(struct mtd_info *mtd, int section,
 					struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	if (section)
 		return -ERANGE;
@@ -76,7 +76,7 @@ static const struct mtd_ooblayout_ops flctl_4secc_oob_smallpage_ops = {
 static int flctl_4secc_ooblayout_lp_ecc(struct mtd_info *mtd, int section,
 					struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	if (section >= chip->ecc.steps)
 		return -ERANGE;
@@ -90,7 +90,7 @@ static int flctl_4secc_ooblayout_lp_ecc(struct mtd_info *mtd, int section,
 static int flctl_4secc_ooblayout_lp_free(struct mtd_info *mtd, int section,
 					 struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	if (section >= chip->ecc.steps)
 		return -ERANGE;
@@ -1164,7 +1164,7 @@ static int flctl_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, flctl);
 	nand = &flctl->chip;
-	flctl_mtd = nand_to_mtd(nand);
+	flctl_mtd = nandc_to_mtd(nand);
 	nand_set_flash_node(nand, pdev->dev.of_node);
 	flctl_mtd->dev.parent = &pdev->dev;
 	flctl->pdev = pdev;
@@ -1229,7 +1229,7 @@ static int flctl_remove(struct platform_device *pdev)
 	struct sh_flctl *flctl = platform_get_drvdata(pdev);
 
 	flctl_release_dma(flctl);
-	nand_release(nand_to_mtd(&flctl->chip));
+	nand_release(nandc_to_mtd(&flctl->chip));
 	pm_runtime_disable(&pdev->dev);
 
 	return 0;
diff --git a/drivers/mtd/nand/raw/sharpsl.c b/drivers/mtd/nand/raw/sharpsl.c
index 737efe83cd36..00ef260dfe99 100644
--- a/drivers/mtd/nand/raw/sharpsl.c
+++ b/drivers/mtd/nand/raw/sharpsl.c
@@ -36,7 +36,7 @@ struct sharpsl_nand {
 
 static inline struct sharpsl_nand *mtd_to_sharpsl(struct mtd_info *mtd)
 {
-	return container_of(mtd_to_nand(mtd), struct sharpsl_nand, chip);
+	return container_of(mtd_to_nandc(mtd), struct sharpsl_nand, chip);
 }
 
 /* register offset */
@@ -68,7 +68,7 @@ static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd,
 				   unsigned int ctrl)
 {
 	struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	if (ctrl & NAND_CTRL_CHANGE) {
 		unsigned char bits = ctrl & 0x07;
@@ -146,7 +146,7 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
 	this = (struct nand_chip *)(&sharpsl->chip);
 
 	/* Link the private data with the MTD structure */
-	mtd = nand_to_mtd(this);
+	mtd = nandc_to_mtd(this);
 	mtd->dev.parent = &pdev->dev;
 	mtd_set_ooblayout(mtd, data->ecc_layout);
 
@@ -210,7 +210,7 @@ static int sharpsl_nand_remove(struct platform_device *pdev)
 	struct sharpsl_nand *sharpsl = platform_get_drvdata(pdev);
 
 	/* Release resources, unregister device */
-	nand_release(nand_to_mtd(&sharpsl->chip));
+	nand_release(nandc_to_mtd(&sharpsl->chip));
 
 	iounmap(sharpsl->io);
 
diff --git a/drivers/mtd/nand/raw/sm_common.c b/drivers/mtd/nand/raw/sm_common.c
index c378705c6e2b..a0ad3283a8d9 100644
--- a/drivers/mtd/nand/raw/sm_common.c
+++ b/drivers/mtd/nand/raw/sm_common.c
@@ -163,7 +163,7 @@ static struct nand_flash_dev nand_xd_flash_ids[] = {
 
 int sm_register_device(struct mtd_info *mtd, int smartmedia)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	int ret;
 
 	chip->options |= NAND_SKIP_BBTSCAN;
diff --git a/drivers/mtd/nand/raw/socrates_nand.c b/drivers/mtd/nand/raw/socrates_nand.c
index f5a3e7252b82..bd918869c878 100644
--- a/drivers/mtd/nand/raw/socrates_nand.c
+++ b/drivers/mtd/nand/raw/socrates_nand.c
@@ -44,7 +44,7 @@ static void socrates_nand_write_buf(struct mtd_info *mtd,
 		const uint8_t *buf, int len)
 {
 	int i;
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct socrates_nand_host *host = nand_get_controller_data(this);
 
 	for (i = 0; i < len; i++) {
@@ -63,7 +63,7 @@ static void socrates_nand_write_buf(struct mtd_info *mtd,
 static void socrates_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 {
 	int i;
-	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_chip *this = mtd_to_nandc(mtd);
 	struct socrates_nand_host *host = nand_get_controller_data(this);
 	uint32_t val;
 
@@ -104,7 +104,7 @@ static uint16_t socrates_nand_read_word(struct mtd_info *mtd)
 static void socrates_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
 		unsigned int ctrl)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct socrates_nand_host *host = nand_get_controller_data(nand_chip);
 	uint32_t val;
 
@@ -129,7 +129,7 @@ static void socrates_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
  */
 static int socrates_nand_device_ready(struct mtd_info *mtd)
 {
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct nand_chip *nand_chip = mtd_to_nandc(mtd);
 	struct socrates_nand_host *host = nand_get_controller_data(nand_chip);
 
 	if (in_be32(host->io_base) & FPGA_NAND_BUSY)
@@ -159,7 +159,7 @@ static int socrates_nand_probe(struct platform_device *ofdev)
 	}
 
 	nand_chip = &host->nand_chip;
-	mtd = nand_to_mtd(nand_chip);
+	mtd = nandc_to_mtd(nand_chip);
 	host->dev = &ofdev->dev;
 
 	/* link the private data structures */
@@ -216,7 +216,7 @@ static int socrates_nand_probe(struct platform_device *ofdev)
 static int socrates_nand_remove(struct platform_device *ofdev)
 {
 	struct socrates_nand_host *host = dev_get_drvdata(&ofdev->dev);
-	struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
+	struct mtd_info *mtd = nandc_to_mtd(&host->nand_chip);
 
 	nand_release(mtd);
 
diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c
index ccccc7ab9023..f17f2609927c 100644
--- a/drivers/mtd/nand/raw/sunxi_nand.c
+++ b/drivers/mtd/nand/raw/sunxi_nand.c
@@ -374,7 +374,7 @@ static int sunxi_nfc_dma_op_prepare(struct mtd_info *mtd, const void *buf,
 				    enum dma_data_direction ddir,
 				    struct scatterlist *sg)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
 	struct dma_async_tx_descriptor *dmad;
 	enum dma_transfer_direction tdir;
@@ -422,7 +422,7 @@ static void sunxi_nfc_dma_op_cleanup(struct mtd_info *mtd,
 				     enum dma_data_direction ddir,
 				     struct scatterlist *sg)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
 
 	dma_unmap_sg(nfc->dev, sg, 1, ddir);
@@ -432,7 +432,7 @@ static void sunxi_nfc_dma_op_cleanup(struct mtd_info *mtd,
 
 static int sunxi_nfc_dev_ready(struct mtd_info *mtd)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
 	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
 	struct sunxi_nand_rb *rb;
@@ -463,7 +463,7 @@ static int sunxi_nfc_dev_ready(struct mtd_info *mtd)
 
 static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
 	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
 	struct sunxi_nand_chip_sel *sel;
@@ -508,7 +508,7 @@ static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip)
 
 static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
 	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
 	int ret;
@@ -541,7 +541,7 @@ static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
 				int len)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
 	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
 	int ret;
@@ -582,7 +582,7 @@ static uint8_t sunxi_nfc_read_byte(struct mtd_info *mtd)
 static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat,
 			       unsigned int ctrl)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
 	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
 	int ret;
@@ -739,7 +739,7 @@ static u16 sunxi_nfc_randomizer_state(struct mtd_info *mtd, int page, bool ecc)
 static void sunxi_nfc_randomizer_config(struct mtd_info *mtd,
 					int page, bool ecc)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
 	u32 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
 	u16 state;
@@ -755,7 +755,7 @@ static void sunxi_nfc_randomizer_config(struct mtd_info *mtd,
 
 static void sunxi_nfc_randomizer_enable(struct mtd_info *mtd)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
 
 	if (!(nand->options & NAND_NEED_SCRAMBLING))
@@ -767,7 +767,7 @@ static void sunxi_nfc_randomizer_enable(struct mtd_info *mtd)
 
 static void sunxi_nfc_randomizer_disable(struct mtd_info *mtd)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
 
 	if (!(nand->options & NAND_NEED_SCRAMBLING))
@@ -806,7 +806,7 @@ static void sunxi_nfc_randomizer_read_buf(struct mtd_info *mtd, uint8_t *buf,
 
 static void sunxi_nfc_hw_ecc_enable(struct mtd_info *mtd)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
 	struct sunxi_nand_hw_ecc *data = nand->ecc.priv;
 	u32 ecc_ctl;
@@ -822,7 +822,7 @@ static void sunxi_nfc_hw_ecc_enable(struct mtd_info *mtd)
 
 static void sunxi_nfc_hw_ecc_disable(struct mtd_info *mtd)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
 
 	writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN,
@@ -845,7 +845,7 @@ static inline u32 sunxi_nfc_buf_to_user_data(const u8 *buf)
 static void sunxi_nfc_hw_ecc_get_prot_oob_bytes(struct mtd_info *mtd, u8 *oob,
 						int step, bool bbm, int page)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
 
 	sunxi_nfc_user_data_to_buf(readl(nfc->regs + NFC_REG_USER_DATA(step)),
@@ -860,7 +860,7 @@ static void sunxi_nfc_hw_ecc_set_prot_oob_bytes(struct mtd_info *mtd,
 						const u8 *oob, int step,
 						bool bbm, int page)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
 	u8 user_data[4];
 
@@ -889,7 +889,7 @@ static void sunxi_nfc_hw_ecc_update_stats(struct mtd_info *mtd,
 static int sunxi_nfc_hw_ecc_correct(struct mtd_info *mtd, u8 *data, u8 *oob,
 				    int step, u32 status, bool *erased)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
 	struct nand_ecc_ctrl *ecc = &nand->ecc;
 	u32 tmp;
@@ -930,7 +930,7 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
 				       unsigned int *max_bitflips,
 				       bool bbm, bool oob_required, int page)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
 	struct nand_ecc_ctrl *ecc = &nand->ecc;
 	int raw_mode = 0;
@@ -1009,7 +1009,7 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd,
 					    u8 *oob, int *cur_off,
 					    bool randomize, int page)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct nand_ecc_ctrl *ecc = &nand->ecc;
 	int offset = ((ecc->bytes + 4) * ecc->steps);
 	int len = mtd->oobsize - offset;
@@ -1035,7 +1035,7 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct mtd_info *mtd, uint8_t *buf,
 					    int oob_required, int page,
 					    int nchunks)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	bool randomized = nand->options & NAND_NEED_SCRAMBLING;
 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
 	struct nand_ecc_ctrl *ecc = &nand->ecc;
@@ -1161,7 +1161,7 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
 					int *cur_off, bool bbm,
 					int page)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
 	struct nand_ecc_ctrl *ecc = &nand->ecc;
 	int ret;
@@ -1199,7 +1199,7 @@ static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd,
 					     u8 *oob, int *cur_off,
 					     int page)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct nand_ecc_ctrl *ecc = &nand->ecc;
 	int offset = ((ecc->bytes + 4) * ecc->steps);
 	int len = mtd->oobsize - offset;
@@ -1390,7 +1390,7 @@ static int sunxi_nfc_hw_ecc_write_page_dma(struct mtd_info *mtd,
 					   int oob_required,
 					   int page)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
 	struct nand_ecc_ctrl *ecc = &nand->ecc;
 	struct scatterlist sg;
@@ -1576,7 +1576,7 @@ static int sunxi_nfc_setup_data_interface(struct mtd_info *mtd,
 					const struct nand_data_interface *conf,
 					bool check_only)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct sunxi_nand_chip *chip = to_sunxi_nand(nand);
 	struct sunxi_nfc *nfc = to_sunxi_nfc(chip->nand.controller);
 	const struct nand_sdr_timings *timings;
@@ -1726,7 +1726,7 @@ static int sunxi_nfc_setup_data_interface(struct mtd_info *mtd,
 static int sunxi_nand_ooblayout_ecc(struct mtd_info *mtd, int section,
 				    struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct nand_ecc_ctrl *ecc = &nand->ecc;
 
 	if (section >= ecc->steps)
@@ -1741,7 +1741,7 @@ static int sunxi_nand_ooblayout_ecc(struct mtd_info *mtd, int section,
 static int sunxi_nand_ooblayout_free(struct mtd_info *mtd, int section,
 				     struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct nand_ecc_ctrl *ecc = &nand->ecc;
 
 	if (section > ecc->steps)
@@ -1779,7 +1779,7 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
 					      struct device_node *np)
 {
 	static const u8 strengths[] = { 16, 24, 28, 32, 40, 48, 56, 60, 64 };
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
 	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
 	struct sunxi_nand_hw_ecc *data;
@@ -1878,7 +1878,7 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,
 				       struct nand_ecc_ctrl *ecc,
 				       struct device_node *np)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
 	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
 	int ret;
@@ -1942,7 +1942,7 @@ static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc)
 static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc,
 			       struct device_node *np)
 {
-	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_chip *nand = mtd_to_nandc(mtd);
 	int ret;
 
 	if (!ecc->size) {
@@ -2068,7 +2068,7 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
 	nand->read_byte = sunxi_nfc_read_byte;
 	nand->setup_data_interface = sunxi_nfc_setup_data_interface;
 
-	mtd = nand_to_mtd(nand);
+	mtd = nandc_to_mtd(nand);
 	mtd->dev.parent = dev;
 
 	ret = nand_scan_ident(mtd, nsels, NULL);
@@ -2137,7 +2137,7 @@ static void sunxi_nand_chips_cleanup(struct sunxi_nfc *nfc)
 	while (!list_empty(&nfc->chips)) {
 		chip = list_first_entry(&nfc->chips, struct sunxi_nand_chip,
 					node);
-		nand_release(nand_to_mtd(&chip->nand));
+		nand_release(nandc_to_mtd(&chip->nand));
 		sunxi_nand_ecc_cleanup(&chip->nand.ecc);
 		list_del(&chip->node);
 	}
diff --git a/drivers/mtd/nand/raw/tmio_nand.c b/drivers/mtd/nand/raw/tmio_nand.c
index e599ada12cd0..af8e6a9743fd 100644
--- a/drivers/mtd/nand/raw/tmio_nand.c
+++ b/drivers/mtd/nand/raw/tmio_nand.c
@@ -120,7 +120,7 @@ struct tmio_nand {
 
 static inline struct tmio_nand *mtd_to_tmio(struct mtd_info *mtd)
 {
-	return container_of(mtd_to_nand(mtd), struct tmio_nand, chip);
+	return container_of(mtd_to_nandc(mtd), struct tmio_nand, chip);
 }
 
 
@@ -130,7 +130,7 @@ static void tmio_nand_hwcontrol(struct mtd_info *mtd, int cmd,
 				   unsigned int ctrl)
 {
 	struct tmio_nand *tmio = mtd_to_tmio(mtd);
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 
 	if (ctrl & NAND_CTRL_CHANGE) {
 		u8 mode;
@@ -381,7 +381,7 @@ static int tmio_probe(struct platform_device *dev)
 
 	platform_set_drvdata(dev, tmio);
 	nand_chip = &tmio->chip;
-	mtd = nand_to_mtd(nand_chip);
+	mtd = nandc_to_mtd(nand_chip);
 	mtd->name = "tmio-nand";
 	mtd->dev.parent = &dev->dev;
 
@@ -457,7 +457,7 @@ static int tmio_remove(struct platform_device *dev)
 {
 	struct tmio_nand *tmio = platform_get_drvdata(dev);
 
-	nand_release(nand_to_mtd(&tmio->chip));
+	nand_release(nandc_to_mtd(&tmio->chip));
 	tmio_hw_stop(dev, tmio);
 	return 0;
 }
diff --git a/drivers/mtd/nand/raw/txx9ndfmc.c b/drivers/mtd/nand/raw/txx9ndfmc.c
index b567d212fe7d..8f626bec6b47 100644
--- a/drivers/mtd/nand/raw/txx9ndfmc.c
+++ b/drivers/mtd/nand/raw/txx9ndfmc.c
@@ -78,7 +78,7 @@ struct txx9ndfmc_drvdata {
 
 static struct platform_device *mtd_to_platdev(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct txx9ndfmc_priv *txx9_priv = nand_get_controller_data(chip);
 	return txx9_priv->dev;
 }
@@ -134,7 +134,7 @@ static void txx9ndfmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 static void txx9ndfmc_cmd_ctrl(struct mtd_info *mtd, int cmd,
 			       unsigned int ctrl)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct txx9ndfmc_priv *txx9_priv = nand_get_controller_data(chip);
 	struct platform_device *dev = txx9_priv->dev;
 	struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
@@ -174,7 +174,7 @@ static int txx9ndfmc_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
 				   uint8_t *ecc_code)
 {
 	struct platform_device *dev = mtd_to_platdev(mtd);
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	int eccbytes;
 	u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
 
@@ -194,7 +194,7 @@ static int txx9ndfmc_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
 static int txx9ndfmc_correct_data(struct mtd_info *mtd, unsigned char *buf,
 		unsigned char *read_ecc, unsigned char *calc_ecc)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	int eccsize;
 	int corrected = 0;
 	int stat;
@@ -256,7 +256,7 @@ static void txx9ndfmc_initialize(struct platform_device *dev)
 
 static int txx9ndfmc_nand_scan(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	int ret;
 
 	ret = nand_scan_ident(mtd, 1, NULL);
@@ -320,7 +320,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
 		if (!txx9_priv)
 			continue;
 		chip = &txx9_priv->chip;
-		mtd = nand_to_mtd(chip);
+		mtd = nandc_to_mtd(chip);
 		mtd->dev.parent = &dev->dev;
 
 		chip->read_byte = txx9ndfmc_read_byte;
@@ -387,7 +387,7 @@ static int __exit txx9ndfmc_remove(struct platform_device *dev)
 
 		if (!mtd)
 			continue;
-		chip = mtd_to_nand(mtd);
+		chip = mtd_to_nandc(mtd);
 		txx9_priv = nand_get_controller_data(chip);
 
 		nand_release(mtd);
diff --git a/drivers/mtd/nand/raw/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c
index c497b157d56a..42e35040f5d9 100644
--- a/drivers/mtd/nand/raw/vf610_nfc.c
+++ b/drivers/mtd/nand/raw/vf610_nfc.c
@@ -171,7 +171,7 @@ struct vf610_nfc {
 
 static inline struct vf610_nfc *mtd_to_nfc(struct mtd_info *mtd)
 {
-	return container_of(mtd_to_nand(mtd), struct vf610_nfc, chip);
+	return container_of(mtd_to_nandc(mtd), struct vf610_nfc, chip);
 }
 
 static inline u32 vf610_nfc_read(struct vf610_nfc *nfc, uint reg)
@@ -648,7 +648,7 @@ static int vf610_nfc_probe(struct platform_device *pdev)
 
 	nfc->dev = &pdev->dev;
 	chip = &nfc->chip;
-	mtd = nand_to_mtd(chip);
+	mtd = nandc_to_mtd(chip);
 
 	mtd->owner = THIS_MODULE;
 	mtd->dev.parent = nfc->dev;
diff --git a/drivers/mtd/nand/raw/xway_nand.c b/drivers/mtd/nand/raw/xway_nand.c
index 3e7353e76264..fd9d90e43c9c 100644
--- a/drivers/mtd/nand/raw/xway_nand.c
+++ b/drivers/mtd/nand/raw/xway_nand.c
@@ -71,7 +71,7 @@ struct xway_nand_data {
 
 static u8 xway_readb(struct mtd_info *mtd, int op)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct xway_nand_data *data = nand_get_controller_data(chip);
 
 	return readb(data->nandaddr + op);
@@ -79,7 +79,7 @@ static u8 xway_readb(struct mtd_info *mtd, int op)
 
 static void xway_writeb(struct mtd_info *mtd, int op, u8 value)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct xway_nand_data *data = nand_get_controller_data(chip);
 
 	writeb(value, data->nandaddr + op);
@@ -87,7 +87,7 @@ static void xway_writeb(struct mtd_info *mtd, int op, u8 value)
 
 static void xway_select_chip(struct mtd_info *mtd, int select)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct xway_nand_data *data = nand_get_controller_data(chip);
 
 	switch (select) {
@@ -170,7 +170,7 @@ static int xway_nand_probe(struct platform_device *pdev)
 		return PTR_ERR(data->nandaddr);
 
 	nand_set_flash_node(&data->chip, pdev->dev.of_node);
-	mtd = nand_to_mtd(&data->chip);
+	mtd = nandc_to_mtd(&data->chip);
 	mtd->dev.parent = &pdev->dev;
 
 	data->chip.cmd_ctrl = xway_cmd_ctrl;
@@ -223,7 +223,7 @@ static int xway_nand_remove(struct platform_device *pdev)
 {
 	struct xway_nand_data *data = platform_get_drvdata(pdev);
 
-	nand_release(nand_to_mtd(&data->chip));
+	nand_release(nandc_to_mtd(&data->chip));
 
 	return 0;
 }
diff --git a/drivers/staging/mt29f_spinand/mt29f_spinand.c b/drivers/staging/mt29f_spinand/mt29f_spinand.c
index f7f6edf2dda1..a7f104861f82 100644
--- a/drivers/staging/mt29f_spinand/mt29f_spinand.c
+++ b/drivers/staging/mt29f_spinand/mt29f_spinand.c
@@ -31,7 +31,7 @@
 
 static inline struct spinand_state *mtd_to_state(struct mtd_info *mtd)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct spinand_info *info = nand_get_controller_data(chip);
 	struct spinand_state *state = info->priv;
 
@@ -756,7 +756,7 @@ static void spinand_reset(struct spi_device *spi_nand)
 static void spinand_cmdfunc(struct mtd_info *mtd, unsigned int command,
 			    int column, int page)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_chip *chip = mtd_to_nandc(mtd);
 	struct spinand_info *info = nand_get_controller_data(chip);
 	struct spinand_state *state = info->priv;
 
@@ -916,7 +916,7 @@ static int spinand_probe(struct spi_device *spi_nand)
 	chip->options	|= NAND_CACHEPRG;
 	chip->select_chip = spinand_select_chip;
 
-	mtd = nand_to_mtd(chip);
+	mtd = nandc_to_mtd(chip);
 
 	dev_set_drvdata(&spi_nand->dev, mtd);
 
diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
index fecfd05a585a..941218dec463 100644
--- a/include/linux/mtd/rawnand.h
+++ b/include/linux/mtd/rawnand.h
@@ -888,12 +888,12 @@ static inline struct device_node *nand_get_flash_node(struct nand_chip *chip)
 	return mtd_get_of_node(&chip->mtd);
 }
 
-static inline struct nand_chip *mtd_to_nand(struct mtd_info *mtd)
+static inline struct nand_chip *mtd_to_nandc(struct mtd_info *mtd)
 {
 	return container_of(mtd, struct nand_chip, mtd);
 }
 
-static inline struct mtd_info *nand_to_mtd(struct nand_chip *chip)
+static inline struct mtd_info *nandc_to_mtd(struct nand_chip *chip)
 {
 	return &chip->mtd;
 }
diff --git a/include/linux/mtd/sh_flctl.h b/include/linux/mtd/sh_flctl.h
index c759d403cbc0..db51c0b983dd 100644
--- a/include/linux/mtd/sh_flctl.h
+++ b/include/linux/mtd/sh_flctl.h
@@ -186,7 +186,7 @@ struct sh_flctl_platform_data {
 
 static inline struct sh_flctl *mtd_to_flctl(struct mtd_info *mtdinfo)
 {
-	return container_of(mtd_to_nand(mtdinfo), struct sh_flctl, chip);
+	return container_of(mtd_to_nandc(mtdinfo), struct sh_flctl, chip);
 }
 
 #endif	/* __SH_FLCTL_H__ */
-- 
2.7.4



From boris.brezillon at free-electrons.com  Sun Oct 16 08:38:56 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Sun, 16 Oct 2016 17:38:56 +0200
Subject: [PATCH][V2] ubi: fix swapped arguments to call to ubi_alloc_aeb
In-Reply-To: <20161015160011.27600-1-colin.king@canonical.com>
References: <20161015160011.27600-1-colin.king@canonical.com>
Message-ID: <20161016173856.11d486aa@bbrezillon>

On Sat, 15 Oct 2016 17:00:11 +0100
Colin King <colin.king at canonical.com> wrote:

> From: Colin Ian King <colin.king at canonical.com>
> 
> Static analysis by CoverityScan detected the ec and pnum
> arguments are in the wrong order on a call to ubi_alloc_aeb.
> Swap the order to fix this.
> 
> Fixes: 91f4285fe389a27 ("UBI: provide helpers to allocate and free aeb elements")
> Signed-off-by: Colin Ian King <colin.king at canonical.com>

Reviewed-by: Boris Brezillon <boris.brezillon at free-electrons.com>

> ---
>  drivers/mtd/ubi/fastmap.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c
> index d6384d9..4eed546 100644
> --- a/drivers/mtd/ubi/fastmap.c
> +++ b/drivers/mtd/ubi/fastmap.c
> @@ -287,7 +287,7 @@ static int update_vol(struct ubi_device *ubi, struct ubi_attach_info *ai,
>  
>  		/* new_aeb is newer */
>  		if (cmp_res & 1) {
> -			victim = ubi_alloc_aeb(ai, aeb->ec, aeb->pnum);
> +			victim = ubi_alloc_aeb(ai, aeb->pnum, aeb->ec);
>  			if (!victim)
>  				return -ENOMEM;
>  



From boris.brezillon at free-electrons.com  Sun Oct 16 09:24:41 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Sun, 16 Oct 2016 18:24:41 +0200
Subject: [PATCH v2 00/46] Nandsim facelift (part I of II)
In-Reply-To: <cover.1474450295.git.dwalter@sigma-star.at>
References: <cover.1474450295.git.dwalter@sigma-star.at>
Message-ID: <20161016182441.49adc653@bbrezillon>

Daniel, Richard,

On Wed, 21 Sep 2016 11:43:29 +0200
Daniel Walter <dwalter at sigma-star.at> wrote:

> Changes since V1:
>   Incooperate feedback for nand_cleanup()
>   Improve commit messages
> 
> 
> 
> Over a decade ago nandsim was introduced to Linux. The main purpose is having a software implementation of a NAND chip for rapid prototyping systems such as UBI on top of it. On
> the other hand is it also heavily used to load and inspect dumps from real NAND flashes. The current design allows only having a single chip and all parameters are passed as
> modules parameters. Another draw back is that it emulates all NAND chip internals including command parsing, this makes it slow and error prone wrt. changes in nand_base.c since
> the emulated chip is not really ONFI compliant.
> 
> This series addresses the singleton property of nandsim. It allows having multiple instances which can be controlled by a new userspace tool, nandsimctl. Nandsimctl works like
> losetup. You can add and remove instances with different settings.
> To allow multiple instances nandsim offers an ioctl() interface via a new device file, /dev/nandsimctl, to userspace.
> 
> Currently nandsim has two backends, ram and cache. In the default backend mode, ram, all data you change is stored in main memory. For smaller chips this works well but becomes
> problematic when modern multi-gigabyte chips are emulated. Cache mode addresses this drawback and redirects program commands to a local file. Using the cache_file module parameter
> the path of the backing file can be set. When nandsim is not a module passing a file name to it can lead to unexpected behavior since during kernel bootup the real root filesystem
> might not be ready and nandsim will populate the cache file on the initial root filesysem which is either tmpfs or worse a ramfs.
> 
> Via the new ioctl() interface a third backend mode can be used, file mode. File mode works like cache file but all data (including erases and OOB data) are stored on a local file.
> This file can also also be reused later. It is also possible to operate nandsim in a mode to omit existing OOB data and masquerade OOB bytes to 0xFF. This allows using a nanddump
> (without OOB) from a real NAND chip directly in nandsim using the file backend. That way you don't have to use nandwrite or other tools to write the dump into yout MTD before using
> it. You can directly attach the dump in a losetup alike way.
> 
> The ioctl() accepts all existing nandsim parameters except that in cache mode you pass a file descriptor instead of a file name to nandsim. This allows utilizing O_TMPFILE.
> To preserve existing behavior and no breaking any users of nandsim it is still possible to specify all parameters using module parameters but these parameters will only affect the
> first nandsim instance which will be automatically created upon module loading. If you don't have to have a default instance and explicitly create nandsim instances using
> nandsimctl pass defaults=n to the module.
> 
> There will be an additional patch series for mtd-utils containing nandsimctl.
> 
> A side effect of heavily reworking nandsim's backend internals it is now also possible to create custom backends. A custom backed was added to UserModeLinux. It allows directly
> booting from a nanddump using UML such that UBIFS as rootfs can be tested nicely on virtual machines.
> On step ahead for MTD testing.
> 
> The series itself is less straight forward than I wanted it to be, mostly because while adding new features it was needed to cleanup some parts, over and over.
> 
> Part II of that series will address the chip emulation nature of nandsim. It will add a second emulation mode. By default NAND chip emulation will be used but to allow arbitrary
> sized MTDs a more simple mode will be added which just allocates a MTD with the expected sizes instead of mocking nand_base.c.

I really like the new approach for 2 reasons:
1/ it allows creating several NAND devs, and you can do that after the
   module has been loaded.
2/ it fixes the partial NAND detection support by allowing one to
   describe its NAND in term of page size, eraseblock size, oob
   size, ...

But I'm wondering if we should not create a new driver instead of
trying to fix the old one (I must admit I haven't been through the 46
patches of this series, but last time we discussed it on IRC, Richard
said it actually was a complete rewrite of the nandsim driver).

Moreover, if we specify the flash layout manually, maybe we could make
it an mtdsim driver instead of restricting the emulation to NAND
devices.

What do you think?

Regards,

Boris


From geert at linux-m68k.org  Mon Oct 17 01:00:25 2016
From: geert at linux-m68k.org (Geert Uytterhoeven)
Date: Mon, 17 Oct 2016 10:00:25 +0200
Subject: [PATCH] UBI: Fix crash in try_recover_peb()
In-Reply-To: <20161013162458.0219177b@bbrezillon>
References: <1476367536-24782-1-git-send-email-geert@linux-m68k.org>
 <20161013162458.0219177b@bbrezillon>
Message-ID: <CAMuHMdVJJxN2bU6JVsia9uDMonczqMw3SiAu-eygnHVLUqcqMg@mail.gmail.com>

Hi Boris,

On Thu, Oct 13, 2016 at 4:24 PM, Boris Brezillon
<boris.brezillon at free-electrons.com> wrote:
> On Thu, 13 Oct 2016 16:05:36 +0200
> Geert Uytterhoeven <geert at linux-m68k.org> wrote:
>
>>     drivers/mtd/ubi/eba.c: In function ?try_recover_peb?:
>>     drivers/mtd/ubi/eba.c:744: warning: ?vid_hdr? is used uninitialized in this function
>>
>> The pointer vid_hdr is indeed not initialized, leading to a crash when
>> it is dereferenced.
>>
>> Fix this by obtaining the pointer from the VID buffer, like is done
>> everywhere else.
>
> Indeed, I don't know how I missed that one :-/.
>
>>
>> Fixes: 3291b52f9ff0acc8 ("UBI: introduce the VID buffer concept")
>> Signed-off-by: Geert Uytterhoeven <geert at linux-m68k.org>
>
> One minor comment below, otherwise
>
> Reviewed-by: Boris Brezillon <boris.brezillon at free-electrons.com>

Thanks!

>> ---
>> Completely untested. And I know nothing about UBI ;-)
>> ---
>>  drivers/mtd/ubi/eba.c | 1 +
>>  1 file changed, 1 insertion(+)
>>
>> diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
>> index 95c4048a371e87b6..388e46be6ad92805 100644
>> --- a/drivers/mtd/ubi/eba.c
>> +++ b/drivers/mtd/ubi/eba.c
>> @@ -741,6 +741,7 @@ static int try_recover_peb(struct ubi_volume *vol, int pnum, int lnum,
>>               goto out_put;
>>       }
>>
>> +     vid_hdr = ubi_get_vid_hdr(vidb);
>
> Can you move this assignment at variable declaration time?

I can do that. However, that moves the call to ubi_get_vid_hdr() _before_
the call to ubi_io_read_vid_hdr().

While that would still work (ubi_get_vid_hdr() would just return a pointer to
the not-yet-read data), I think it's better to not move it, to prevent people
from accidentally trying to use it before the data has been read.

Do you agree?

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds


From geert at linux-m68k.org  Mon Oct 17 01:00:39 2016
From: geert at linux-m68k.org (Geert Uytterhoeven)
Date: Mon, 17 Oct 2016 10:00:39 +0200
Subject: [PATCH] UBI: Fix crash in try_recover_peb()
In-Reply-To: <20161014124928.5a27ed59@bbrezillon>
References: <1476367536-24782-1-git-send-email-geert@linux-m68k.org>
 <20161013162458.0219177b@bbrezillon> <20161014124928.5a27ed59@bbrezillon>
Message-ID: <CAMuHMdXExe_vUuiuB76Vn-oWVDcdz_gS36M6BVgR5JY--0Uk5Q@mail.gmail.com>

Hi Boris,

On Fri, Oct 14, 2016 at 12:49 PM, Boris Brezillon
<boris.brezillon at free-electrons.com> wrote:
> On Thu, 13 Oct 2016 16:24:58 +0200
> Boris Brezillon <boris.brezillon at free-electrons.com> wrote:
>> On Thu, 13 Oct 2016 16:05:36 +0200
>> Geert Uytterhoeven <geert at linux-m68k.org> wrote:
>>
>> >     drivers/mtd/ubi/eba.c: In function ?try_recover_peb?:
>> >     drivers/mtd/ubi/eba.c:744: warning: ?vid_hdr? is used uninitialized in this function
>> >
>> > The pointer vid_hdr is indeed not initialized, leading to a crash when
>> > it is dereferenced.
>> >
>> > Fix this by obtaining the pointer from the VID buffer, like is done
>> > everywhere else.
>>
>> Indeed, I don't know how I missed that one :-/.
>
> That's really weird. I tried to recompile the kernel on my machine
> (before applying your patch), to see if the compiler was complaining,
> and it's not :-(.
>
> I also coded simple functions with goto statements, to check that the
> detection was working correctly, and it is.
>
> Maybe you have some ideas why my compiler is failing to detect the
> problem (I'm currently using the ubuntu cross-toolchain:
> 'arm-linux-gnueabi-gcc (Ubuntu/Linaro 5.4.0-6ubuntu1~16.04.1) 5.4.0
> 20160609').

It depends highly on the toolchain.

My good old m68k-linux-gnu-gcc version 4.1.2 20061115 (prerelease) (Ubuntu
4.1.1-21) is known to generate plenty of warnings like these. Due to the high
percentage of false positives, this was disabled in later versions of gcc, but
(partially) re-enabled later (usually Arnd catches most of these while stll in
-next. I'm afraid he's suffering from travelling to Linaro Connect ;-)
Still, some of them are real bugs, so that's when my patch habits kick in...

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds


From boris.brezillon at free-electrons.com  Mon Oct 17 04:02:18 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Mon, 17 Oct 2016 13:02:18 +0200
Subject: [PATCH] UBI: Fix crash in try_recover_peb()
In-Reply-To: <CAMuHMdVJJxN2bU6JVsia9uDMonczqMw3SiAu-eygnHVLUqcqMg@mail.gmail.com>
References: <1476367536-24782-1-git-send-email-geert@linux-m68k.org>
 <20161013162458.0219177b@bbrezillon>
 <CAMuHMdVJJxN2bU6JVsia9uDMonczqMw3SiAu-eygnHVLUqcqMg@mail.gmail.com>
Message-ID: <20161017130218.1d2e19e3@bbrezillon>

On Mon, 17 Oct 2016 10:00:25 +0200
Geert Uytterhoeven <geert at linux-m68k.org> wrote:

> Hi Boris,
> 
> On Thu, Oct 13, 2016 at 4:24 PM, Boris Brezillon
> <boris.brezillon at free-electrons.com> wrote:
> > On Thu, 13 Oct 2016 16:05:36 +0200
> > Geert Uytterhoeven <geert at linux-m68k.org> wrote:
> >  
> >>     drivers/mtd/ubi/eba.c: In function ?try_recover_peb?:
> >>     drivers/mtd/ubi/eba.c:744: warning: ?vid_hdr? is used uninitialized in this function
> >>
> >> The pointer vid_hdr is indeed not initialized, leading to a crash when
> >> it is dereferenced.
> >>
> >> Fix this by obtaining the pointer from the VID buffer, like is done
> >> everywhere else.  
> >
> > Indeed, I don't know how I missed that one :-/.
> >  
> >>
> >> Fixes: 3291b52f9ff0acc8 ("UBI: introduce the VID buffer concept")
> >> Signed-off-by: Geert Uytterhoeven <geert at linux-m68k.org>  
> >
> > One minor comment below, otherwise
> >
> > Reviewed-by: Boris Brezillon <boris.brezillon at free-electrons.com>  
> 
> Thanks!
> 
> >> ---
> >> Completely untested. And I know nothing about UBI ;-)
> >> ---
> >>  drivers/mtd/ubi/eba.c | 1 +
> >>  1 file changed, 1 insertion(+)
> >>
> >> diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
> >> index 95c4048a371e87b6..388e46be6ad92805 100644
> >> --- a/drivers/mtd/ubi/eba.c
> >> +++ b/drivers/mtd/ubi/eba.c
> >> @@ -741,6 +741,7 @@ static int try_recover_peb(struct ubi_volume *vol, int pnum, int lnum,
> >>               goto out_put;
> >>       }
> >>
> >> +     vid_hdr = ubi_get_vid_hdr(vidb);  
> >
> > Can you move this assignment at variable declaration time?  
> 
> I can do that. However, that moves the call to ubi_get_vid_hdr() _before_
> the call to ubi_io_read_vid_hdr().
> 
> While that would still work (ubi_get_vid_hdr() would just return a pointer to
> the not-yet-read data), I think it's better to not move it, to prevent people
> from accidentally trying to use it before the data has been read.

Well, maybe. I just thought it would be safer to assign it as early as
possible to avoid another 'uninitialized var' bug if move code around
again (which will happen soon ;-)).

Anyway, it's not that important, I'll let Richard take the version
he prefers.

Thanks again for the fix.

Boris


From geert at linux-m68k.org  Mon Oct 17 04:10:55 2016
From: geert at linux-m68k.org (Geert Uytterhoeven)
Date: Mon, 17 Oct 2016 13:10:55 +0200
Subject: [PATCH] UBI: Fix crash in try_recover_peb()
In-Reply-To: <20161017130218.1d2e19e3@bbrezillon>
References: <1476367536-24782-1-git-send-email-geert@linux-m68k.org>
 <20161013162458.0219177b@bbrezillon>
 <CAMuHMdVJJxN2bU6JVsia9uDMonczqMw3SiAu-eygnHVLUqcqMg@mail.gmail.com>
 <20161017130218.1d2e19e3@bbrezillon>
Message-ID: <CAMuHMdX+2TG8STTJJH9FTTN_hOXYgV4H2TaBOxo+nVeUZL+aug@mail.gmail.com>

Hi Boris,

On Mon, Oct 17, 2016 at 1:02 PM, Boris Brezillon
<boris.brezillon at free-electrons.com> wrote:
> On Mon, 17 Oct 2016 10:00:25 +0200
> Geert Uytterhoeven <geert at linux-m68k.org> wrote:
>> On Thu, Oct 13, 2016 at 4:24 PM, Boris Brezillon
>> <boris.brezillon at free-electrons.com> wrote:
>> > On Thu, 13 Oct 2016 16:05:36 +0200
>> > Geert Uytterhoeven <geert at linux-m68k.org> wrote:
>> >
>> >>     drivers/mtd/ubi/eba.c: In function ?try_recover_peb?:
>> >>     drivers/mtd/ubi/eba.c:744: warning: ?vid_hdr? is used uninitialized in this function
>> >>
>> >> The pointer vid_hdr is indeed not initialized, leading to a crash when
>> >> it is dereferenced.
>> >>
>> >> Fix this by obtaining the pointer from the VID buffer, like is done
>> >> everywhere else.
>> >
>> > Indeed, I don't know how I missed that one :-/.
>> >
>> >>
>> >> Fixes: 3291b52f9ff0acc8 ("UBI: introduce the VID buffer concept")
>> >> Signed-off-by: Geert Uytterhoeven <geert at linux-m68k.org>
>> >
>> > One minor comment below, otherwise
>> >
>> > Reviewed-by: Boris Brezillon <boris.brezillon at free-electrons.com>
>>
>> Thanks!
>>
>> >> ---
>> >> Completely untested. And I know nothing about UBI ;-)
>> >> ---
>> >>  drivers/mtd/ubi/eba.c | 1 +
>> >>  1 file changed, 1 insertion(+)
>> >>
>> >> diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
>> >> index 95c4048a371e87b6..388e46be6ad92805 100644
>> >> --- a/drivers/mtd/ubi/eba.c
>> >> +++ b/drivers/mtd/ubi/eba.c
>> >> @@ -741,6 +741,7 @@ static int try_recover_peb(struct ubi_volume *vol, int pnum, int lnum,
>> >>               goto out_put;
>> >>       }
>> >>
>> >> +     vid_hdr = ubi_get_vid_hdr(vidb);
>> >
>> > Can you move this assignment at variable declaration time?
>>
>> I can do that. However, that moves the call to ubi_get_vid_hdr() _before_
>> the call to ubi_io_read_vid_hdr().
>>
>> While that would still work (ubi_get_vid_hdr() would just return a pointer to
>> the not-yet-read data), I think it's better to not move it, to prevent people
>> from accidentally trying to use it before the data has been read.
>
> Well, maybe. I just thought it would be safer to assign it as early as
> possible to avoid another 'uninitialized var' bug if move code around
> again (which will happen soon ;-)).

I prefer seeing the warning again (I _will_ notice if it pops up again!) over
failing at runtime because the data structure it points to hasn't been
initialized yet, which the compiler can't warn me about...

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds


From mika.westerberg at linux.intel.com  Mon Oct 17 07:58:57 2016
From: mika.westerberg at linux.intel.com (Mika Westerberg)
Date: Mon, 17 Oct 2016 17:58:57 +0300
Subject: [PATCH v4 2/3] mfd: lpc_ich: Add support for SPI serial flash host
 controller
In-Reply-To: <20161017145858.143771-1-mika.westerberg@linux.intel.com>
References: <20161017145858.143771-1-mika.westerberg@linux.intel.com>
Message-ID: <20161017145858.143771-3-mika.westerberg@linux.intel.com>

Many Intel CPUs including Haswell, Broadwell and Baytrail have SPI serial
flash host controller as part of the LPC device. This will populate an MFD
cell suitable for the SPI host controller driver if we know that the LPC
device has one.

Signed-off-by: Mika Westerberg <mika.westerberg at linux.intel.com>
Acked-by: Lee Jones <lee.jones at linaro.org>
---
 drivers/mfd/lpc_ich.c       | 92 +++++++++++++++++++++++++++++++++++++++++++++
 include/linux/mfd/lpc_ich.h |  3 ++
 2 files changed, 95 insertions(+)

diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c
index c8dee47b45d9..985bda575849 100644
--- a/drivers/mfd/lpc_ich.c
+++ b/drivers/mfd/lpc_ich.c
@@ -83,6 +83,15 @@
 #define ACPIBASE_GCS_OFF	0x3410
 #define ACPIBASE_GCS_END	0x3414
 
+#define SPIBASE_BYT		0x54
+#define SPIBASE_BYT_SZ		512
+#define SPIBASE_BYT_EN		BIT(1)
+
+#define SPIBASE_LPT		0x3800
+#define SPIBASE_LPT_SZ		512
+#define BCR			0xdc
+#define BCR_WPD			BIT(0)
+
 #define GPIOBASE_ICH0		0x58
 #define GPIOCTRL_ICH0		0x5C
 #define GPIOBASE_ICH6		0x48
@@ -133,6 +142,12 @@ static struct resource gpio_ich_res[] = {
 	},
 };
 
+static struct resource intel_spi_res[] = {
+	{
+		.flags = IORESOURCE_MEM,
+	}
+};
+
 static struct mfd_cell lpc_ich_wdt_cell = {
 	.name = "iTCO_wdt",
 	.num_resources = ARRAY_SIZE(wdt_ich_res),
@@ -147,6 +162,14 @@ static struct mfd_cell lpc_ich_gpio_cell = {
 	.ignore_resource_conflicts = true,
 };
 
+
+static struct mfd_cell lpc_ich_spi_cell = {
+	.name = "intel-spi",
+	.num_resources = ARRAY_SIZE(intel_spi_res),
+	.resources = intel_spi_res,
+	.ignore_resource_conflicts = true,
+};
+
 /* chipset related info */
 enum lpc_chipsets {
 	LPC_ICH = 0,	/* ICH */
@@ -493,10 +516,12 @@ static struct lpc_ich_info lpc_chipset_info[] = {
 	[LPC_LPT] = {
 		.name = "Lynx Point",
 		.iTCO_version = 2,
+		.spi_type = INTEL_SPI_LPT,
 	},
 	[LPC_LPT_LP] = {
 		.name = "Lynx Point_LP",
 		.iTCO_version = 2,
+		.spi_type = INTEL_SPI_LPT,
 	},
 	[LPC_WBG] = {
 		.name = "Wellsburg",
@@ -510,6 +535,7 @@ static struct lpc_ich_info lpc_chipset_info[] = {
 	[LPC_BAYTRAIL] = {
 		.name = "Bay Trail SoC",
 		.iTCO_version = 3,
+		.spi_type = INTEL_SPI_BYT,
 	},
 	[LPC_COLETO] = {
 		.name = "Coleto Creek",
@@ -518,10 +544,12 @@ static struct lpc_ich_info lpc_chipset_info[] = {
 	[LPC_WPT_LP] = {
 		.name = "Wildcat Point_LP",
 		.iTCO_version = 2,
+		.spi_type = INTEL_SPI_LPT,
 	},
 	[LPC_BRASWELL] = {
 		.name = "Braswell SoC",
 		.iTCO_version = 3,
+		.spi_type = INTEL_SPI_BYT,
 	},
 	[LPC_LEWISBURG] = {
 		.name = "Lewisburg",
@@ -1054,6 +1082,64 @@ static int lpc_ich_init_wdt(struct pci_dev *dev)
 	return ret;
 }
 
+static int lpc_ich_init_spi(struct pci_dev *dev)
+{
+	struct lpc_ich_priv *priv = pci_get_drvdata(dev);
+	struct resource *res = &intel_spi_res[0];
+	struct intel_spi_boardinfo *info;
+	u32 spi_base, rcba, bcr;
+
+	info = devm_kzalloc(&dev->dev, sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->type = lpc_chipset_info[priv->chipset].spi_type;
+
+	switch (info->type) {
+	case INTEL_SPI_BYT:
+		pci_read_config_dword(dev, SPIBASE_BYT, &spi_base);
+		if (spi_base & SPIBASE_BYT_EN) {
+			res->start = spi_base & ~(SPIBASE_BYT_SZ - 1);
+			res->end = res->start + SPIBASE_BYT_SZ - 1;
+		}
+		break;
+
+	case INTEL_SPI_LPT:
+		pci_read_config_dword(dev, RCBABASE, &rcba);
+		if (rcba & 1) {
+			spi_base = rcba & ~(SPIBASE_LPT_SZ - 1);
+			res->start = spi_base + SPIBASE_LPT;
+			res->end = res->start + SPIBASE_LPT_SZ - 1;
+
+			/*
+			 * Try to make the flash chip writeable now by
+			 * setting BCR_WPD. It it fails we tell the driver
+			 * that it can only read the chip.
+			 */
+			pci_read_config_dword(dev, BCR, &bcr);
+			if (!(bcr & BCR_WPD)) {
+				bcr |= BCR_WPD;
+				pci_write_config_dword(dev, BCR, bcr);
+				pci_read_config_dword(dev, BCR, &bcr);
+			}
+			info->writeable = !!(bcr & BCR_WPD);
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (!res->start)
+		return -ENODEV;
+
+	lpc_ich_spi_cell.platform_data = info;
+	lpc_ich_spi_cell.pdata_size = sizeof(*info);
+
+	return mfd_add_devices(&dev->dev, PLATFORM_DEVID_NONE,
+			       &lpc_ich_spi_cell, 1, NULL, 0, NULL);
+}
+
 static int lpc_ich_probe(struct pci_dev *dev,
 				const struct pci_device_id *id)
 {
@@ -1097,6 +1183,12 @@ static int lpc_ich_probe(struct pci_dev *dev,
 			cell_added = true;
 	}
 
+	if (lpc_chipset_info[priv->chipset].spi_type) {
+		ret = lpc_ich_init_spi(dev);
+		if (!ret)
+			cell_added = true;
+	}
+
 	/*
 	 * We only care if at least one or none of the cells registered
 	 * successfully.
diff --git a/include/linux/mfd/lpc_ich.h b/include/linux/mfd/lpc_ich.h
index 2b300b44f994..fba8fcb54f8c 100644
--- a/include/linux/mfd/lpc_ich.h
+++ b/include/linux/mfd/lpc_ich.h
@@ -20,6 +20,8 @@
 #ifndef LPC_ICH_H
 #define LPC_ICH_H
 
+#include <linux/platform_data/intel-spi.h>
+
 /* GPIO resources */
 #define ICH_RES_GPIO	0
 #define ICH_RES_GPE0	1
@@ -40,6 +42,7 @@ struct lpc_ich_info {
 	char name[32];
 	unsigned int iTCO_version;
 	unsigned int gpio_version;
+	enum intel_spi_type spi_type;
 	u8 use_gpio;
 };
 
-- 
2.9.3



From mika.westerberg at linux.intel.com  Mon Oct 17 07:58:55 2016
From: mika.westerberg at linux.intel.com (Mika Westerberg)
Date: Mon, 17 Oct 2016 17:58:55 +0300
Subject: [PATCH v4 0/3] spi-nor: Add support for Intel SPI serial flash
 controller
Message-ID: <20161017145858.143771-1-mika.westerberg@linux.intel.com>

This is fourth version of the series. Previous versions can be found:

  v3: https://lwn.net/Articles/697231/
  v2: http://lists.infradead.org/pipermail/linux-mtd/2016-June/068277.html
  v1: https://lkml.org/lkml/2016/6/14/269

This patch series adds support for the Intel SPI serial flash controller
found on many recent Intel CPUs including Baytrail and Braswell. This
driver makes it possible to access the BIOS and other platform data which
is stored on the SPI serial flash. It is also possible to upgrade the BIOS
using this driver if it has not been protected by special hardware bits.

The patch [1/3] includes documentation how to upgrade BIOS on MinnowBoard
MAX.

Since poking the SPI serial flash can brick the machine, this driver can
only be enabled when CONFIG_EXPERT=y and even then it will remain read-only
unless instructed othwerwise by module parameter.

This missed v4.8 and v4.9 so it would be really nice to get it finally
included in v4.10.

Changes from v3:

[1/3] spi-nor: Add support for Intel SPI serial flash controller
  
  * No changes

[2/3] mfd: lpc_ich: Add support for SPI serial flash host controller

  * Added ACK from Lee Jones.

[3/3] mfd: lpc_ich: Add support for Intel Apollo Lake SoC
   
  * Use bus instead of dev->bus in PCI accesses
  * Added ACK from Lee Jones.

Changes from v2:

  * Rebased on top of v4.8-rc2

  * Updated intel_spi_read/write() according spi-nor core changes which
    drops retlen parameter and returns number of bytes read/written.

Changes from v1:

[1/3] spi-nor: Add support for Intel SPI serial flash controller

  * Older hardware does not support 64k erase command so added erase_64k
    flag which is set only for Broxton (BXT).

  * Fix protection range offset for Broxton. Now there is ispi->pregs
    pointing to the start of the protection registers.

  * Change naming of constants from BCR_BYT -> BYT_BCR and so on.

[2/3] mfd: lpc_ich: Add support for SPI serial flash host controller

  * Drop lpc_ich_finalize_spi_cell() and initialize cell directly in
    lpc_ich_init_spi().

  * Use info->type in switch in lpc_ich_init_spi().

  * Add defines for magic numbers used in lpc_ich_init_spi().

  * Use PLATFORM_DEVID_NONE with mfd_add_devices().

[3/3] mfd: lpc_ich: Add support for Intel Apollo Lake SoC

  * No changes

Mika Westerberg (3):
  spi-nor: Add support for Intel SPI serial flash controller
  mfd: lpc_ich: Add support for SPI serial flash host controller
  mfd: lpc_ich: Add support for Intel Apollo Lake SoC

 Documentation/mtd/intel-spi.txt          |  88 ++++
 drivers/mfd/lpc_ich.c                    | 131 ++++++
 drivers/mtd/spi-nor/Kconfig              |  20 +
 drivers/mtd/spi-nor/Makefile             |   2 +
 drivers/mtd/spi-nor/intel-spi-platform.c |  57 +++
 drivers/mtd/spi-nor/intel-spi.c          | 780 +++++++++++++++++++++++++++++++
 drivers/mtd/spi-nor/intel-spi.h          |  24 +
 include/linux/mfd/lpc_ich.h              |   3 +
 include/linux/platform_data/intel-spi.h  |  31 ++
 9 files changed, 1136 insertions(+)
 create mode 100644 Documentation/mtd/intel-spi.txt
 create mode 100644 drivers/mtd/spi-nor/intel-spi-platform.c
 create mode 100644 drivers/mtd/spi-nor/intel-spi.c
 create mode 100644 drivers/mtd/spi-nor/intel-spi.h
 create mode 100644 include/linux/platform_data/intel-spi.h

-- 
2.9.3



From mika.westerberg at linux.intel.com  Mon Oct 17 07:58:56 2016
From: mika.westerberg at linux.intel.com (Mika Westerberg)
Date: Mon, 17 Oct 2016 17:58:56 +0300
Subject: [PATCH v4 1/3] spi-nor: Add support for Intel SPI serial flash
 controller
In-Reply-To: <20161017145858.143771-1-mika.westerberg@linux.intel.com>
References: <20161017145858.143771-1-mika.westerberg@linux.intel.com>
Message-ID: <20161017145858.143771-2-mika.westerberg@linux.intel.com>

Add support for the SPI serial flash host controller found on many Intel
CPUs including Baytrail and Braswell. The SPI serial flash controller is
used to access BIOS and other platform specific information. By default the
driver exposes a single read-only MTD device but with a module parameter
"writeable=1" the MTD device can be made read-write which makes it possible
to upgrade BIOS directly from Linux.

Signed-off-by: Mika Westerberg <mika.westerberg at linux.intel.com>
---
 Documentation/mtd/intel-spi.txt          |  88 ++++
 drivers/mtd/spi-nor/Kconfig              |  20 +
 drivers/mtd/spi-nor/Makefile             |   2 +
 drivers/mtd/spi-nor/intel-spi-platform.c |  57 +++
 drivers/mtd/spi-nor/intel-spi.c          | 780 +++++++++++++++++++++++++++++++
 drivers/mtd/spi-nor/intel-spi.h          |  24 +
 include/linux/platform_data/intel-spi.h  |  31 ++
 7 files changed, 1002 insertions(+)
 create mode 100644 Documentation/mtd/intel-spi.txt
 create mode 100644 drivers/mtd/spi-nor/intel-spi-platform.c
 create mode 100644 drivers/mtd/spi-nor/intel-spi.c
 create mode 100644 drivers/mtd/spi-nor/intel-spi.h
 create mode 100644 include/linux/platform_data/intel-spi.h

diff --git a/Documentation/mtd/intel-spi.txt b/Documentation/mtd/intel-spi.txt
new file mode 100644
index 000000000000..bc357729c2cb
--- /dev/null
+++ b/Documentation/mtd/intel-spi.txt
@@ -0,0 +1,88 @@
+Upgrading BIOS using intel-spi
+------------------------------
+
+Many Intel CPUs like Baytrail and Braswell include SPI serial flash host
+controller which is used to hold BIOS and other platform specific data.
+Since contents of the SPI serial flash is crucial for machine to function,
+it is typically protected by different hardware protection mechanisms to
+avoid accidental (or on purpose) overwrite of the content.
+
+Not all manufacturers protect the SPI serial flash, mainly because it
+allows upgrading the BIOS image directly from an OS.
+
+The intel-spi driver makes it possible to read and write the SPI serial
+flash, if certain protection bits are not set and locked. If it finds
+any of them set, the whole MTD device is made read-only to prevent
+partial overwrites. By default the driver exposes SPI serial flash
+contents as read-only but it can be changed from kernel command line,
+passing "intel-spi.writeable=1".
+
+Please keep in mind that overwriting the BIOS image on SPI serial flash
+might render the machine unbootable and requires special equipment like
+Dediprog to revive. You have been warned!
+
+Below are the steps how to upgrade MinnowBoard MAX BIOS directly from
+Linux.
+
+ 1) Download and extract the latest Minnowboard MAX BIOS SPI image
+    [1]. At the time writing this the latest image is v92.
+
+ 2) Install mtd-utils package [2]. We need this in order to erase the SPI
+    serial flash. Distros like Debian and Fedora have this prepackaged with
+    name "mtd-utils".
+
+ 3) Add "intel-spi.writeable=1" to the kernel command line and reboot
+    the board (you can also reload the driver passing "writeable=1" as
+    module parameter to modprobe).
+
+ 4) Once the board is up and running again, find the right MTD partition
+    (it is named as "BIOS"):
+
+    # cat /proc/mtd
+    dev:    size   erasesize  name
+    mtd0: 00800000 00001000 "BIOS"
+
+    So here it will be /dev/mtd0 but it may vary.
+
+ 5) Make backup of the existing image first:
+
+    # dd if=/dev/mtd0ro of=bios.bak
+    16384+0 records in
+    16384+0 records out
+    8388608 bytes (8.4 MB) copied, 10.0269 s, 837 kB/s
+
+ 6) Verify the backup
+
+    # sha1sum /dev/mtd0ro bios.bak
+    fdbb011920572ca6c991377c4b418a0502668b73  /dev/mtd0ro
+    fdbb011920572ca6c991377c4b418a0502668b73  bios.bak
+
+    The SHA1 sums must match. Otherwise do not continue any further!
+
+ 7) Erase the SPI serial flash. After this step, do not reboot the
+    board! Otherwise it will not start anymore.
+
+    # flash_erase /dev/mtd0 0 0
+    Erasing 4 Kibyte @ 7ff000 -- 100 % complete
+
+ 8) Once completed without errors you can write the new BIOS image:
+
+    # dd if=MNW2MAX1.X64.0092.R01.1605221712.bin of=/dev/mtd0
+
+ 9) Verify that the new content of the SPI serial flash matches the new
+    BIOS image:
+
+    # sha1sum /dev/mtd0ro MNW2MAX1.X64.0092.R01.1605221712.bin
+    9b4df9e4be2057fceec3a5529ec3d950836c87a2  /dev/mtd0ro
+    9b4df9e4be2057fceec3a5529ec3d950836c87a2 MNW2MAX1.X64.0092.R01.1605221712.bin
+
+    The SHA1 sums should match.
+
+ 10) Now you can reboot your board and observe the new BIOS starting up
+     properly.
+
+References
+----------
+
+[1] https://firmware.intel.com/sites/default/files/MinnowBoard.MAX_.X64.92.R01.zip
+[2] http://www.linux-mtd.infradead.org/
diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
index 4a682ee0f632..02013ffa5231 100644
--- a/drivers/mtd/spi-nor/Kconfig
+++ b/drivers/mtd/spi-nor/Kconfig
@@ -76,4 +76,24 @@ config SPI_NXP_SPIFI
 	  Flash. Enable this option if you have a device with a SPIFI
 	  controller and want to access the Flash as a mtd device.
 
+config SPI_INTEL_SPI
+	tristate
+
+config SPI_INTEL_SPI_PLATFORM
+	tristate "Intel PCH/PCU SPI flash platform driver" if EXPERT
+	depends on X86
+	select SPI_INTEL_SPI
+	help
+	  This enables platform support for the Intel PCH/PCU SPI
+	  controller in master mode. This controller is present in modern
+	  Intel hardware and is used to hold BIOS and other persistent
+	  settings. Using this driver it is possible to upgrade BIOS
+	  directly from Linux.
+
+	  Say N here unless you know what you are doing. Overwriting the
+	  SPI flash may render the system unbootable.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called intel-spi-platform.
+
 endif # MTD_SPI_NOR
diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile
index 121695e83542..1796e8cd6e1a 100644
--- a/drivers/mtd/spi-nor/Makefile
+++ b/drivers/mtd/spi-nor/Makefile
@@ -5,3 +5,5 @@ obj-$(CONFIG_SPI_FSL_QUADSPI)	+= fsl-quadspi.o
 obj-$(CONFIG_SPI_HISI_SFC)	+= hisi-sfc.o
 obj-$(CONFIG_MTD_MT81xx_NOR)    += mtk-quadspi.o
 obj-$(CONFIG_SPI_NXP_SPIFI)	+= nxp-spifi.o
+obj-$(CONFIG_SPI_INTEL_SPI)	+= intel-spi.o
+obj-$(CONFIG_SPI_INTEL_SPI_PLATFORM)	+= intel-spi-platform.o
diff --git a/drivers/mtd/spi-nor/intel-spi-platform.c b/drivers/mtd/spi-nor/intel-spi-platform.c
new file mode 100644
index 000000000000..5c943df9398f
--- /dev/null
+++ b/drivers/mtd/spi-nor/intel-spi-platform.c
@@ -0,0 +1,57 @@
+/*
+ * Intel PCH/PCU SPI flash platform driver.
+ *
+ * Copyright (C) 2016, Intel Corporation
+ * Author: Mika Westerberg <mika.westerberg at linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "intel-spi.h"
+
+static int intel_spi_platform_probe(struct platform_device *pdev)
+{
+	struct intel_spi_boardinfo *info;
+	struct intel_spi *ispi;
+	struct resource *mem;
+
+	info = dev_get_platdata(&pdev->dev);
+	if (!info)
+		return -EINVAL;
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	ispi = intel_spi_probe(&pdev->dev, mem, info);
+	if (IS_ERR(ispi))
+		return PTR_ERR(ispi);
+
+	platform_set_drvdata(pdev, ispi);
+	return 0;
+}
+
+static int intel_spi_platform_remove(struct platform_device *pdev)
+{
+	struct intel_spi *ispi = platform_get_drvdata(pdev);
+
+	return intel_spi_remove(ispi);
+}
+
+static struct platform_driver intel_spi_platform_driver = {
+	.probe = intel_spi_platform_probe,
+	.remove = intel_spi_platform_remove,
+	.driver = {
+		.name = "intel-spi",
+	},
+};
+
+module_platform_driver(intel_spi_platform_driver);
+
+MODULE_DESCRIPTION("Intel PCH/PCU SPI flash platform driver");
+MODULE_AUTHOR("Mika Westerberg <mika.westerberg at linux.intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:intel-spi");
diff --git a/drivers/mtd/spi-nor/intel-spi.c b/drivers/mtd/spi-nor/intel-spi.c
new file mode 100644
index 000000000000..ded613bff1ab
--- /dev/null
+++ b/drivers/mtd/spi-nor/intel-spi.c
@@ -0,0 +1,780 @@
+/*
+ * Intel PCH/PCU SPI flash driver.
+ *
+ * Copyright (C) 2016, Intel Corporation
+ * Author: Mika Westerberg <mika.westerberg at linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/sizes.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/spi-nor.h>
+#include <linux/platform_data/intel-spi.h>
+
+#include "intel-spi.h"
+
+/* Offsets are from @ispi->base */
+#define BFPREG				0x00
+
+#define HSFSTS_CTL			0x04
+#define HSFSTS_CTL_FSMIE		BIT(31)
+#define HSFSTS_CTL_FDBC_SHIFT		24
+#define HSFSTS_CTL_FDBC_MASK		(0x3f << HSFSTS_CTL_FDBC_SHIFT)
+
+#define HSFSTS_CTL_FCYCLE_SHIFT		17
+#define HSFSTS_CTL_FCYCLE_MASK		(0x0f << HSFSTS_CTL_FCYCLE_SHIFT)
+/* HW sequencer opcodes */
+#define HSFSTS_CTL_FCYCLE_READ		(0x00 << HSFSTS_CTL_FCYCLE_SHIFT)
+#define HSFSTS_CTL_FCYCLE_WRITE		(0x02 << HSFSTS_CTL_FCYCLE_SHIFT)
+#define HSFSTS_CTL_FCYCLE_ERASE		(0x03 << HSFSTS_CTL_FCYCLE_SHIFT)
+#define HSFSTS_CTL_FCYCLE_ERASE_64K	(0x04 << HSFSTS_CTL_FCYCLE_SHIFT)
+#define HSFSTS_CTL_FCYCLE_RDID		(0x06 << HSFSTS_CTL_FCYCLE_SHIFT)
+#define HSFSTS_CTL_FCYCLE_WRSR		(0x07 << HSFSTS_CTL_FCYCLE_SHIFT)
+#define HSFSTS_CTL_FCYCLE_RDSR		(0x08 << HSFSTS_CTL_FCYCLE_SHIFT)
+
+#define HSFSTS_CTL_FGO			BIT(16)
+#define HSFSTS_CTL_FLOCKDN		BIT(15)
+#define HSFSTS_CTL_FDV			BIT(14)
+#define HSFSTS_CTL_SCIP			BIT(5)
+#define HSFSTS_CTL_AEL			BIT(2)
+#define HSFSTS_CTL_FCERR		BIT(1)
+#define HSFSTS_CTL_FDONE		BIT(0)
+
+#define FADDR				0x08
+#define DLOCK				0x0c
+#define FDATA(n)			(0x10 + ((n) * 4))
+
+#define FRACC				0x50
+
+#define FREG(n)				(0x54 + ((n) * 4))
+#define FREG_BASE_MASK			0x3fff
+#define FREG_LIMIT_SHIFT		16
+#define FREG_LIMIT_MASK			(0x03fff << FREG_LIMIT_SHIFT)
+
+/* Offset is from @ispi->pregs */
+#define PR(n)				((n) * 4)
+#define PR_WPE				BIT(31)
+#define PR_LIMIT_SHIFT			16
+#define PR_LIMIT_MASK			(0x3fff << PR_LIMIT_SHIFT)
+#define PR_RPE				BIT(15)
+#define PR_BASE_MASK			0x3fff
+/* Last PR is GPR0 */
+#define PR_NUM				(5 + 1)
+
+/* Offsets are from @ispi->sregs */
+#define SSFSTS_CTL			0x00
+#define SSFSTS_CTL_FSMIE		BIT(23)
+#define SSFSTS_CTL_DS			BIT(22)
+#define SSFSTS_CTL_DBC_SHIFT		16
+#define SSFSTS_CTL_SPOP			BIT(11)
+#define SSFSTS_CTL_ACS			BIT(10)
+#define SSFSTS_CTL_SCGO			BIT(9)
+#define SSFSTS_CTL_COP_SHIFT		12
+#define SSFSTS_CTL_FRS			BIT(7)
+#define SSFSTS_CTL_DOFRS		BIT(6)
+#define SSFSTS_CTL_AEL			BIT(4)
+#define SSFSTS_CTL_FCERR		BIT(3)
+#define SSFSTS_CTL_FDONE		BIT(2)
+#define SSFSTS_CTL_SCIP			BIT(0)
+
+#define PREOP_OPTYPE			0x04
+#define OPMENU0				0x08
+#define OPMENU1				0x0c
+
+/* CPU specifics */
+#define BYT_PR				0x74
+#define BYT_SSFSTS_CTL			0x90
+#define BYT_BCR				0xfc
+#define BYT_BCR_WPD			BIT(0)
+#define BYT_FREG_NUM			5
+
+#define LPT_PR				0x74
+#define LPT_SSFSTS_CTL			0x90
+#define LPT_FREG_NUM			5
+
+#define BXT_PR				0x84
+#define BXT_SSFSTS_CTL			0xa0
+#define BXT_FREG_NUM			12
+
+#define INTEL_SPI_TIMEOUT		5000 /* ms */
+
+/**
+ * struct intel_spi - Driver private data
+ * @dev: Device pointer
+ * @info: Pointer to board specific info
+ * @nor: SPI NOR layer structure
+ * @base: Beginning of MMIO space
+ * @pregs: Start of protection registers
+ * @sregs: Start of software sequencer registers
+ * @nregions: Maximum number of regions
+ * @writeable: Is the chip writeable
+ * @swseq: Use SW sequencer in register reads/writes
+ * @erase_64k: 64k erase supported
+ * @opcodes: Opcodes which are supported. This are programmed by BIOS
+ *           before it locks down the controller.
+ * @preopcodes: Preopcodes which are supported.
+ */
+struct intel_spi {
+	struct device *dev;
+	const struct intel_spi_boardinfo *info;
+	struct spi_nor nor;
+	void __iomem *base;
+	void __iomem *pregs;
+	void __iomem *sregs;
+	size_t nregions;
+	bool writeable;
+	bool swseq;
+	bool erase_64k;
+	u8 opcodes[8];
+	u8 preopcodes[2];
+};
+
+static bool writeable;
+module_param(writeable, bool, 0);
+MODULE_PARM_DESC(writeable, "Enable write access to SPI flash chip (default=0)");
+
+static void intel_spi_dump_regs(struct intel_spi *ispi)
+{
+	u32 value;
+	int i;
+
+	dev_dbg(ispi->dev, "BFPREG=0x%08x\n", readl(ispi->base + BFPREG));
+
+	value = readl(ispi->base + HSFSTS_CTL);
+	dev_dbg(ispi->dev, "HSFSTS_CTL=0x%08x\n", value);
+	if (value & HSFSTS_CTL_FLOCKDN)
+		dev_dbg(ispi->dev, "-> Locked\n");
+
+	dev_dbg(ispi->dev, "FADDR=0x%08x\n", readl(ispi->base + FADDR));
+	dev_dbg(ispi->dev, "DLOCK=0x%08x\n", readl(ispi->base + DLOCK));
+
+	for (i = 0; i < 16; i++)
+		dev_dbg(ispi->dev, "FDATA(%d)=0x%08x\n",
+			i, readl(ispi->base + FDATA(i)));
+
+	dev_dbg(ispi->dev, "FRACC=0x%08x\n", readl(ispi->base + FRACC));
+
+	for (i = 0; i < ispi->nregions; i++)
+		dev_dbg(ispi->dev, "FREG(%d)=0x%08x\n", i,
+			readl(ispi->base + FREG(i)));
+	for (i = 0; i < PR_NUM; i++)
+		dev_dbg(ispi->dev, "PR(%d)=0x%08x\n", i,
+			readl(ispi->pregs + PR(i)));
+
+	value = readl(ispi->sregs + SSFSTS_CTL);
+	dev_dbg(ispi->dev, "SSFSTS_CTL=0x%08x\n", value);
+	dev_dbg(ispi->dev, "PREOP_OPTYPE=0x%08x\n",
+		readl(ispi->sregs + PREOP_OPTYPE));
+	dev_dbg(ispi->dev, "OPMENU0=0x%08x\n", readl(ispi->sregs + OPMENU0));
+	dev_dbg(ispi->dev, "OPMENU1=0x%08x\n", readl(ispi->sregs + OPMENU1));
+
+	if (ispi->info->type == INTEL_SPI_BYT)
+		dev_dbg(ispi->dev, "BCR=0x%08x\n", readl(ispi->base + BYT_BCR));
+
+	dev_dbg(ispi->dev, "Protected regions:\n");
+	for (i = 0; i < PR_NUM; i++) {
+		u32 base, limit;
+
+		value = readl(ispi->pregs + PR(i));
+		if (!(value & (PR_WPE | PR_RPE)))
+			continue;
+
+		limit = (value & PR_LIMIT_MASK) >> PR_LIMIT_SHIFT;
+		base = value & PR_BASE_MASK;
+
+		dev_dbg(ispi->dev, " %02d base: 0x%08x limit: 0x%08x [%c%c]\n",
+			 i, base << 12, (limit << 12) | 0xfff,
+			 value & PR_WPE ? 'W' : '.',
+			 value & PR_RPE ? 'R' : '.');
+	}
+
+	dev_dbg(ispi->dev, "Flash regions:\n");
+	for (i = 0; i < ispi->nregions; i++) {
+		u32 region, base, limit;
+
+		region = readl(ispi->base + FREG(i));
+		base = region & FREG_BASE_MASK;
+		limit = (region & FREG_LIMIT_MASK) >> FREG_LIMIT_SHIFT;
+
+		if (base > limit || (i > 0 && limit == 0))
+			dev_dbg(ispi->dev, " %02d disabled\n", i);
+		else
+			dev_dbg(ispi->dev, " %02d base: 0x%08x limit: 0x%08x\n",
+				 i, base << 12, (limit << 12) | 0xfff);
+	}
+
+	dev_dbg(ispi->dev, "Using %cW sequencer for register access\n",
+		ispi->swseq ? 'S' : 'H');
+}
+
+/* Reads max 64 bytes from the device fifo */
+static int intel_spi_read_block(struct intel_spi *ispi, void *buf, size_t size)
+{
+	size_t bytes;
+	int i = 0;
+
+	if (size > 64)
+		return -EINVAL;
+
+	while (size > 0) {
+		bytes = min_t(size_t, size, 4);
+		memcpy_fromio(buf, ispi->base + FDATA(i++), bytes);
+		size -= bytes;
+		buf += bytes;
+	}
+
+	return 0;
+}
+
+/* Writes max 64 bytes to the device fifo */
+static int intel_spi_write_block(struct intel_spi *ispi, const void *buf,
+				 size_t size)
+{
+	size_t bytes;
+	int i = 0;
+
+	if (size > 64)
+		return -EINVAL;
+
+	while (size > 0) {
+		bytes = min_t(size_t, size, 4);
+		memcpy_toio(ispi->base + FDATA(i++), buf, bytes);
+		size -= bytes;
+		buf += bytes;
+	}
+
+	return 0;
+}
+
+static int intel_spi_wait_hw_busy(struct intel_spi *ispi)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(INTEL_SPI_TIMEOUT);
+	u32 hwstat;
+
+	while (!time_after(jiffies, timeout)) {
+		hwstat = readl(ispi->base + HSFSTS_CTL);
+		if (!(hwstat & HSFSTS_CTL_SCIP))
+			return 0;
+		cond_resched();
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int intel_spi_wait_sw_busy(struct intel_spi *ispi)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(INTEL_SPI_TIMEOUT);
+	u32 swstat;
+
+	while (!time_after(jiffies, timeout)) {
+		swstat = readl(ispi->sregs + SSFSTS_CTL);
+		if (!(swstat & SSFSTS_CTL_SCIP))
+			return 0;
+		cond_resched();
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int intel_spi_init(struct intel_spi *ispi)
+{
+	u32 opmenu0, opmenu1, val;
+	int i;
+
+	switch (ispi->info->type) {
+	case INTEL_SPI_BYT:
+		ispi->sregs = ispi->base + BYT_SSFSTS_CTL;
+		ispi->pregs = ispi->base + BYT_PR;
+		ispi->nregions = BYT_FREG_NUM;
+
+		if (writeable) {
+			/* Disable write protection */
+			val = readl(ispi->base + BYT_BCR);
+			if (!(val & BYT_BCR_WPD)) {
+				val |= BYT_BCR_WPD;
+				writel(val, ispi->base + BYT_BCR);
+				val = readl(ispi->base + BYT_BCR);
+			}
+
+			ispi->writeable = !!(val & BYT_BCR_WPD);
+		}
+
+		break;
+
+	case INTEL_SPI_LPT:
+		ispi->sregs = ispi->base + LPT_SSFSTS_CTL;
+		ispi->pregs = ispi->base + LPT_PR;
+		ispi->nregions = LPT_FREG_NUM;
+		break;
+
+	case INTEL_SPI_BXT:
+		ispi->sregs = ispi->base + BXT_SSFSTS_CTL;
+		ispi->pregs = ispi->base + BXT_PR;
+		ispi->nregions = BXT_FREG_NUM;
+		ispi->erase_64k = true;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* Disable #SMI generation */
+	val = readl(ispi->base + HSFSTS_CTL);
+	val &= ~HSFSTS_CTL_FSMIE;
+	writel(val, ispi->base + HSFSTS_CTL);
+
+	/*
+	 * BIOS programs allowed opcodes and then locks down the register.
+	 * So read back what opcodes it decided to support. That's the set
+	 * we are going to support as well.
+	 */
+	opmenu0 = readl(ispi->sregs + OPMENU0);
+	opmenu1 = readl(ispi->sregs + OPMENU1);
+
+	/*
+	 * Some controllers can only do basic operations using hardware
+	 * sequencer. All other operations are supposed to be carried out
+	 * using software sequencer. If we find that BIOS has programmed
+	 * opcodes for the software sequencer we use that over the hardware
+	 * sequencer.
+	 */
+	if (opmenu0 && opmenu1) {
+		for (i = 0; i < ARRAY_SIZE(ispi->opcodes) / 2; i++) {
+			ispi->opcodes[i] = opmenu0 >> i * 8;
+			ispi->opcodes[i + 4] = opmenu1 >> i * 8;
+		}
+
+		val = readl(ispi->sregs + PREOP_OPTYPE);
+		ispi->preopcodes[0] = val;
+		ispi->preopcodes[1] = val >> 8;
+
+		/* Disable #SMI generation from SW sequencer */
+		val = readl(ispi->sregs + SSFSTS_CTL);
+		val &= ~SSFSTS_CTL_FSMIE;
+		writel(val, ispi->sregs + SSFSTS_CTL);
+
+		ispi->swseq = true;
+	}
+
+	intel_spi_dump_regs(ispi);
+
+	return 0;
+}
+
+static int intel_spi_opcode_index(struct intel_spi *ispi, u8 opcode)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ispi->opcodes); i++)
+		if (ispi->opcodes[i] == opcode)
+			return i;
+	return -EINVAL;
+}
+
+static int intel_spi_hw_cycle(struct intel_spi *ispi, u8 opcode, u8 *buf,
+			      int len)
+{
+	u32 val, status;
+	int ret;
+
+	val = readl(ispi->base + HSFSTS_CTL);
+	val &= ~(HSFSTS_CTL_FCYCLE_MASK | HSFSTS_CTL_FDBC_MASK);
+
+	switch (opcode) {
+	case SPINOR_OP_RDID:
+		val |= HSFSTS_CTL_FCYCLE_RDID;
+		break;
+	case SPINOR_OP_WRSR:
+		val |= HSFSTS_CTL_FCYCLE_WRSR;
+		break;
+	case SPINOR_OP_RDSR:
+		val |= HSFSTS_CTL_FCYCLE_RDSR;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	val |= (len - 1) << HSFSTS_CTL_FDBC_SHIFT;
+	val |= HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE;
+	val |= HSFSTS_CTL_FGO;
+	writel(val, ispi->base + HSFSTS_CTL);
+
+	ret = intel_spi_wait_hw_busy(ispi);
+	if (ret)
+		return ret;
+
+	status = readl(ispi->base + HSFSTS_CTL);
+	if (status & HSFSTS_CTL_FCERR)
+		return -EIO;
+	else if (status & HSFSTS_CTL_AEL)
+		return -EACCES;
+
+	return 0;
+}
+
+static int intel_spi_sw_cycle(struct intel_spi *ispi, u8 opcode, u8 *buf,
+			      int len)
+{
+	u32 val, status;
+	int ret;
+
+	ret = intel_spi_opcode_index(ispi, opcode);
+	if (ret < 0)
+		return ret;
+
+	val = (len << SSFSTS_CTL_DBC_SHIFT) | SSFSTS_CTL_DS;
+	val |= ret << SSFSTS_CTL_COP_SHIFT;
+	val |= SSFSTS_CTL_FCERR | SSFSTS_CTL_FDONE;
+	val |= SSFSTS_CTL_SCGO;
+	writel(val, ispi->sregs + SSFSTS_CTL);
+
+	ret = intel_spi_wait_sw_busy(ispi);
+	if (ret)
+		return ret;
+
+	status = readl(ispi->base + SSFSTS_CTL);
+	if (status & SSFSTS_CTL_FCERR)
+		return -EIO;
+	else if (status & SSFSTS_CTL_AEL)
+		return -EACCES;
+
+	return 0;
+}
+
+static int intel_spi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
+{
+	struct intel_spi *ispi = nor->priv;
+	int ret;
+
+	/* Address of the first chip */
+	writel(0, ispi->base + FADDR);
+
+	if (ispi->swseq)
+		ret = intel_spi_sw_cycle(ispi, opcode, buf, len);
+	else
+		ret = intel_spi_hw_cycle(ispi, opcode, buf, len);
+
+	if (ret)
+		return ret;
+
+	return intel_spi_read_block(ispi, buf, len);
+}
+
+static int intel_spi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
+{
+	struct intel_spi *ispi = nor->priv;
+	int ret;
+
+	/*
+	 * This is handled with atomic operation and preop code in Intel
+	 * controller so skip it here now.
+	 */
+	if (opcode == SPINOR_OP_WREN)
+		return 0;
+
+	writel(0, ispi->base + FADDR);
+
+	/* Write the value beforehand */
+	ret = intel_spi_write_block(ispi, buf, len);
+	if (ret)
+		return ret;
+
+	if (ispi->swseq)
+		return intel_spi_sw_cycle(ispi, opcode, buf, len);
+	return intel_spi_hw_cycle(ispi, opcode, buf, len);
+}
+
+static ssize_t intel_spi_read(struct spi_nor *nor, loff_t from, size_t len,
+			      u_char *read_buf)
+{
+	struct intel_spi *ispi = nor->priv;
+	size_t block_size, retlen = 0;
+	u32 val, status;
+	ssize_t ret;
+
+	while (len > 0) {
+		block_size = min_t(size_t, len, 64);
+
+		writel(from, ispi->base + FADDR);
+
+		val = readl(ispi->base + HSFSTS_CTL);
+		val |= HSFSTS_CTL_AEL | HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE;
+		val &= ~HSFSTS_CTL_FDBC_MASK;
+		val |= (block_size - 1) << HSFSTS_CTL_FDBC_SHIFT;
+		val &= ~HSFSTS_CTL_FCYCLE_MASK;
+		val |= HSFSTS_CTL_FCYCLE_READ;
+		val |= HSFSTS_CTL_FGO;
+		writel(val, ispi->base + HSFSTS_CTL);
+
+		ret = intel_spi_wait_hw_busy(ispi);
+		if (ret)
+			return ret;
+
+		status = readl(ispi->base + HSFSTS_CTL);
+		if (status & HSFSTS_CTL_FCERR)
+			ret = -EIO;
+		else if (status & HSFSTS_CTL_AEL)
+			ret = -EACCES;
+
+		if (ret < 0) {
+			dev_err(ispi->dev, "read error: %llx: %#x\n", from,
+				status);
+			return ret;
+		}
+
+		ret = intel_spi_read_block(ispi, read_buf, block_size);
+		if (ret)
+			return ret;
+
+		len -= block_size;
+		from += block_size;
+		retlen += block_size;
+		read_buf += block_size;
+	}
+
+	return retlen;
+}
+
+static ssize_t intel_spi_write(struct spi_nor *nor, loff_t to, size_t len,
+			       const u_char *write_buf)
+{
+	struct intel_spi *ispi = nor->priv;
+	size_t block_size, retlen = 0;
+	u32 val, status;
+	ssize_t ret;
+
+	while (len > 0) {
+		block_size = min_t(size_t, len, 64);
+
+		writel(to, ispi->base + FADDR);
+
+		val = readl(ispi->base + HSFSTS_CTL);
+		val |= HSFSTS_CTL_AEL | HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE;
+		val &= ~HSFSTS_CTL_FDBC_MASK;
+		val |= (block_size - 1) << HSFSTS_CTL_FDBC_SHIFT;
+		val &= ~HSFSTS_CTL_FCYCLE_MASK;
+		val |= HSFSTS_CTL_FCYCLE_WRITE;
+
+		/* Write enable */
+		if (ispi->preopcodes[1] == SPINOR_OP_WREN)
+			val |= SSFSTS_CTL_SPOP;
+		val |= SSFSTS_CTL_ACS;
+		writel(val, ispi->base + HSFSTS_CTL);
+
+		ret = intel_spi_write_block(ispi, write_buf, block_size);
+		if (ret) {
+			dev_err(ispi->dev, "failed to write block\n");
+			return ret;
+		}
+
+		/* Start the write now */
+		val = readl(ispi->base + HSFSTS_CTL);
+		writel(val | HSFSTS_CTL_FGO, ispi->base + HSFSTS_CTL);
+
+		ret = intel_spi_wait_hw_busy(ispi);
+		if (ret) {
+			dev_err(ispi->dev, "timeout\n");
+			return ret;
+		}
+
+		status = readl(ispi->base + HSFSTS_CTL);
+		if (status & HSFSTS_CTL_FCERR)
+			ret = -EIO;
+		else if (status & HSFSTS_CTL_AEL)
+			ret = -EACCES;
+
+		if (ret < 0) {
+			dev_err(ispi->dev, "write error: %llx: %#x\n", to,
+				status);
+			return ret;
+		}
+
+		len -= block_size;
+		to += block_size;
+		retlen += block_size;
+		write_buf += block_size;
+	}
+
+	return retlen;
+}
+
+static int intel_spi_erase(struct spi_nor *nor, loff_t offs)
+{
+	size_t erase_size, len = nor->mtd.erasesize;
+	struct intel_spi *ispi = nor->priv;
+	u32 val, status, cmd;
+	int ret;
+
+	/* If the hardware can do 64k erase use that when possible */
+	if (len >= SZ_64K && ispi->erase_64k) {
+		cmd = HSFSTS_CTL_FCYCLE_ERASE_64K;
+		erase_size = SZ_64K;
+	} else {
+		cmd = HSFSTS_CTL_FCYCLE_ERASE;
+		erase_size = SZ_4K;
+	}
+
+	while (len > 0) {
+		writel(offs, ispi->base + FADDR);
+
+		val = readl(ispi->base + HSFSTS_CTL);
+		val |= HSFSTS_CTL_AEL | HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE;
+		val &= ~HSFSTS_CTL_FDBC_MASK;
+		val &= ~HSFSTS_CTL_FCYCLE_MASK;
+		val |= cmd;
+		val |= HSFSTS_CTL_FGO;
+		writel(val, ispi->base + HSFSTS_CTL);
+
+		ret = intel_spi_wait_hw_busy(ispi);
+		if (ret)
+			return ret;
+
+		status = readl(ispi->base + HSFSTS_CTL);
+		if (status & HSFSTS_CTL_FCERR)
+			return -EIO;
+		else if (status & HSFSTS_CTL_AEL)
+			return -EACCES;
+
+		offs += erase_size;
+		len -= erase_size;
+	}
+
+	return 0;
+}
+
+static bool intel_spi_is_protected(const struct intel_spi *ispi,
+				   unsigned int base, unsigned int limit)
+{
+	int i;
+
+	for (i = 0; i < PR_NUM; i++) {
+		u32 pr_base, pr_limit, pr_value;
+
+		pr_value = readl(ispi->pregs + PR(i));
+		if (!(pr_value & (PR_WPE | PR_RPE)))
+			continue;
+
+		pr_limit = (pr_value & PR_LIMIT_MASK) >> PR_LIMIT_SHIFT;
+		pr_base = pr_value & PR_BASE_MASK;
+
+		if (pr_base >= base && pr_limit <= limit)
+			return true;
+	}
+
+	return false;
+}
+
+/*
+ * There will be a single partition holding all enabled flash regions. We
+ * call this "BIOS".
+ */
+static void intel_spi_fill_partition(struct intel_spi *ispi,
+				     struct mtd_partition *part)
+{
+	u64 end;
+	int i;
+
+	memset(part, 0, sizeof(*part));
+
+	/* Start from the mandatory descriptor region */
+	part->size = 4096;
+	part->name = "BIOS";
+
+	/*
+	 * Now try to find where this partition ends based on the flash
+	 * region registers.
+	 */
+	for (i = 1; i < ispi->nregions; i++) {
+		u32 region, base, limit;
+
+		region = readl(ispi->base + FREG(i));
+		base = region & FREG_BASE_MASK;
+		limit = (region & FREG_LIMIT_MASK) >> FREG_LIMIT_SHIFT;
+
+		if (base > limit || limit == 0)
+			continue;
+
+		/*
+		 * If any of the regions have protection bits set, make the
+		 * whole partition read-only to be on the safe side.
+		 */
+		if (intel_spi_is_protected(ispi, base, limit))
+			ispi->writeable = 0;
+
+		end = (limit << 12) + 4096;
+		if (end > part->size)
+			part->size = end;
+	}
+}
+
+struct intel_spi *intel_spi_probe(struct device *dev,
+	struct resource *mem, const struct intel_spi_boardinfo *info)
+{
+	struct mtd_partition part;
+	struct intel_spi *ispi;
+	int ret;
+
+	if (!info || !mem)
+		return ERR_PTR(-EINVAL);
+
+	ispi = devm_kzalloc(dev, sizeof(*ispi), GFP_KERNEL);
+	if (!ispi)
+		return ERR_PTR(-ENOMEM);
+
+	ispi->base = devm_ioremap_resource(dev, mem);
+	if (IS_ERR(ispi->base))
+		return ispi->base;
+
+	ispi->dev = dev;
+	ispi->info = info;
+	ispi->writeable = info->writeable;
+
+	ret = intel_spi_init(ispi);
+	if (ret)
+		return ERR_PTR(ret);
+
+	ispi->nor.dev = ispi->dev;
+	ispi->nor.priv = ispi;
+	ispi->nor.read_reg = intel_spi_read_reg;
+	ispi->nor.write_reg = intel_spi_write_reg;
+	ispi->nor.read = intel_spi_read;
+	ispi->nor.write = intel_spi_write;
+	ispi->nor.erase = intel_spi_erase;
+
+	ret = spi_nor_scan(&ispi->nor, NULL, SPI_NOR_NORMAL);
+	if (ret) {
+		dev_info(dev, "failed to locate the chip\n");
+		return ERR_PTR(ret);
+	}
+
+	intel_spi_fill_partition(ispi, &part);
+
+	/* Prevent writes if not explicitly enabled */
+	if (!ispi->writeable || !writeable)
+		ispi->nor.mtd.flags &= ~MTD_WRITEABLE;
+
+	ret = mtd_device_parse_register(&ispi->nor.mtd, NULL, NULL, &part, 1);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return ispi;
+}
+EXPORT_SYMBOL_GPL(intel_spi_probe);
+
+int intel_spi_remove(struct intel_spi *ispi)
+{
+	return mtd_device_unregister(&ispi->nor.mtd);
+}
+EXPORT_SYMBOL_GPL(intel_spi_remove);
+
+MODULE_DESCRIPTION("Intel PCH/PCU SPI flash core driver");
+MODULE_AUTHOR("Mika Westerberg <mika.westerberg at linux.intel.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/spi-nor/intel-spi.h b/drivers/mtd/spi-nor/intel-spi.h
new file mode 100644
index 000000000000..5ab7dc250050
--- /dev/null
+++ b/drivers/mtd/spi-nor/intel-spi.h
@@ -0,0 +1,24 @@
+/*
+ * Intel PCH/PCU SPI flash driver.
+ *
+ * Copyright (C) 2016, Intel Corporation
+ * Author: Mika Westerberg <mika.westerberg at linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef INTEL_SPI_H
+#define INTEL_SPI_H
+
+#include <linux/platform_data/intel-spi.h>
+
+struct intel_spi;
+struct resource;
+
+struct intel_spi *intel_spi_probe(struct device *dev,
+	struct resource *mem, const struct intel_spi_boardinfo *info);
+int intel_spi_remove(struct intel_spi *ispi);
+
+#endif /* INTEL_SPI_H */
diff --git a/include/linux/platform_data/intel-spi.h b/include/linux/platform_data/intel-spi.h
new file mode 100644
index 000000000000..942b0c3f8f08
--- /dev/null
+++ b/include/linux/platform_data/intel-spi.h
@@ -0,0 +1,31 @@
+/*
+ * Intel PCH/PCU SPI flash driver.
+ *
+ * Copyright (C) 2016, Intel Corporation
+ * Author: Mika Westerberg <mika.westerberg at linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef INTEL_SPI_PDATA_H
+#define INTEL_SPI_PDATA_H
+
+enum intel_spi_type {
+	INTEL_SPI_BYT = 1,
+	INTEL_SPI_LPT,
+	INTEL_SPI_BXT,
+};
+
+/**
+ * struct intel_spi_boardinfo - Board specific data for Intel SPI driver
+ * @type: Type which this controller is compatible with
+ * @writeable: The chip is writeable
+ */
+struct intel_spi_boardinfo {
+	enum intel_spi_type type;
+	bool writeable;
+};
+
+#endif /* INTEL_SPI_PDATA_H */
-- 
2.9.3



From mika.westerberg at linux.intel.com  Mon Oct 17 07:58:58 2016
From: mika.westerberg at linux.intel.com (Mika Westerberg)
Date: Mon, 17 Oct 2016 17:58:58 +0300
Subject: [PATCH v4 3/3] mfd: lpc_ich: Add support for Intel Apollo Lake SoC
In-Reply-To: <20161017145858.143771-1-mika.westerberg@linux.intel.com>
References: <20161017145858.143771-1-mika.westerberg@linux.intel.com>
Message-ID: <20161017145858.143771-4-mika.westerberg@linux.intel.com>

Intel Apollo Lake SoC exposes serial SPI flash through the LPC device. The
SPI flash host controller is not discoverable through PCI config cycles
because P2SB (function 0 of the device 13) is hidden by the BIOS. We unhide
the device briefly in order to read BAR 0 of the SPI host controller.

Signed-off-by: Mika Westerberg <mika.westerberg at linux.intel.com>
Acked-by: Lee Jones <lee.jones at linaro.org>
---
 drivers/mfd/lpc_ich.c | 39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c
index 985bda575849..1d8d1caebdf1 100644
--- a/drivers/mfd/lpc_ich.c
+++ b/drivers/mfd/lpc_ich.c
@@ -56,6 +56,7 @@
  *	document number TBD : Wildcat Point-LP
  *	document number TBD : 9 Series
  *	document number TBD : Lewisburg
+ *	document number TBD : Apollo Lake SoC
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -92,6 +93,8 @@
 #define BCR			0xdc
 #define BCR_WPD			BIT(0)
 
+#define SPIBASE_APL_SZ		4096
+
 #define GPIOBASE_ICH0		0x58
 #define GPIOCTRL_ICH0		0x5C
 #define GPIOBASE_ICH6		0x48
@@ -239,6 +242,7 @@ enum lpc_chipsets {
 	LPC_BRASWELL,	/* Braswell SoC */
 	LPC_LEWISBURG,	/* Lewisburg */
 	LPC_9S,		/* 9 Series */
+	LPC_APL,	/* Apollo Lake SoC */
 };
 
 static struct lpc_ich_info lpc_chipset_info[] = {
@@ -559,6 +563,10 @@ static struct lpc_ich_info lpc_chipset_info[] = {
 		.name = "9 Series",
 		.iTCO_version = 2,
 	},
+	[LPC_APL] = {
+		.name = "Apollo Lake SoC",
+		.spi_type = INTEL_SPI_BXT,
+	},
 };
 
 /*
@@ -707,6 +715,7 @@ static const struct pci_device_id lpc_ich_ids[] = {
 	{ PCI_VDEVICE(INTEL, 0x3b14), LPC_3420},
 	{ PCI_VDEVICE(INTEL, 0x3b16), LPC_3450},
 	{ PCI_VDEVICE(INTEL, 0x5031), LPC_EP80579},
+	{ PCI_VDEVICE(INTEL, 0x5ae8), LPC_APL},
 	{ PCI_VDEVICE(INTEL, 0x8c40), LPC_LPT},
 	{ PCI_VDEVICE(INTEL, 0x8c41), LPC_LPT},
 	{ PCI_VDEVICE(INTEL, 0x8c42), LPC_LPT},
@@ -1126,6 +1135,36 @@ static int lpc_ich_init_spi(struct pci_dev *dev)
 		}
 		break;
 
+	case INTEL_SPI_BXT: {
+		unsigned int p2sb = PCI_DEVFN(13, 0);
+		unsigned int spi = PCI_DEVFN(13, 2);
+		struct pci_bus *bus = dev->bus;
+
+		/*
+		 * The P2SB is hidden by BIOS and we need to unhide it in
+		 * order to read BAR of the SPI flash device. Once that is
+		 * done we hide it again.
+		 */
+		pci_bus_write_config_byte(bus, p2sb, 0xe1, 0x0);
+		pci_bus_read_config_dword(bus, spi, PCI_BASE_ADDRESS_0,
+					  &spi_base);
+		if (spi_base != ~0) {
+			res->start = spi_base & 0xfffffff0;
+			res->end = res->start + SPIBASE_APL_SZ - 1;
+
+			pci_bus_read_config_dword(bus, spi, BCR, &bcr);
+			if (!(bcr & BCR_WPD)) {
+				bcr |= BCR_WPD;
+				pci_bus_write_config_dword(bus, spi, BCR, bcr);
+				pci_bus_read_config_dword(bus, spi, BCR, &bcr);
+			}
+			info->writeable = !!(bcr & BCR_WPD);
+		}
+
+		pci_bus_write_config_byte(bus, p2sb, 0xe1, 0x1);
+		break;
+	}
+
 	default:
 		return -EINVAL;
 	}
-- 
2.9.3



From zach.brown at ni.com  Mon Oct 17 08:57:22 2016
From: zach.brown at ni.com (Zach Brown)
Date: Mon, 17 Oct 2016 10:57:22 -0500
Subject: [PATCH] UBI: add debugfs file for tracking PEB state
Message-ID: <1476719842-28642-1-git-send-email-zach.brown@ni.com>

From: Ben Shelton <ben.shelton at ni.com>

Add a file under debugfs to allow easy access to the erase count for
each physical erase block on an UBI device.  This is useful when
debugging data integrity issues with UBIFS on NAND flash devices.

Signed-off-by: Ben Shelton <ben.shelton at ni.com>
Signed-off-by: Zach Brown <zach.brown at ni.com>
---
 drivers/mtd/ubi/debug.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 150 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c
index f101a49..6086822 100644
--- a/drivers/mtd/ubi/debug.c
+++ b/drivers/mtd/ubi/debug.c
@@ -22,6 +22,7 @@
 #include <linux/debugfs.h>
 #include <linux/uaccess.h>
 #include <linux/module.h>
+#include <linux/seq_file.h>
 
 
 /**
@@ -386,7 +387,9 @@ out:
 	return count;
 }
 
-/* File operations for all UBI debugfs files */
+/* File operations for all UBI debugfs files except
+ * detailed_erase_block_info
+ */
 static const struct file_operations dfs_fops = {
 	.read   = dfs_file_read,
 	.write  = dfs_file_write,
@@ -395,6 +398,146 @@ static const struct file_operations dfs_fops = {
 	.owner  = THIS_MODULE,
 };
 
+/* As long as the position is less then that total number of erase blocks,
+ * we still have more to print.
+ */
+static void *eraseblk_count_seq_start(struct seq_file *s, loff_t *pos)
+{
+	struct ubi_device *ubi = s->private;
+
+	if (*pos == 0)
+		return SEQ_START_TOKEN;
+
+	if (*pos < ubi->peb_count)
+		return pos;
+
+	return NULL;
+}
+
+/* Since we are using the position as the iterator, we just need to check if we
+ * are done and increment the position.
+ */
+static void *eraseblk_count_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+	struct ubi_device *ubi = s->private;
+
+	if (v == SEQ_START_TOKEN)
+		return pos;
+	(*pos)++;
+
+	if (*pos < ubi->peb_count)
+		return pos;
+
+	return NULL;
+}
+
+static void eraseblk_count_seq_stop(struct seq_file *s, void *v)
+{
+}
+
+enum block_status {
+	BLOCK_STATUS_OK,
+	BLOCK_STATUS_BAD_BLOCK,
+	BLOCK_STATUS_ERASE_COUNT_BEYOND_MAX
+};
+
+static char const *block_status_names[] = {"OK", "marked_bad",
+					   "erase_count_beyond_max"};
+
+enum read_status {
+	READ_STATUS_OK,
+	READ_STATUS_ERR_READING_BLOCK,
+};
+
+static char const *read_status_names[] = {"OK", "err_reading_block"};
+
+static int eraseblk_count_seq_show(struct seq_file *s, void *iter)
+{
+	struct ubi_device *ubi = s->private;
+	struct ubi_wl_entry *wl;
+	int *block_number = iter;
+	int erase_count = -1;
+	enum block_status b_sts = BLOCK_STATUS_OK;
+	enum read_status r_sts = READ_STATUS_OK;
+	int err;
+
+	/* If this is the start, print a header */
+	if (iter == SEQ_START_TOKEN) {
+		seq_puts(s,
+			 "physical_block_number\terase_count\tblock_status\tread_status\n");
+		return 0;
+	}
+
+	err = ubi_io_is_bad(ubi, *block_number);
+	if (err) {
+		if (err < 0)
+			r_sts = READ_STATUS_ERR_READING_BLOCK;
+		else
+			b_sts = BLOCK_STATUS_BAD_BLOCK;
+	} else {
+		spin_lock(&ubi->wl_lock);
+
+		wl = ubi->lookuptbl[*block_number];
+		if (wl)
+			erase_count = wl->ec;
+		else
+			r_sts = READ_STATUS_ERR_READING_BLOCK;
+
+		spin_unlock(&ubi->wl_lock);
+
+		if (erase_count > UBI_MAX_ERASECOUNTER)
+			b_sts = BLOCK_STATUS_ERASE_COUNT_BEYOND_MAX;
+	}
+
+	seq_printf(s, "%-22d\t%-11d\t%-12s\t%-12s\n", *block_number,
+		   erase_count, block_status_names[b_sts],
+		   read_status_names[r_sts]);
+	return 0;
+}
+
+static const struct seq_operations eraseblk_count_seq_ops = {
+	.start = eraseblk_count_seq_start,
+	.next = eraseblk_count_seq_next,
+	.stop = eraseblk_count_seq_stop,
+	.show = eraseblk_count_seq_show
+};
+
+static int eraseblk_count_open(struct inode *inode, struct file *f)
+{
+	struct seq_file *s;
+	int err;
+
+	err = seq_open(f, &eraseblk_count_seq_ops);
+	if (err)
+		return err;
+
+	s = f->private_data;
+	s->private = ubi_get_device((unsigned long)inode->i_private);
+
+	if (!s->private)
+		return -ENODEV;
+	else
+		return 0;
+}
+
+static int eraseblk_count_release(struct inode *inode, struct file *f)
+{
+	struct seq_file *s = f->private_data;
+	struct ubi_device *ubi = s->private;
+
+	ubi_put_device(ubi);
+
+	return seq_release(inode, f);
+}
+
+static const struct file_operations eraseblk_count_fops = {
+	.owner = THIS_MODULE,
+	.open = eraseblk_count_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = eraseblk_count_release,
+};
+
 /**
  * ubi_debugfs_init_dev - initialize debugfs for an UBI device.
  * @ubi: UBI device description object
@@ -491,6 +634,12 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi)
 		goto out_remove;
 	d->dfs_power_cut_max = dent;
 
+	fname = "detailed_erase_block_info";
+	dent = debugfs_create_file(fname, S_IRUSR, d->dfs_dir, (void *)ubi_num,
+				   &eraseblk_count_fops);
+	if (IS_ERR_OR_NULL(dent))
+		goto out_remove;
+
 	return 0;
 
 out_remove:
-- 
2.7.4



From javier at osg.samsung.com  Mon Oct 17 09:19:37 2016
From: javier at osg.samsung.com (Javier Martinez Canillas)
Date: Mon, 17 Oct 2016 13:19:37 -0300
Subject: [PATCH] mtd: nand: omap2: Fix module autoload
Message-ID: <1476721177-3425-1-git-send-email-javier@osg.samsung.com>

If the driver is built as a module, autoload won't work because the module
alias information is not filled. So user-space can't match the registered
device with the corresponding module.

Export the module alias information using the MODULE_DEVICE_TABLE() macro.

Before this patch:

$ modinfo drivers/mtd/nand/omap2_nand.ko | grep alias
alias:          platform:omap2-nand

After this patch:

$ modinfo drivers/mtd/nand/omap2_nand.ko | grep alias
alias:          platform:omap2-nand
alias:          of:N*T*Cti,omap2-nandC*
alias:          of:N*T*Cti,omap2-nand

Signed-off-by: Javier Martinez Canillas <javier at osg.samsung.com>

---

 drivers/mtd/nand/omap2.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 5513bfd9cdc9..0934c3b3f70e 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -2197,6 +2197,7 @@ static const struct of_device_id omap_nand_ids[] = {
 	{ .compatible = "ti,omap2-nand", },
 	{},
 };
+MODULE_DEVICE_TABLE(of, omap_nand_ids);
 
 static struct platform_driver omap_nand_driver = {
 	.probe		= omap_nand_probe,
-- 
2.7.4



From marex at denx.de  Mon Oct 17 09:39:18 2016
From: marex at denx.de (Marek Vasut)
Date: Mon, 17 Oct 2016 18:39:18 +0200
Subject: [PATCH] mtd: spi-nor: cqspi: Fix build on arches missing
 readsl/writesl
In-Reply-To: <1470143447-11351-1-git-send-email-marex@denx.de>
References: <1470143447-11351-1-git-send-email-marex@denx.de>
Message-ID: <62687e78-288d-bddb-e567-de2a9ab9fc8b@denx.de>

On 08/02/2016 03:10 PM, Marek Vasut wrote:
> The x86-64 and some other architectures are missing readsl/writesl
> functions, so this driver won't build on them. Use a more portable
> ioread32_rep()/iowrite32_rep() instead.
> 
> Signed-off-by: Marek Vasut <marex at denx.de>
> Cc: Alan Tull <atull at opensource.altera.com>
> Cc: Brian Norris <computersforpeace at gmail.com>
> Cc: David Woodhouse <dwmw2 at infradead.org>
> Cc: Dinh Nguyen <dinguyen at opensource.altera.com>
> Cc: Graham Moore <grmoore at opensource.altera.com>
> Cc: Vignesh R <vigneshr at ti.com>
> Cc: Yves Vandervennet <yvanderv at opensource.altera.com>
> Suggested-by: Stefan Roese <sr at denx.de>
> ---

Bump ?

>  drivers/mtd/spi-nor/Kconfig           | 2 +-
>  drivers/mtd/spi-nor/cadence-quadspi.c | 6 ++++--
>  2 files changed, 5 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
> index 4a682ee..1e6f037 100644
> --- a/drivers/mtd/spi-nor/Kconfig
> +++ b/drivers/mtd/spi-nor/Kconfig
> @@ -40,7 +40,7 @@ config SPI_ATMEL_QUADSPI
>  
>  config SPI_CADENCE_QUADSPI
>  	tristate "Cadence Quad SPI controller"
> -	depends on OF && ARM
> +	depends on OF && (ARM || COMPILE_TEST)
>  	help
>  	  Enable support for the Cadence Quad SPI Flash controller.
>  
> diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c
> index d403ba7..08c9483 100644
> --- a/drivers/mtd/spi-nor/cadence-quadspi.c
> +++ b/drivers/mtd/spi-nor/cadence-quadspi.c
> @@ -526,7 +526,8 @@ static int cqspi_indirect_read_execute(struct spi_nor *nor,
>  			bytes_to_read *= cqspi->fifo_width;
>  			bytes_to_read = bytes_to_read > remaining ?
>  					remaining : bytes_to_read;
> -			readsl(ahb_base, rxbuf, DIV_ROUND_UP(bytes_to_read, 4));
> +			ioread32_rep(ahb_base, rxbuf,
> +				     DIV_ROUND_UP(bytes_to_read, 4));
>  			rxbuf += bytes_to_read;
>  			remaining -= bytes_to_read;
>  			bytes_to_read = cqspi_get_rd_sram_level(cqspi);
> @@ -610,7 +611,8 @@ static int cqspi_indirect_write_execute(struct spi_nor *nor,
>  
>  	while (remaining > 0) {
>  		write_bytes = remaining > page_size ? page_size : remaining;
> -		writesl(cqspi->ahb_base, txbuf, DIV_ROUND_UP(write_bytes, 4));
> +		iowrite32_rep(cqspi->ahb_base, txbuf,
> +			      DIV_ROUND_UP(write_bytes, 4));
>  
>  		ret = wait_for_completion_timeout(&cqspi->transfer_complete,
>  						  msecs_to_jiffies
> 


-- 
Best regards,
Marek Vasut


From davsingl at cisco.com  Mon Oct 17 09:51:04 2016
From: davsingl at cisco.com (David Singleton)
Date: Mon, 17 Oct 2016 09:51:04 -0700
Subject: [PATCH] mtd: chips: cfi_cmdset_0001: Disable erase and write suspend
 for Intel flash.
Message-ID: <20161017165108.29718-1-davsingl@cisco.com>

From: Steve Shih <sshih at cisco.com>

Some revisions of the P30, P33, and J3 Flash memory devices can hang
when an ERASE SUSPEND command is issued following an ERASE RESUME
without waiting for the minimum delay time to elapse. The result
is that when the ERASE appears to be complete (no bits are toggling),
the contents of the Flash memory block on which the ERASE was executing
could be inconsstent with the expected values (typically, the array
value is stuck to the 0xC0, 0xC4, 0x80, or 0x84 values). This cause
ERASE operation to fail.

Please refer to Micron Technical Note TN-12-06:
Adapting the Linux Kernel for P30, P33, and J3 Flash

Cc: xe-kernel at external.cisco.com
Signed-off-by: Steve Shih <sshih at cisco.com>
Signed-off-by: David Singleton <davsingl at cisco.com>
---
 drivers/mtd/chips/Kconfig           | 17 +++++++++++++++++
 drivers/mtd/chips/cfi_cmdset_0001.c |  6 ++++--
 2 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig
index bbfa1f1..b25545c 100644
--- a/drivers/mtd/chips/Kconfig
+++ b/drivers/mtd/chips/Kconfig
@@ -184,6 +184,23 @@ config MTD_CFI_INTELEXT
 	  provides support for command set 0001, used on Intel StrataFlash
 	  and other parts.
 
+config MTD_CFI_INTELEXT_NO_SUSPEND
+	bool "Disable erase and write suspends for Intel/Sharp flash"
+	depends on MTD_CFI_INTELEXT
+	default n
+	help
+	  Some revisions of the P30, P33, and J3 Flash memory devices can hang
+	  when an ERASE SUSPEND command is issued following an ERASE RESUME
+	  without waiting for the minimum delay time to elapse. The result
+	  is that when the ERASE appears to be complete (no bits are toggling),
+	  the contents of the Flash memory block on which the ERASE was
+	  executing could be inconsstent with the expected values (typically,
+	  the array value is stuck to the 0xC0, 0xC4, 0x80, or 0x84 values).
+	  This cause ERASE operation to fail.
+
+	  Please refer to Micron Technical Note TN-12-06:
+		Adapting the Linux Kernel for P30, P33, and J3 Flash
+
 config MTD_CFI_AMDSTD
 	tristate "Support for CFI command set 0002 (AMD/Fujitsu/Spansion chips)"
 	depends on MTD_GEN_PROBE
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index 5e1b68c..23dde4e 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -35,8 +35,10 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/cfi.h>
 
-/* #define CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE */
-/* #define CMDSET0001_DISABLE_WRITE_SUSPEND */
+#ifdef CONFIG_MTD_CFI_INTELEXT_NO_SUSPEND
+#define CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
+#define CMDSET0001_DISABLE_WRITE_SUSPEND
+#endif
 
 // debugging, turns off buffer write mode if set to 1
 #define FORCE_WORD_WRITE 0
-- 
2.9.3



From clg at kaod.org  Mon Oct 17 09:57:07 2016
From: clg at kaod.org (=?UTF-8?q?C=C3=A9dric=20Le=20Goater?=)
Date: Mon, 17 Oct 2016 18:57:07 +0200
Subject: [PATCH] mtd/spi-nor: Add SPI memory controllers for Aspeed SoCs
Message-ID: <1476723427-13243-1-git-send-email-clg@kaod.org>

This driver adds mtd support for spi-nor attached to either or both of
the Firmware Memory Controller or the SPI Flash Controller (AST2400
only).

The SMC controllers on the Aspeed AST2500 SoC are very similar to the
ones found on the AST2400. The differences are on the number of
supported flash modules and their default mappings in the SoC address
space.

The Aspeed AST2500 has one SPI controller for the BMC firmware and two
for the host firmware. All controllers have now the same set of
registers compatible with the AST2400 FMC controller and the legacy
'SMC' controller is fully gone.

Based on previous work from Milton D. Miller II <miltonm at us.ibm.com>

Signed-off-by: C?dric Le Goater <clg at kaod.org>
---
 .../devicetree/bindings/mtd/aspeed-smc.txt         |  86 +++
 drivers/mtd/spi-nor/Kconfig                        |  12 +
 drivers/mtd/spi-nor/Makefile                       |   1 +
 drivers/mtd/spi-nor/aspeed-smc.c                   | 746 +++++++++++++++++++++
 4 files changed, 845 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/aspeed-smc.txt
 create mode 100644 drivers/mtd/spi-nor/aspeed-smc.c

diff --git a/Documentation/devicetree/bindings/mtd/aspeed-smc.txt b/Documentation/devicetree/bindings/mtd/aspeed-smc.txt
new file mode 100644
index 000000000000..f6bfa7761205
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/aspeed-smc.txt
@@ -0,0 +1,86 @@
+* Aspeed Static Memory controller
+* Aspeed SPI Flash Controller
+
+The Static memory controller in the ast2400 supports 5 chip selects each
+can be attached to NAND, parallel NOR, or SPI NOR attached flash.  The
+Firmware Memory Controller in the ast2500 supports 3 chip selects, two of
+which are always in SPI-NOR mode and the third can be SPI-NOR or parallel
+flash.  The SPI flash controller in the ast2400 supports one of 2 chip
+selects selected by pinmux.  The two SPI flash controllers in the ast2500
+each support two chip selects.
+
+Required properties:
+  - compatible : Should be one of
+	"aspeed,ast2400-fmc" for the AST2400 Static Memory Controller
+	"aspeed,ast2400-smc" for the AST2400 SPI Flash Controller
+	"aspeed,ast2500-fmc" for the AST2500 Firmware SPI Memory Controller
+	"aspeed,ast2500-smc" for the AST2500 SPI Flash Controllers
+  - reg : the first contains the control register location and length,
+          the second contains the memory window mapping address and length
+  - clocks : The APB clock input to the controller
+  - #address-cells : must be 1 corresponding to chip select child binding
+  - #size-cells : must be 0 corresponding to chip select child binding
+
+Optional properties:
+  - aspeed,fmc-has-dma : controller supports DMA transfers
+  - interrupts : Should contain the interrupt for the dma device if an fmc
+
+Child node required properties:
+  - reg : must contain chip select number in first cell of address, must
+	  be 1 tuple long
+  - compatible : may contain "vendor,part", must include "jedec,spi-nor"
+		when attached to SPI flash (see spi-nor.txt binding).
+
+Child node optional properties:
+  - label           - (optional) name to assign to mtd, default os assigned
+
+Child node optional properties for SPI mode (may be ignored):
+  - spi-max-frequency - (optional) max frequency of spi bus
+  - spi-cpol        - (optional) Empty property indicating device requires
+			inverse clock polarity (CPOL) mode (boolean)
+  - spi-cpha        - (optional) Empty property indicating device requires
+			shifted clock phase (CPHA) mode (boolean)
+  - spi-tx-bus-width - (optional) The bus width(number of data wires) that
+                        used for MOSI. Defaults to 1 if not present.
+  - spi-rx-bus-width - (optional) The bus width(number of data wires) that
+                        used for MOSI. Defaults to 1 if not present.
+
+Grandchild node optional properties:
+ - see mtd/partiton.txt for partitioning bindings and mtd naming
+
+
+Example:
+
+fmc: fmc at 1e620000 {
+	compatible = "aspeed,ast2400-fmc";
+	reg = < 0x1e620000 0x94
+		0x20000000 0x02000000
+		0x22000000 0x02000000 >;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	flash at 0 {
+		reg = < 0 >;
+		compatible = "jedec,spi-nor" ;
+		label = "bmc";
+		/* spi-max-frequency = <>; */
+		/* m25p,fast-read; */
+		#address-cells = <1>;
+		#size-cells = <1>;
+		boot at 0 {
+			label = "boot-loader";
+			reg = < 0 0x8000 >
+		}
+		image at 8000 {
+			label = "kernel-image";
+			reg = < 0x8000 0x1f8000 >
+		}
+	};
+	flash at 1 {
+		reg = < 1 >;
+		compatible = "jedec,spi-nor" ;
+		label = "alt";
+		/* spi-max-frequency = <>; */
+		status = "fail";
+		/* m25p,fast-read; */
+	};
+};
diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
index 4a682ee0f632..96148600fdab 100644
--- a/drivers/mtd/spi-nor/Kconfig
+++ b/drivers/mtd/spi-nor/Kconfig
@@ -76,4 +76,16 @@ config SPI_NXP_SPIFI
 	  Flash. Enable this option if you have a device with a SPIFI
 	  controller and want to access the Flash as a mtd device.
 
+config ASPEED_FLASH_SPI
+	tristate "Aspeed flash controllers in SPI mode"
+	depends on HAS_IOMEM && OF
+	depends on ARCH_ASPEED || COMPILE_TEST
+	# IO_SPACE_LIMIT must be equivalent to (~0UL)
+	depends on !NEED_MACH_IO_H
+	help
+	  This enables support for the New Static Memory Controller
+	  (FMC) in the Aspeed SoCs (AST2400 and AST2500) when attached
+	  to SPI nor chips, and support for the SPI Memory controller
+	  (SPI) for the BIOS.
+
 endif # MTD_SPI_NOR
diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile
index 121695e83542..c3174ebc45c2 100644
--- a/drivers/mtd/spi-nor/Makefile
+++ b/drivers/mtd/spi-nor/Makefile
@@ -4,4 +4,5 @@ obj-$(CONFIG_SPI_CADENCE_QUADSPI)	+= cadence-quadspi.o
 obj-$(CONFIG_SPI_FSL_QUADSPI)	+= fsl-quadspi.o
 obj-$(CONFIG_SPI_HISI_SFC)	+= hisi-sfc.o
 obj-$(CONFIG_MTD_MT81xx_NOR)    += mtk-quadspi.o
+obj-$(CONFIG_ASPEED_FLASH_SPI)	+= aspeed-smc.o
 obj-$(CONFIG_SPI_NXP_SPIFI)	+= nxp-spifi.o
diff --git a/drivers/mtd/spi-nor/aspeed-smc.c b/drivers/mtd/spi-nor/aspeed-smc.c
new file mode 100644
index 000000000000..a1b9d6711f73
--- /dev/null
+++ b/drivers/mtd/spi-nor/aspeed-smc.c
@@ -0,0 +1,746 @@
+/*
+ * ASPEED Static Memory Controller driver
+ *
+ * Copyright (c) 2015-2016, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/spi-nor.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/sysfs.h>
+
+#define DEVICE_NAME	"aspeed-smc"
+
+/*
+ * In user mode all data bytes read or written to the chip decode address
+ * range are transferred to or from the SPI bus. The range is treated as a
+ * fifo of arbitratry 1, 2, or 4 byte width but each write has to be aligned
+ * to its size.  The address within the multiple 8kB range is ignored when
+ * sending bytes to the SPI bus.
+ *
+ * On the arm architecture, as of Linux version 4.3, memcpy_fromio and
+ * memcpy_toio on little endian targets use the optimized memcpy routines
+ * that were designed for well behavied memory storage.  These routines
+ * have a stutter if the source and destination are not both word aligned,
+ * once with a duplicate access to the source after aligning to the
+ * destination to a word boundary, and again with a duplicate access to
+ * the source when the final byte count is not word aligned.
+ *
+ * When writing or reading the fifo this stutter discards data or sends
+ * too much data to the fifo and can not be used by this driver.
+ *
+ * While the low level io string routines that implement the insl family do
+ * the desired accesses and memory increments, the cross architecture io
+ * macros make them essentially impossible to use on a memory mapped address
+ * instead of a a token from the call to iomap of an io port.
+ *
+ * These fifo routines use readl and friends to a constant io port and update
+ * the memory buffer pointer and count via explicit code. The final updates
+ * to len are optimistically suppressed.
+ */
+
+static void aspeed_smc_from_fifo(void *buf, const void __iomem *iop, size_t len)
+{
+	if (!len)
+		return;
+
+	/* Expect a 4 byte input port.  Otherwise just read bytes. */
+	if (unlikely((unsigned long)iop & 3)) {
+		while (len--) {
+			*(u8 *)buf = readb(iop);
+			buf++;
+		}
+	}
+
+	/* Align target to word: first byte then half word */
+	if ((unsigned long)buf & 1) {
+		*(u8 *)buf = readb(iop);
+		buf++;
+		len--;
+	}
+	if (((unsigned long)buf & 2) && (len >= 2)) {
+		*(u16 *)buf = readw(iop);
+		buf += 2;
+		len -= 2;
+	}
+
+	/* Transfer words, then remaining halfword and remaining byte */
+	while (len >= 4) {
+		*(u32 *)buf = readl(iop);
+		buf += 4;
+		len -= 4;
+	}
+	if (len & 2) {
+		*(u16 *)buf = readw(iop);
+		buf += 2;
+	}
+	if (len & 1)
+		*(u8 *)buf = readb(iop);
+}
+
+static void aspeed_smc_to_fifo(void __iomem *iop, const void *buf, size_t len)
+{
+	if (!len)
+		return;
+
+	/* Expect a 4 byte output port.  Otherwise just write bytes. */
+	if ((unsigned long)iop & 3) {
+		while (len--) {
+			writeb(*(u8 *)buf, iop);
+			buf++;
+		}
+		return;
+	}
+
+	/* Align target to word: first byte then half word */
+	if ((unsigned long)buf & 1) {
+		writeb(*(u8 *)buf, iop);
+		buf++;
+		len--;
+	}
+	if (((unsigned long)buf & 2) && (len >= 2)) {
+		writew(*(u16 *)buf, iop);
+		buf += 2;
+		len -= 2;
+	}
+
+	/* Transfer words, then remaining halfword and remaining byte */
+	while (len >= 4) {
+		writel(*(u32 *)buf, iop);
+		buf += 4;
+		len -= 4;
+	}
+	if (len & 2) {
+		writew(*(u16 *)buf, iop);
+		buf += 2;
+	}
+	if (len & 1)
+		writeb(*(u8 *)buf, iop);
+}
+
+enum smc_flash_type {
+	smc_type_nor = 0,	/* controller connected to nor flash */
+	smc_type_nand = 1,	/* controller connected to nand flash */
+	smc_type_spi = 2,	/* controller connected to spi flash */
+};
+
+struct aspeed_smc_info {
+	u32 maxsize;		/* maximum size of 1 chip window */
+	u8 nce;			/* number of chip enables */
+	u8 maxwidth;		/* max width of spi bus */
+	bool hastype;		/* flash type field exists in cfg reg */
+	u8 we0;			/* shift for write enable bit for ce 0 */
+	u8 ctl0;		/* offset in regs of ctl for ce 0 */
+	u8 time;		/* offset in regs of timing */
+	u8 misc;		/* offset in regs of misc settings */
+};
+
+static struct aspeed_smc_info fmc_2400_info = {
+	.maxsize = 64 * 1024 * 1024,
+	.nce = 5,
+	.maxwidth = 4,
+	.hastype = true,
+	.we0 = 16,
+	.ctl0 = 0x10,
+	.time = 0x94,
+	.misc = 0x54,
+};
+
+static struct aspeed_smc_info smc_2400_info = {
+	.maxsize = 64 * 1024 * 1024,
+	.nce = 1,
+	.maxwidth = 2,
+	.hastype = false,
+	.we0 = 0,
+	.ctl0 = 0x04,
+	.time = 0x14,
+	.misc = 0x10,
+};
+
+static struct aspeed_smc_info fmc_2500_info = {
+	.maxsize = 256 * 1024 * 1024,
+	.nce = 3,
+	.maxwidth = 2,
+	.hastype = true,
+	.we0 = 16,
+	.ctl0 = 0x10,
+	.time = 0x94,
+	.misc = 0x54,
+};
+
+static struct aspeed_smc_info smc_2500_info = {
+	.maxsize = 128 * 1024 * 1024,
+	.nce = 2,
+	.maxwidth = 2,
+	.hastype = false,
+	.we0 = 16,
+	.ctl0 = 0x10,
+	.time = 0x94,
+	.misc = 0x54,
+};
+
+enum smc_ctl_reg_value {
+	smc_base,		/* base value without mode for other commands */
+	smc_read,		/* command reg for (maybe fast) reads */
+	smc_write,		/* command reg for writes with timings */
+	smc_num_ctl_reg_values	/* last value to get count of commands */
+};
+
+struct aspeed_smc_controller;
+
+struct aspeed_smc_chip {
+	int cs;
+	struct aspeed_smc_controller *controller;
+	__le32 __iomem *ctl;			/* control register */
+	void __iomem *base;			/* base of chip window */
+	__le32 ctl_val[smc_num_ctl_reg_values];	/* controls with timing */
+	enum smc_flash_type type;		/* what type of flash */
+	struct spi_nor nor;
+};
+
+struct aspeed_smc_controller {
+	struct device *dev;
+
+	struct mutex mutex;			/* controller access mutex */
+	const struct aspeed_smc_info *info;	/* type info of controller */
+	void __iomem *regs;			/* controller registers */
+	void __iomem *windows;			/* per-chip windows resource */
+
+	struct aspeed_smc_chip *chips[0];	/* pointers to attached chips */
+};
+
+/*
+ * FMC Type setting Register
+ *   or
+ * SPI Flash Configuration Register
+ */
+#define CONFIG_REG			0x0
+
+/*
+ * CE Control Register
+ */
+#define CE_CONTROL_REG			0x4
+#define    CE0_CONTROL_EXTENDED		    BIT(0)
+
+/* CE0 Control Register (depends on the controller type) */
+#define CONTROL_SPI_AAF_MODE BIT(31)
+#define CONTROL_SPI_IO_MODE_MASK GENMASK(30, 28)
+#define CONTROL_SPI_IO_DUAL_DATA BIT(29)
+#define CONTROL_SPI_IO_DUAL_ADDR_DATA (BIT(29) | BIT(28))
+#define CONTROL_SPI_IO_QUAD_DATA BIT(30)
+#define CONTROL_SPI_IO_QUAD_ADDR_DATA (BIT(30) | BIT(28))
+#define CONTROL_SPI_CE_INACTIVE_SHIFT 24
+#define CONTROL_SPI_CE_INACTIVE_MASK GENMASK(27, CONTROL_SPI_CE_INACTIVE_SHIFT)
+/* 0 = 16T ... 15 = 1T   T=HCLK */
+#define CONTROL_SPI_COMMAND_SHIFT 16
+#define CONTROL_SPI_DUMMY_CYCLE_COMMAND_OUTPUT BIT(15)
+#define CONTROL_SPI_IO_DUMMY_CYCLES_HI BIT(14)
+#define CONTROL_SPI_IO_DUMMY_CYCLES_HI_SHIFT (14 - 2)
+#define CONTROL_SPI_IO_ADDRESS_4B BIT(13) /* 2400-smc */
+#define CONTROL_SPI_CLK_DIV4 BIT(13) /* FMC, 2500 */
+#define CONTROL_SPI_RW_MERGE BIT(12)
+#define CONTROL_SPI_IO_DUMMY_CYCLES_LO_SHIFT 6
+#define CONTROL_SPI_IO_DUMMY_CYCLES_LO GENMASK(7, \
+				       CONTROL_SPI_IO_DUMMY_CYCLES_LO_SHIFT)
+#define CONTROL_SPI_IO_DUMMY_CYCLES_MASK (CONTROL_SPI_IO_DUMMY_CYCLES_HI | \
+					  CONTROL_SPI_IO_DUMMY_CYCLES_LO)
+#define CONTROL_SPI_CLOCK_FREQ_SEL_SHIFT 8
+#define CONTROL_SPI_CLOCK_FREQ_SEL_MASK GENMASK(11, \
+					CONTROL_SPI_CLOCK_FREQ_SEL_SHIFT)
+#define CONTROL_SPI_LSB_FIRST BIT(5)
+#define CONTROL_SPI_CLOCK_MODE_3 BIT(4)
+#define CONTROL_SPI_IN_DUAL_DATA BIT(3)
+#define CONTROL_SPI_CE_STOP_ACTIVE_CONTROL BIT(2)
+#define CONTROL_SPI_COMMAND_MODE_MASK GENMASK(1, 0)
+#define CONTROL_SPI_COMMAND_MODE_NORMAL (0)
+#define CONTROL_SPI_COMMAND_MODE_FREAD (1)
+#define CONTROL_SPI_COMMAND_MODE_WRITE (2)
+#define CONTROL_SPI_COMMAND_MODE_USER (3)
+
+#define CONTROL_SPI_KEEP_MASK (CONTROL_SPI_AAF_MODE | \
+	CONTROL_SPI_CE_INACTIVE_MASK | CONTROL_SPI_CLK_DIV4 | \
+	CONTROL_SPI_IO_DUMMY_CYCLES_MASK | CONTROL_SPI_CLOCK_FREQ_SEL_MASK | \
+	CONTROL_SPI_LSB_FIRST | CONTROL_SPI_CLOCK_MODE_3)
+
+/* Segment Address Registers */
+#define SEGMENT_ADDR_REG0		0x30
+#define     SEGMENT_ADDR_START(_r)	    ((((_r) >> 16) & 0xFF) << 23)
+#define     SEGMENT_ADDR_END(_r)	    ((((_r) >> 24) & 0xFF) << 23)
+
+static u32 spi_control_fill_opcode(u8 opcode)
+{
+	return ((u32)(opcode)) << CONTROL_SPI_COMMAND_SHIFT;
+}
+
+static inline u32 aspeed_smc_chip_write_bit(struct aspeed_smc_chip *chip)
+{
+	return ((u32)1 << (chip->controller->info->we0 + chip->cs));
+}
+
+static void aspeed_smc_chip_check_config(struct aspeed_smc_chip *chip)
+{
+	struct aspeed_smc_controller *controller = chip->controller;
+	u32 reg;
+
+	reg = readl(controller->regs + CONFIG_REG);
+
+	if (!(reg & aspeed_smc_chip_write_bit(chip))) {
+		dev_dbg(controller->dev,
+			"config write is not set ! @%p: 0x%08x\n",
+			controller->regs + CONFIG_REG, reg);
+		reg |= aspeed_smc_chip_write_bit(chip);
+		writel(reg, controller->regs + CONFIG_REG);
+	}
+}
+
+static void aspeed_smc_start_user(struct spi_nor *nor)
+{
+	struct aspeed_smc_chip *chip = nor->priv;
+	u32 ctl = chip->ctl_val[smc_base];
+
+	/*
+	 * When the chip is controlled in user mode, we need write
+	 * access to send the opcodes to it. So check the config.
+	 */
+	aspeed_smc_chip_check_config(chip);
+
+	ctl |= CONTROL_SPI_COMMAND_MODE_USER |
+		CONTROL_SPI_CE_STOP_ACTIVE_CONTROL;
+	writel(ctl, chip->ctl);
+
+	ctl &= ~CONTROL_SPI_CE_STOP_ACTIVE_CONTROL;
+	writel(ctl, chip->ctl);
+}
+
+static void aspeed_smc_stop_user(struct spi_nor *nor)
+{
+	struct aspeed_smc_chip *chip = nor->priv;
+
+	u32 ctl = chip->ctl_val[smc_read];
+	u32 ctl2 = ctl | CONTROL_SPI_COMMAND_MODE_USER |
+		CONTROL_SPI_CE_STOP_ACTIVE_CONTROL;
+
+	writel(ctl2, chip->ctl);	/* stop user CE control */
+	writel(ctl, chip->ctl);		/* default to fread or read */
+}
+
+static int aspeed_smc_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
+{
+	struct aspeed_smc_chip *chip = nor->priv;
+
+	mutex_lock(&chip->controller->mutex);
+
+	aspeed_smc_start_user(nor);
+	aspeed_smc_to_fifo(chip->base, &opcode, 1);
+	aspeed_smc_from_fifo(buf, chip->base, len);
+	aspeed_smc_stop_user(nor);
+
+	mutex_unlock(&chip->controller->mutex);
+
+	return 0;
+}
+
+static int aspeed_smc_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
+				int len)
+{
+	struct aspeed_smc_chip *chip = nor->priv;
+
+	mutex_lock(&chip->controller->mutex);
+
+	aspeed_smc_start_user(nor);
+	aspeed_smc_to_fifo(chip->base, &opcode, 1);
+	aspeed_smc_to_fifo(chip->base, buf, len);
+	aspeed_smc_stop_user(nor);
+
+	mutex_unlock(&chip->controller->mutex);
+
+	return 0;
+}
+
+static void aspeed_smc_send_cmd_addr(struct spi_nor *nor, u8 cmd, u32 addr)
+{
+	struct aspeed_smc_chip *chip = nor->priv;
+	__be32 temp;
+	u32 cmdaddr;
+
+	switch (nor->addr_width) {
+	default:
+		WARN_ONCE(1, "Unexpected address width %u, defaulting to 3\n",
+			  nor->addr_width);
+		/* FALLTHROUGH */
+	case 3:
+		cmdaddr = addr & 0xFFFFFF;
+
+		cmdaddr |= (u32)cmd << 24;
+
+		temp = cpu_to_be32(cmdaddr);
+		aspeed_smc_to_fifo(chip->base, &temp, 4);
+		break;
+	case 4:
+		temp = cpu_to_be32(addr);
+		aspeed_smc_to_fifo(chip->base, &cmd, 1);
+		aspeed_smc_to_fifo(chip->base, &temp, 4);
+		break;
+	}
+}
+
+static ssize_t aspeed_smc_read_user(struct spi_nor *nor, loff_t from, size_t len,
+				    u_char *read_buf)
+{
+	struct aspeed_smc_chip *chip = nor->priv;
+
+	mutex_lock(&chip->controller->mutex);
+
+	aspeed_smc_start_user(nor);
+	aspeed_smc_send_cmd_addr(nor, nor->read_opcode, from);
+	aspeed_smc_from_fifo(read_buf, chip->base, len);
+	aspeed_smc_stop_user(nor);
+
+	mutex_unlock(&chip->controller->mutex);
+
+	return len;
+}
+
+static ssize_t aspeed_smc_write_user(struct spi_nor *nor, loff_t to, size_t len,
+				     const u_char *write_buf)
+{
+	struct aspeed_smc_chip *chip = nor->priv;
+
+	mutex_lock(&chip->controller->mutex);
+
+	aspeed_smc_start_user(nor);
+	aspeed_smc_send_cmd_addr(nor, nor->program_opcode, to);
+	aspeed_smc_to_fifo(chip->base, write_buf, len);
+	aspeed_smc_stop_user(nor);
+
+	mutex_unlock(&chip->controller->mutex);
+
+	return len;
+}
+
+static int aspeed_smc_remove(struct platform_device *dev)
+{
+	struct aspeed_smc_chip *chip;
+	struct aspeed_smc_controller *controller = platform_get_drvdata(dev);
+	int n;
+
+	for (n = 0; n < controller->info->nce; n++) {
+		chip = controller->chips[n];
+		if (chip)
+			mtd_device_unregister(&chip->nor.mtd);
+	}
+
+	return 0;
+}
+
+const struct of_device_id aspeed_smc_matches[] = {
+	{ .compatible = "aspeed,ast2400-fmc", .data = &fmc_2400_info },
+	{ .compatible = "aspeed,ast2400-smc", .data = &smc_2400_info },
+	{ .compatible = "aspeed,ast2500-fmc", .data = &fmc_2500_info },
+	{ .compatible = "aspeed,ast2500-smc", .data = &smc_2500_info },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, aspeed_smc_matches);
+
+static struct platform_device *
+of_platform_device_create_or_find(struct device_node *child,
+				  struct device *parent)
+{
+	struct platform_device *cdev;
+
+	cdev = of_platform_device_create(child, NULL, parent);
+	if (!cdev)
+		cdev = of_find_device_by_node(child);
+	return cdev;
+}
+
+static void __iomem *window_start(struct aspeed_smc_controller *controller,
+				  struct resource *r, unsigned int n)
+{
+	u32 offset = 0;
+	u32 reg;
+
+	if (controller->info->nce > 1) {
+		reg = readl(controller->regs + SEGMENT_ADDR_REG0 + n * 4);
+
+		if (SEGMENT_ADDR_START(reg) >= SEGMENT_ADDR_END(reg))
+			return NULL;
+
+		offset = SEGMENT_ADDR_START(reg) - r->start;
+	}
+
+	return controller->windows + offset;
+}
+
+static void aspeed_smc_chip_enable_write(struct aspeed_smc_chip *chip)
+{
+	struct aspeed_smc_controller *controller = chip->controller;
+	u32 reg;
+
+	reg = readl(controller->regs + CONFIG_REG);
+	dev_dbg(controller->dev, "config reg @%p: 0x%08x\n",
+		controller->regs + CONFIG_REG, reg);
+
+	reg |= aspeed_smc_chip_write_bit(chip);
+	writel(reg, controller->regs + CONFIG_REG);
+}
+
+static void aspeed_smc_chip_set_type(struct aspeed_smc_chip *chip, int type)
+{
+	struct aspeed_smc_controller *controller = chip->controller;
+	u32 reg;
+
+	reg = readl(controller->regs + CONFIG_REG);
+	dev_dbg(controller->dev, "config reg @%p: 0x%08x\n",
+		controller->regs + CONFIG_REG, reg);
+
+	chip->type = type;
+
+	reg &= ~(3 << (chip->cs * 2));
+	reg |= chip->type << (chip->cs * 2);
+	writel(reg, controller->regs + CONFIG_REG);
+}
+
+static int aspeed_smc_chip_setup_init(struct aspeed_smc_chip *chip,
+				      struct resource *r)
+{
+	struct aspeed_smc_controller *controller = chip->controller;
+	const struct aspeed_smc_info *info = controller->info;
+	u32 reg;
+
+	/*
+	 * Always turn on the write enable bit to allow opcodes to be
+	 * sent in user mode.
+	 */
+	aspeed_smc_chip_enable_write(chip);
+
+	/* The driver only supports SPI type flash for the moment */
+	if (info->hastype)
+		aspeed_smc_chip_set_type(chip, smc_type_spi);
+
+	/*
+	 * Configure chip base address in memory
+	 */
+	chip->base = window_start(controller, r, chip->cs);
+	if (!chip->base) {
+		dev_warn(chip->nor.dev, "CE segment window closed.\n");
+		return -1;
+	}
+
+	/*
+	 * Read the existing control register to get basic values.
+	 *
+	 * XXX This register probably needs more sanitation.
+	 *
+	 * Do we need support for mode 3 vs mode 0 clock phasing?
+	 */
+	reg = readl(chip->ctl);
+	dev_dbg(controller->dev, "control register: %08x\n", reg);
+
+	if ((reg & CONTROL_SPI_KEEP_MASK) != reg) {
+		chip->ctl_val[smc_base] = reg & CONTROL_SPI_KEEP_MASK;
+		dev_info(controller->dev,
+			 "control register changed to: %08x\n",
+			 chip->ctl_val[smc_base]);
+	}
+
+	/*
+	 * Retain the prior value of the control register as the
+	 * default if it was normal access mode. Otherwise start with
+	 * the sanitized base value set to read mode.
+	 */
+	if ((reg & CONTROL_SPI_COMMAND_MODE_MASK) ==
+	    CONTROL_SPI_COMMAND_MODE_NORMAL)
+		chip->ctl_val[smc_read] = reg;
+	else
+		chip->ctl_val[smc_read] = chip->ctl_val[smc_base] |
+			CONTROL_SPI_COMMAND_MODE_NORMAL;
+
+	return 0;
+}
+
+static void aspeed_smc_chip_setup_finish(struct aspeed_smc_chip *chip)
+{
+	struct aspeed_smc_controller *controller = chip->controller;
+	u32 reg;
+
+	/*
+	 * Set 4 byte mode in the chip controller register and also in
+	 * controller config register. The BMC flash controller is
+	 * strapped by hardware, or autodetected, but the SPI flash
+	 * controller of the AST2500 still needs to be set.
+	 */
+	if (chip->nor.mtd.size > SZ_16M) {
+		chip->ctl_val[smc_base] |= CONTROL_SPI_IO_ADDRESS_4B;
+
+		/*
+		 * The SPI flash controller of the AST2400 does not
+		 * have such a setting.
+		 */
+		if (chip->controller->info == &smc_2500_info) {
+			reg = readl(controller->regs + CE_CONTROL_REG);
+			reg |= 1 << chip->cs;
+			writel(reg, controller->regs + CE_CONTROL_REG);
+		}
+	}
+
+	chip->ctl_val[smc_write] = chip->ctl_val[smc_base] |
+		spi_control_fill_opcode(chip->nor.program_opcode) |
+		CONTROL_SPI_COMMAND_MODE_WRITE;
+
+	/*
+	 * XXX TODO
+	 * Enable fast read mode as required here.
+	 * Adjust clocks if fast read and write are supported.
+	 * Interpret spi-nor flags to adjust controller settings.
+	 * Check if resource size big enough for detected chip and
+	 * add support assisted (normal or fast-) read and dma.
+	 */
+}
+
+static int aspeed_smc_probe(struct platform_device *pdev)
+{
+	struct aspeed_smc_controller *controller;
+	const struct of_device_id *match;
+	const struct aspeed_smc_info *info;
+	struct resource *r;
+	struct device_node *child;
+	int err = 0;
+	unsigned int n;
+
+	match = of_match_device(aspeed_smc_matches, &pdev->dev);
+	if (!match || !match->data)
+		return -ENODEV;
+	info = match->data;
+
+	controller = devm_kzalloc(&pdev->dev, sizeof(*controller) +
+		info->nce * sizeof(controller->chips[0]), GFP_KERNEL);
+	if (!controller)
+		return -ENOMEM;
+	controller->info = info;
+
+	mutex_init(&controller->mutex);
+	platform_set_drvdata(pdev, controller);
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	controller->regs = devm_ioremap_resource(&pdev->dev, r);
+	if (IS_ERR(controller->regs))
+		return PTR_ERR(controller->regs);
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	controller->windows = devm_ioremap_resource(&pdev->dev, r);
+	if (IS_ERR(controller->windows))
+		return PTR_ERR(controller->windows);
+
+	controller->dev = &pdev->dev;
+
+	/* The pinmux or bootloader will disable the legacy mode controller */
+
+	/*
+	 * XXX Need to add arbitration to the SMC (BIOS) controller if access
+	 * is shared by the host.
+	 */
+	for_each_available_child_of_node(controller->dev->of_node, child) {
+		struct platform_device *cdev;
+		struct aspeed_smc_chip *chip;
+
+		/* This version does not support nand or nor flash devices. */
+		if (!of_device_is_compatible(child, "jedec,spi-nor"))
+			continue;
+
+		/*
+		 * create a platform device from the of node.  If the device
+		 * already was created (eg from a prior bind/unbind cycle)
+		 * reuse it.
+		 *
+		 * The creating the device node for the child here allows its
+		 * use for error reporting via dev_err below.
+		 */
+		cdev = of_platform_device_create_or_find(child,
+							 controller->dev);
+		if (!cdev)
+			continue;
+
+		err = of_property_read_u32(child, "reg", &n);
+		if (err == -EINVAL && info->nce == 1)
+			n = 0;
+		else if (err || n >= info->nce)
+			continue;
+		if (controller->chips[n]) {
+			dev_err(&cdev->dev,
+				"chip-id %u already in use in use by %s\n",
+				n, dev_name(controller->chips[n]->nor.dev));
+			continue;
+		}
+
+		chip = devm_kzalloc(controller->dev, sizeof(*chip), GFP_KERNEL);
+		if (!chip)
+			continue;
+		chip->controller = controller;
+		chip->ctl = controller->regs + info->ctl0 + n * 4;
+		chip->cs = n;
+
+		chip->nor.dev = &cdev->dev;
+		chip->nor.priv = chip;
+		spi_nor_set_flash_node(&chip->nor, child);
+		chip->nor.mtd.name = of_get_property(child, "label", NULL);
+		chip->nor.read = aspeed_smc_read_user;
+		chip->nor.write = aspeed_smc_write_user;
+		chip->nor.read_reg = aspeed_smc_read_reg;
+		chip->nor.write_reg = aspeed_smc_write_reg;
+
+		aspeed_smc_chip_setup_init(chip, r);
+
+		/*
+		 * XXX Add support for SPI_NOR_QUAD and SPI_NOR_DUAL attach
+		 * when board support is present as determined by of property.
+		 */
+		err = spi_nor_scan(&chip->nor, NULL, SPI_NOR_NORMAL);
+		if (err)
+			continue;
+
+		aspeed_smc_chip_setup_finish(chip);
+
+		err = mtd_device_register(&chip->nor.mtd, NULL, 0);
+		if (err)
+			continue;
+		controller->chips[n] = chip;
+	}
+
+	/* Were any children registered? */
+	for (n = 0; n < info->nce; n++)
+		if (controller->chips[n])
+			break;
+
+	if (n == info->nce)
+		return -ENODEV;
+
+	return 0;
+}
+
+static struct platform_driver aspeed_smc_driver = {
+	.probe = aspeed_smc_probe,
+	.remove = aspeed_smc_remove,
+	.driver = {
+		.name = DEVICE_NAME,
+		.of_match_table = aspeed_smc_matches,
+	}
+};
+
+module_platform_driver(aspeed_smc_driver);
+
+MODULE_DESCRIPTION("ASPEED Static Memory Controller Driver");
+MODULE_AUTHOR("Milton Miller");
+MODULE_LICENSE("GPL v2");
-- 
2.7.4



From cyrille.pitchen at atmel.com  Mon Oct 17 10:08:49 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Mon, 17 Oct 2016 19:08:49 +0200
Subject: [PATCH v2, 1/1] mtd: devices: m25p80: Add PM suspend resume
 support
In-Reply-To: <1473710494-4084-1-git-send-email-kdasu.kdev@gmail.com>
References: <1473710494-4084-1-git-send-email-kdasu.kdev@gmail.com>
Message-ID: <4fe502a4-ee01-3fb8-6697-161de814596e@atmel.com>

Hi Kamal,

Le 12/09/2016 ? 22:01, Kamal Dasu a ?crit :
> Adding PM support so as to be able to probe spi-nor flash
> on resume. There are vendor specific commands to setup
> the transfer mode and enable read/write as part of
> spi_nor_scan(), done on initial probe and needed on resume().
> The spi-nor structure is private to the m25p driver and hence
> is the only place this can be done without having to duplicate
> code in controller driver.

Just to be sure I've understood the purpose of this patch: here we suppose
that the SPI NOR memory power supply was cut when the CPU entered its suspend
mode. So when the CPU is resumed, the SPI NOR memory power supply is enabled
again as well and the internal state of the memory is reset.

Depending on the manufacturer, we may need to send dedicated commands so the
memory is ready again (for instance, a Global Unlock Block command for SST
memories so we can perform Sector Erase and Page Program operations).
Those commands are sent from spi_nor_scan(). Hence you call spi_nor_scan()
once again from the resume callback.

If so, your patch does make sense but I wonder whether some operations done
inside spi_nor_scan() and not related to the memory itself but more to other
layers like mtd (struct mtd_info) could always be safely performed a second
time. I don't know if that issue already exists or would ever exist, if so
it might be interesting to find a mean to tell spi_nor_scan() whether it's
called for the first time on this memory (boot) or not (resume).

Best regards,

Cyrille


> Signed-off-by: Kamal Dasu <kdasu.kdev at gmail.com>
> ---
>  drivers/mtd/devices/m25p80.c | 68 +++++++++++++++++++++++++++++++-------------
>  1 file changed, 48 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
> index 9cf7fcd..48c3f64 100644
> --- a/drivers/mtd/devices/m25p80.c
> +++ b/drivers/mtd/devices/m25p80.c
> @@ -186,6 +186,39 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
>  }
>  
>  /*
> + * scan for spi nor flash vendor parts and setup
> + * read/write mode
> + */
> +static int m25p_nor_flash_scan(struct device *dev)
> +{
> +	struct m25p *flash = dev_get_drvdata(dev);
> +	struct flash_platform_data	*data;
> +	char *flash_name = NULL;
> +	enum read_mode mode = SPI_NOR_NORMAL;
> +
> +	data = dev_get_platdata(dev);
> +
> +	/* For some (historical?) reason many platforms provide two different
> +	 * names in flash_platform_data: "name" and "type". Quite often name is
> +	 * set to "m25p80" and then "type" provides a real chip name.
> +	 * If that's the case, respect "type" and ignore a "name".
> +	 */
> +	if (data && data->type)
> +		flash_name = data->type;
> +	else if (!strcmp(flash->spi->modalias, "spi-nor"))
> +		flash_name = NULL; /* auto-detect */
> +	else
> +		flash_name = flash->spi->modalias;
> +
> +	if (flash->spi->mode & SPI_RX_QUAD)
> +		mode = SPI_NOR_QUAD;
> +	else if (flash->spi->mode & SPI_RX_DUAL)
> +		mode = SPI_NOR_DUAL;
> +
> +	return spi_nor_scan(&flash->spi_nor, flash_name, mode);
> +}
> +
> +/*
>   * board specific setup should have ensured the SPI clock used here
>   * matches what the READ command supports, at least until this driver
>   * understands FAST_READ (for clocks over 25 MHz).
> @@ -195,8 +228,6 @@ static int m25p_probe(struct spi_device *spi)
>  	struct flash_platform_data	*data;
>  	struct m25p *flash;
>  	struct spi_nor *nor;
> -	enum read_mode mode = SPI_NOR_NORMAL;
> -	char *flash_name;
>  	int ret;
>  
>  	data = dev_get_platdata(&spi->dev);
> @@ -220,27 +251,11 @@ static int m25p_probe(struct spi_device *spi)
>  	spi_set_drvdata(spi, flash);
>  	flash->spi = spi;
>  
> -	if (spi->mode & SPI_RX_QUAD)
> -		mode = SPI_NOR_QUAD;
> -	else if (spi->mode & SPI_RX_DUAL)
> -		mode = SPI_NOR_DUAL;
> -
>  	if (data && data->name)
>  		nor->mtd.name = data->name;
>  
> -	/* For some (historical?) reason many platforms provide two different
> -	 * names in flash_platform_data: "name" and "type". Quite often name is
> -	 * set to "m25p80" and then "type" provides a real chip name.
> -	 * If that's the case, respect "type" and ignore a "name".
> -	 */
> -	if (data && data->type)
> -		flash_name = data->type;
> -	else if (!strcmp(spi->modalias, "spi-nor"))
> -		flash_name = NULL; /* auto-detect */
> -	else
> -		flash_name = spi->modalias;
> +	ret = m25p_nor_flash_scan(nor->dev);
>  
> -	ret = spi_nor_scan(nor, flash_name, mode);
>  	if (ret)
>  		return ret;
>  
> @@ -248,7 +263,6 @@ static int m25p_probe(struct spi_device *spi)
>  				   data ? data->nr_parts : 0);
>  }
>  
> -
>  static int m25p_remove(struct spi_device *spi)
>  {
>  	struct m25p	*flash = spi_get_drvdata(spi);
> @@ -319,10 +333,24 @@ static const struct of_device_id m25p_of_table[] = {
>  };
>  MODULE_DEVICE_TABLE(of, m25p_of_table);
>  
> +#ifdef CONFIG_PM_SLEEP
> +static int m25p_suspend(struct device *dev)
> +{
> +	return 0;
> +}
> +
> +static int m25p_resume(struct device *dev)
> +{
> +	return m25p_nor_flash_scan(dev);
> +}
> +#endif
> +static SIMPLE_DEV_PM_OPS(m25p_pm_ops, m25p_suspend, m25p_resume);
> +
>  static struct spi_driver m25p80_driver = {
>  	.driver = {
>  		.name	= "m25p80",
>  		.of_match_table = m25p_of_table,
> +		.pm	= &m25p_pm_ops,
>  	},
>  	.id_table	= m25p_ids,
>  	.probe	= m25p_probe,
> 



From pantelis.antoniou at konsulko.com  Mon Oct 17 12:01:39 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Mon, 17 Oct 2016 22:01:39 +0300
Subject: [PATCH 06/10] gpio: sam: Document bindings of SAM FPGA GPIO block
In-Reply-To: <20161010200346.GA24239@rob-hp-laptop>
References: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
 <1475853518-22264-7-git-send-email-pantelis.antoniou@konsulko.com>
 <20161010200346.GA24239@rob-hp-laptop>
Message-ID: <59521A70-4897-4F10-B757-E25245F8E05E@konsulko.com>

Hi Rob,

> On Oct 10, 2016, at 23:03 , Rob Herring <robh at kernel.org> wrote:
> 
> On Fri, Oct 07, 2016 at 06:18:34PM +0300, Pantelis Antoniou wrote:
>> From: Georgi Vlaev <gvlaev at juniper.net>
>> 
>> Add device tree bindings document for the GPIO driver of
>> Juniper's SAM FPGA.
>> 
>> Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
>> [Ported from Juniper kernel]
>> Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
>> ---
>> .../devicetree/bindings/gpio/jnx,gpio-sam.txt      | 110 +++++++++++++++++++++
>> 1 file changed, 110 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/gpio/jnx,gpio-sam.txt
>> 
>> diff --git a/Documentation/devicetree/bindings/gpio/jnx,gpio-sam.txt b/Documentation/devicetree/bindings/gpio/jnx,gpio-sam.txt
>> new file mode 100644
>> index 0000000..514c350
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/gpio/jnx,gpio-sam.txt
>> @@ -0,0 +1,110 @@
>> +Juniper SAM FPGA GPIO block
>> +
>> +The controller's registers are organized as sets of eight 32-bit
>> +registers with each set controlling a bank of up to 32 pins.  A single
>> +interrupt is shared for all of the banks handled by the controller.
>> +
>> +Required properties:
>> +
>> +- compatible:
>> +    Must be "jnx,gpio-sam"
>> +
>> +- #gpio-cells:
>> +    Should be <2>.  The first cell is the pin number (within the controller's
>> +    pin space), and the second is used for the following flags:
>> +	bit[0]: direction (0 = out, 1 = in)
>> +	bit[1]: init high
>> +	bit[2]: active low
>> +	bit[3]: open drain
>> +	bit[4]: open drain
> 
> Use and/or add to standard flags.
> 

OK.

>> +
>> +- gpio-controller:
>> +    Specifies that the node is a GPIO controller.
>> +
>> +Optional properties:
>> +
>> +- reg:
>> +    This driver is part of the SAM FPGA MFD driver, so the
>> +    address range is supplied by that driver. However you can
>> +    override using this property.
>> +
>> +- gpio-base:
>> +    Base of the GPIO pins of this instance. If not present use system allocated.
> 
> This probably needs to go.
> 

OK.

>> +
>> +- gpio-count:
> 
> ngpios instead.
> 

OK.

>> +    Number of GPIO pins of this instance. If not present read the number from
>> +    the one configured in the FPGA data. Maximum number is 512.
>> +
>> +- #interrupt-cells:
>> +    Should be <2>.  The first cell is the GPIO number, the second should specify
>> +    flags.  The following subset of flags is supported:
>> +    - bits[16,4:0] trigger type and level flags
>> +	bit  0: rising edge interrupt
>> +	bit  1: falling edge interrupt
>> +	bit  2: active high interrupt
>> +	bit  3: active low interrupt
>> +	bit  4: enable debounce
>> +	bit 16: signal is active low
> 
> What does this mean?
> 

I will reword.

>> +    See also Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
>> +
>> +- gpio-interrupts:
>> +    A number of triples that define the mapping of interrupt groupsb to a range of
>> +    pins. The first cell defines the interrupt group, the second is the start of
>> +    the pin range and the third the number of pins in the range.
> 
> Needs a vendor prefix.
> 

OK.

>> +
>> +- gpio-exports:
>> +    A subnode containing the list of pins that will be exported to user-space.
> 
> DT doesn't know about userspace. Drop this.
> 

OK, the export bit should go. 

>> +    Each subnode contains:
>> +    Required properties:
>> +	- pin: The gpio to be exported and the relevant flags.
>> +    Optional properties:
>> +        - label: The label to use for export; if not supplied use the node name.
>> +
>> +Example:
>> +
>> +gpio20: gpio-sam {
>> +	compatible = "jnx,gpio-sam";
>> +	gpio-controller;
>> +	interrupt-controller;
>> +	/* 1st cell: gpio pin
>> +	 * 2nd cell: flags (bit mask)
>> +	 * bit  0: rising edge interrupt
>> +	 * bit  1: falling edge interrupt
>> +	 * bit  2: active high interrupt
>> +	 * bit  3: active low interrupt
>> +	 * bit  4: enable debounce
>> +	 * bit 16: signal is active low
>> +	 */
>> +	#interrupt-cells = <2>;
>> +	#gpio-cells = <2>;
>> +	gpio-count = <340>;
>> +	/* 1st cell: gpio interrupt status bit
>> +	 * 2nd cell: 1st pin
>> +	 * 3rd cell: # of pins
>> +	 */
>> +	gpio-interrupts =
>> +		<0 0 32>,	/* TL / TQ */
>> +		<1 32 32>,	/* PIC 1 */
>> +		<2 32 32>,	/* PIC 1 spare */
>> +		<7 148 32>,	/* PIC 0 */
>> +		<8 170 32>,	/* PIC 0 spare */
>> +		<16 318 22>;	/* FPC */
>> +
>> +	gpio-exports {
>> +		/*
>> +		 * flags:
>> +		 * GPIOF_DIR_IN			bit 0=1
>> +		 * GPIOF_DIR_OUT		bit 0=0
>> +		 * GPIOF_INIT_HIGH		bit 1=1
>> +		 *   GPIOF_INIT_HIGH is raw, not translated
>> +		 * GPIOF_ACTIVE_LOW		bit 2=1
>> +		 * GPIOF_OPEN_DRAIN		bit 3=1
>> +		 * GPIOF_OPEN_SOURCE		bit 4=1
>> +		 * GPIOF_EXPORT			bit 5=1
>> +		 * GPIOF_EXPORT_CHANGEABLE      bit 6=1
>> +		 */
>> +		tl0-rst {
>> +			pin = < 8 0x24 >;
>> +		};
>> +	};
>> +};
>> -- 
>> 1.9.1



From pantelis.antoniou at konsulko.com  Mon Oct 17 12:03:35 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Mon, 17 Oct 2016 22:03:35 +0300
Subject: [PATCH 08/10] mtd: flash-sam: Bindings for Juniper's SAM FPGA
 flash
In-Reply-To: <20161010200704.GA28870@rob-hp-laptop>
References: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
 <1475853518-22264-9-git-send-email-pantelis.antoniou@konsulko.com>
 <20161010200704.GA28870@rob-hp-laptop>
Message-ID: <6D4CB7D2-D9FC-4B82-869F-550D1BF96996@konsulko.com>

Hi Rob,

> On Oct 10, 2016, at 23:07 , Rob Herring <robh at kernel.org> wrote:
> 
> gOn Fri, Oct 07, 2016 at 06:18:36PM +0300, Pantelis Antoniou wrote:
>> From: Georgi Vlaev <gvlaev at juniper.net>
>> 
>> Add binding document for Junipers Flash IP block present
>> in the SAM FPGA on PTX series of routers.
>> 
>> Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
>> [Ported from Juniper kernel]
>> Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
>> ---
>> .../devicetree/bindings/mtd/flash-sam.txt          | 31 ++++++++++++++++++++++
>> 1 file changed, 31 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/mtd/flash-sam.txt
>> 
>> diff --git a/Documentation/devicetree/bindings/mtd/flash-sam.txt b/Documentation/devicetree/bindings/mtd/flash-sam.txt
>> new file mode 100644
>> index 0000000..bdf1d78
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mtd/flash-sam.txt
>> @@ -0,0 +1,31 @@
>> +Flash device on a Juniper SAM FPGA
>> +
>> +These flash chips are found in the PTX series of Juniper routers.
>> +
>> +They are regular CFI compatible (Intel or AMD extended) flash chips with
>> +some special write protect/VPP bits that can be controlled by the machine's
>> +system controller.
> 
> And where's the description of the sys ctrlr?
> 

The system controller is Juniper IP. We?ll have to ask around about
specifics, and it?s pretty uninspiring stuff.

>> +
>> +Required properties:
>> +- compatible : must be "jnx,flash-sam"
>> +
>> +Optional properties:
>> +- reg : memory address for the flash chip, note that this is not
>> +required since usually the device is a subdevice of the SAM MFD
>> +driver which fills in the register fields.
>> +
>> +For the rest of the properties, see mtd-physmap.txt.
>> +
>> +The device tree may optionally contain sub-nodes describing partitions of the
>> +address space. See partition.txt for more detail.
>> +
>> +Example:
>> +
>> +flash_sam {
>> +	compatible = "jnx,flash-sam";
>> +	partition at 0 {
> 
> This should have a heirarchy of a controller node, a flash child node, 
> partitions child node, and partition child nodes.
> 

OK.

>> +		reg = <0x0 0x400000>;
>> +		label = "pic0-golden";
>> +		read-only;
>> +	};
>> +};
>> -- 
>> 1.9.1



From pantelis.antoniou at konsulko.com  Mon Oct 17 12:08:54 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Mon, 17 Oct 2016 22:08:54 +0300
Subject: [PATCH 2/4] mfd: ptxpmb-ext-cpld: Add documentation for PTXPMB
 extended CPLD
In-Reply-To: <20161010201031.GA31318@rob-hp-laptop>
References: <1475853574-22339-1-git-send-email-pantelis.antoniou@konsulko.com>
 <1475853574-22339-3-git-send-email-pantelis.antoniou@konsulko.com>
 <20161010201031.GA31318@rob-hp-laptop>
Message-ID: <96110C7A-A2F6-44A6-A72E-2B2E2A800AD6@konsulko.com>

Hi Rob,

> On Oct 10, 2016, at 23:10 , Rob Herring <robh at kernel.org> wrote:
> 
> On Fri, Oct 07, 2016 at 06:19:32PM +0300, Pantelis Antoniou wrote:
>> From: Georgi Vlaev <gvlaev at juniper.net>
>> 
>> Add DT bindings document for the PTXPMB extended CPLD device.
>> 
>> Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
>> [Ported from Juniper kernel]
>> Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
>> ---
>> .../bindings/mfd/jnx-ptxpmb-ext-cpld.txt           | 35 ++++++++++++++++++++++
>> 1 file changed, 35 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/mfd/jnx-ptxpmb-ext-cpld.txt
>> 
>> diff --git a/Documentation/devicetree/bindings/mfd/jnx-ptxpmb-ext-cpld.txt b/Documentation/devicetree/bindings/mfd/jnx-ptxpmb-ext-cpld.txt
>> new file mode 100644
>> index 0000000..098a548a
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mfd/jnx-ptxpmb-ext-cpld.txt
>> @@ -0,0 +1,35 @@
>> +* Device tree bindings for Juniper's PTXPMB Extended CPLD FPGA MFD driver
>> +
>> +The device supports a gpio block which is described in the
>> +jnx-gpio-ptxpmb-ext-cpld document.
>> +
>> +Required properties:
>> +
>> +- compatible:		"jnx,ptxpmb-ext-cpld"
>> +
>> +- reg:			contains offset/length value for device state control
>> +			registers space.
>> +
>> +Optional properties:
>> +
>> +- interrupts:		The interrupt line(s) the /IRQ signal(s) for the device is
>> +			connected to.
>> +
>> +- interrupt-parent:	The parent interrupt controller.
>> +
>> +Example:
>> +
>> +ext-cpld at 1,0 {
>> +	compatible = "jnx,ptxpmb-ext-cpld";
>> +	reg = <0x1 0 0x1000>;
> 
> What's the bus type here? Unit address is probably wrong.
> 

localbus on a gpmc memory controller.

>> +	interrupt-parent = <&mpic>;
>> +	interrupts = <7 2>, <8 2>;
>> +
>> +	gpio_ext_cpld: cpld-ext-gpio {
>> +		compatible = "jnx,gpio-ptxpmb-ext-cpld";
>> +		#gpio-cells = <2>;
>> +		#interrupt-cells = <2>;
>> +		gpio-controller;
>> +		interrupt-controller;
>> +	};
>> +};
>> -- 
>> 1.9.1



From pantelis.antoniou at konsulko.com  Mon Oct 17 12:10:01 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Mon, 17 Oct 2016 22:10:01 +0300
Subject: [PATCH 4/4] gpio: ptxpmb-ext-cpld: Document bindings of PTXPMB
 extended CPLD
In-Reply-To: <20161010201936.GB32418@rob-hp-laptop>
References: <1475853574-22339-1-git-send-email-pantelis.antoniou@konsulko.com>
 <1475853574-22339-5-git-send-email-pantelis.antoniou@konsulko.com>
 <20161010201936.GB32418@rob-hp-laptop>
Message-ID: <FECF48A5-4540-4370-B2E1-5EEC10EEA22B@konsulko.com>

Hi Rob,

> On Oct 10, 2016, at 23:19 , Rob Herring <robh at kernel.org> wrote:
> 
> On Fri, Oct 07, 2016 at 06:19:34PM +0300, Pantelis Antoniou wrote:
>> From: Georgi Vlaev <gvlaev at juniper.net>
>> 
>> Add device tree bindings document for the GPIO driver of
>> Juniper's PTXPMB extended CPLD.
>> 
>> Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
>> [Ported from Juniper kernel]
>> Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
>> ---
>> .../bindings/gpio/jnx,gpio-ptxpmb-ext-cpld.txt     | 36 ++++++++++++++++++++++
>> 1 file changed, 36 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/gpio/jnx,gpio-ptxpmb-ext-cpld.txt
>> 
>> diff --git a/Documentation/devicetree/bindings/gpio/jnx,gpio-ptxpmb-ext-cpld.txt b/Documentation/devicetree/bindings/gpio/jnx,gpio-ptxpmb-ext-cpld.txt
>> new file mode 100644
>> index 0000000..87f01b9
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/gpio/jnx,gpio-ptxpmb-ext-cpld.txt
>> @@ -0,0 +1,36 @@
>> +Juniper PTXPMB extended CPLD GPIO block
>> +
>> +Required properties:
>> +
>> +- compatible:
>> +    Must be "jnx,gpio-ptxpmb-ext-cpld"
> 
> Generally, '-gpio' would be last.
> 

OK.


>> +
>> +- #gpio-cells:
>> +    Should be <2>.  The first cell is the pin number (within the controller's
>> +    pin space), and the second is used for the following flags:
>> +	bit[0]: direction (0 = out, 1 = in)
>> +	bit[1]: init high
>> +	bit[2]: active low
> 
> Same comment as all the other gpio bindings...
> 
>> +
>> +- gpio-controller:
>> +    Specifies that the node is a GPIO controller.
>> +
>> +- interrupt-controller:
>> +    Specifies that the node is an interrupt controller.
>> +
>> +Optional properties:
>> +
>> +- reg:
>> +    Address and length of the register set for the device. Usually supplied
>> +    by the parent MFD device.
> 
> Make it required.
> 

Hmm, the current driver supplies that range via platform data (it?s an mfd driver).
What?s the take on mixing those?

>> +
>> +
>> +Example:
>> +
>> +gpio_ext_cpld: cpld-ext-gpio {
>> +	compatible = "jnx,gpio-ptxpmb-ext-cpld";
>> +	#gpio-cells = <2>;
>> +	#interrupt-cells = <2>;
>> +	gpio-controller;
>> +	interrupt-controller;
>> +};
>> -- 
>> 1.9.1



From boris.brezillon at free-electrons.com  Mon Oct 17 13:20:00 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Mon, 17 Oct 2016 22:20:00 +0200
Subject: [PATCH] mtd: nand: omap2: Fix module autoload
In-Reply-To: <1476721177-3425-1-git-send-email-javier@osg.samsung.com>
References: <1476721177-3425-1-git-send-email-javier@osg.samsung.com>
Message-ID: <20161017222000.79b8fe04@bbrezillon>

On Mon, 17 Oct 2016 13:19:37 -0300
Javier Martinez Canillas <javier at osg.samsung.com> wrote:

> If the driver is built as a module, autoload won't work because the module
> alias information is not filled. So user-space can't match the registered
> device with the corresponding module.
> 
> Export the module alias information using the MODULE_DEVICE_TABLE() macro.
> 
> Before this patch:
> 
> $ modinfo drivers/mtd/nand/omap2_nand.ko | grep alias
> alias:          platform:omap2-nand
> 
> After this patch:
> 
> $ modinfo drivers/mtd/nand/omap2_nand.ko | grep alias
> alias:          platform:omap2-nand
> alias:          of:N*T*Cti,omap2-nandC*
> alias:          of:N*T*Cti,omap2-nand
> 
> Signed-off-by: Javier Martinez Canillas <javier at osg.samsung.com>

Applied.

Thanks,

Boris

> 
> ---
> 
>  drivers/mtd/nand/omap2.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
> index 5513bfd9cdc9..0934c3b3f70e 100644
> --- a/drivers/mtd/nand/omap2.c
> +++ b/drivers/mtd/nand/omap2.c
> @@ -2197,6 +2197,7 @@ static const struct of_device_id omap_nand_ids[] = {
>  	{ .compatible = "ti,omap2-nand", },
>  	{},
>  };
> +MODULE_DEVICE_TABLE(of, omap_nand_ids);
>  
>  static struct platform_driver omap_nand_driver = {
>  	.probe		= omap_nand_probe,



From ray.jui at broadcom.com  Mon Oct 17 13:49:27 2016
From: ray.jui at broadcom.com (Ray Jui)
Date: Mon, 17 Oct 2016 13:49:27 -0700
Subject: [PATCH v2 2/2] arm64: dts: Updated NAND DT properties for NS2 SVK
In-Reply-To: <1469051631-7896-3-git-send-email-ray.jui@broadcom.com>
References: <1469051631-7896-1-git-send-email-ray.jui@broadcom.com>
 <1469051631-7896-3-git-send-email-ray.jui@broadcom.com>
Message-ID: <8832e18c-cd77-9fe1-8bd8-a2d65390666a@broadcom.com>

Hi Florian,

Would you be able to help to queue the following patch for v4.10? Sorry 
I did not include you in the "To" field of the original email.

Thanks,

Ray

On 7/20/2016 2:53 PM, Ray Jui wrote:
> This patch adds NAND DT properties for NS2 SVK to configure the bus
> width width and OOB sector size
>
> Signed-off-by: Prafulla Kota <prafulla.kota at broadcom.com>
> Signed-off-by: Ray Jui <ray.jui at broadcom.com>
> ---
>  arch/arm64/boot/dts/broadcom/ns2-svk.dts | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/broadcom/ns2-svk.dts b/arch/arm64/boot/dts/broadcom/ns2-svk.dts
> index 54ca40c..5ef0407 100644
> --- a/arch/arm64/boot/dts/broadcom/ns2-svk.dts
> +++ b/arch/arm64/boot/dts/broadcom/ns2-svk.dts
> @@ -128,6 +128,8 @@
>  		nand-ecc-mode = "hw";
>  		nand-ecc-strength = <8>;
>  		nand-ecc-step-size = <512>;
> +		nand-bus-width = <16>;
> +		brcm,nand-oob-sector-size = <16>;
>  		#address-cells = <1>;
>  		#size-cells = <1>;
>  	};
>


From arnd at arndb.de  Mon Oct 17 15:03:28 2016
From: arnd at arndb.de (Arnd Bergmann)
Date: Tue, 18 Oct 2016 00:03:28 +0200
Subject: [PATCH 00/28] Reenable maybe-uninitialized warnings
Message-ID: <20161017220342.1627073-1-arnd@arndb.de>

This is a set of patches that I hope to get into v4.9 in some form
in order to turn on the -Wmaybe-uninitialized warnings again.

After talking to Linus in person at Linaro Connect about this, I
spent some time on finding all the remaining warnings, and this
is the resulting patch series. More details are in the description
of the last patch that actually enables the warning.

Let me know if there are other warnings that I missed, and whether
you think these are still appropriate for v4.9 or not.
A couple of patches are non-obvious, and could use some more
detailed review.

	Arnd

Arnd Bergmann (28):
  [v2] netfilter: nf_tables: avoid uninitialized variable warning
  [v2] mtd: mtk: avoid warning in mtk_ecc_encode
  [v2] infiniband: shut up a maybe-uninitialized warning
  f2fs: replace a build-time warning with runtime WARN_ON
  ext2: avoid bogus -Wmaybe-uninitialized warning
  NFSv4.1: work around -Wmaybe-uninitialized warning
  ceph: avoid false positive maybe-uninitialized warning
  staging: lustre: restore initialization of return code
  staging: lustre: remove broken dead code in
    cfs_cpt_table_create_pattern
  UBI: fix uninitialized access of vid_hdr pointer
  block: rdb: false-postive gcc-4.9 -Wmaybe-uninitialized
  [media] rc: print correct variable for z8f0811
  [media] dib0700: fix uninitialized data on 'repeat' event
  iio: accel: sca3000_core: avoid potentially uninitialized variable
  crypto: aesni: avoid -Wmaybe-uninitialized warning
  pcmcia: fix return value of soc_pcmcia_regulator_set
  spi: fsl-espi: avoid processing uninitalized data on error
  drm: avoid uninitialized timestamp use in wait_vblank
  brcmfmac: avoid maybe-uninitialized warning in brcmf_cfg80211_start_ap
  net: bcm63xx: avoid referencing uninitialized variable
  net/hyperv: avoid uninitialized variable
  x86: apm: avoid uninitialized data
  x86: mark target address as output in 'insb' asm
  x86: math-emu: possible uninitialized variable use
  s390: pci: don't print uninitialized data for debugging
  nios2: fix timer initcall return value
  rocker: fix maybe-uninitialized warning
  Kbuild: bring back -Wmaybe-uninitialized warning

 Makefile                                           |  10 +-
 arch/arc/Makefile                                  |   4 +-
 arch/nios2/kernel/time.c                           |   1 +
 arch/s390/pci/pci_dma.c                            |   2 +-
 arch/x86/crypto/aesni-intel_glue.c                 | 121 +++++++++++++--------
 arch/x86/include/asm/io.h                          |   4 +-
 arch/x86/kernel/apm_32.c                           |   5 +-
 arch/x86/math-emu/Makefile                         |   4 +-
 arch/x86/math-emu/reg_compare.c                    |  16 +--
 drivers/block/rbd.c                                |   1 +
 drivers/gpu/drm/drm_irq.c                          |   4 +-
 drivers/infiniband/core/cma.c                      |  56 +++++-----
 drivers/media/i2c/ir-kbd-i2c.c                     |   2 +-
 drivers/media/usb/dvb-usb/dib0700_core.c           |  10 +-
 drivers/mtd/nand/mtk_ecc.c                         |  19 ++--
 drivers/mtd/ubi/eba.c                              |   2 +-
 drivers/net/ethernet/broadcom/bcm63xx_enet.c       |   3 +-
 drivers/net/ethernet/rocker/rocker_ofdpa.c         |   4 +-
 drivers/net/hyperv/netvsc_drv.c                    |   2 +-
 .../broadcom/brcm80211/brcmfmac/cfg80211.c         |   2 +-
 drivers/pcmcia/soc_common.c                        |   2 +-
 drivers/spi/spi-fsl-espi.c                         |   2 +-
 drivers/staging/iio/accel/sca3000_core.c           |   2 +
 .../staging/lustre/lnet/libcfs/linux/linux-cpu.c   |   7 --
 drivers/staging/lustre/lustre/lov/lov_pack.c       |   2 +
 fs/ceph/super.c                                    |   3 +-
 fs/ext2/inode.c                                    |   7 +-
 fs/f2fs/data.c                                     |   7 ++
 fs/nfs/nfs4session.c                               |  10 +-
 net/netfilter/nft_range.c                          |  10 +-
 scripts/Makefile.ubsan                             |   4 +
 31 files changed, 187 insertions(+), 141 deletions(-)

-- 
Cc: x86 at kernel.org
Cc: linux-media at vger.kernel.org
Cc: Mauro Carvalho Chehab <mchehab at kernel.org>
Cc: Martin Schwidefsky <schwidefsky at de.ibm.com>
Cc: linux-s390 at vger.kernel.org
Cc: Ilya Dryomov <idryomov at gmail.com>
Cc: dri-devel at lists.freedesktop.org
Cc: linux-mtd at lists.infradead.org
Cc: Herbert Xu <herbert at gondor.apana.org.au>
Cc: linux-crypto at vger.kernel.org
Cc: "David S. Miller" <davem at davemloft.net>
Cc: netdev at vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
Cc: ceph-devel at vger.kernel.org
Cc: linux-f2fs-devel at lists.sourceforge.net
Cc: linux-ext4 at vger.kernel.org
Cc: netfilter-devel at vger.kernel.org
2.9.0



From arnd at arndb.de  Mon Oct 17 15:05:31 2016
From: arnd at arndb.de (Arnd Bergmann)
Date: Tue, 18 Oct 2016 00:05:31 +0200
Subject: [PATCH 02/28] [v2] mtd: mtk: avoid warning in mtk_ecc_encode
In-Reply-To: <20161017220342.1627073-1-arnd@arndb.de>
References: <20161017220342.1627073-1-arnd@arndb.de>
Message-ID: <20161017220557.1688282-2-arnd@arndb.de>

When building with -Wmaybe-uninitialized, gcc produces a silly false positive
warning for the mtk_ecc_encode function:

drivers/mtd/nand/mtk_ecc.c: In function 'mtk_ecc_encode':
drivers/mtd/nand/mtk_ecc.c:402:15: error: 'val' may be used uninitialized in this function [-Werror=maybe-uninitialized]

The function for some reason contains a double byte swap on big-endian
builds to get the OOB data into the correct order again, and is written
in a slightly confusing way.

Using a simple memcpy32_fromio() to read the data simplifies it a lot
so it becomes more readable and produces no warning. However, the
output might not have 32-bit alignment, so we have to use another
memcpy to avoid taking alignment faults or writing beyond the end
of the array.

Signed-off-by: Arnd Bergmann <arnd at arndb.de>
---
v2: move temporary buffer into struct mtk_ecc instead of having it
    on the stack, as suggested by Boris Brezillon
---
 drivers/mtd/nand/mtk_ecc.c | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/drivers/mtd/nand/mtk_ecc.c b/drivers/mtd/nand/mtk_ecc.c
index d54f666..dbf2562 100644
--- a/drivers/mtd/nand/mtk_ecc.c
+++ b/drivers/mtd/nand/mtk_ecc.c
@@ -86,6 +86,8 @@ struct mtk_ecc {
 	struct completion done;
 	struct mutex lock;
 	u32 sectors;
+
+	u8 eccdata[112];
 };
 
 static inline void mtk_ecc_wait_idle(struct mtk_ecc *ecc,
@@ -366,9 +368,8 @@ int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
 		   u8 *data, u32 bytes)
 {
 	dma_addr_t addr;
-	u8 *p;
-	u32 len, i, val;
-	int ret = 0;
+	u32 len;
+	int ret;
 
 	addr = dma_map_single(ecc->dev, data, bytes, DMA_TO_DEVICE);
 	ret = dma_mapping_error(ecc->dev, addr);
@@ -393,14 +394,12 @@ int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
 
 	/* Program ECC bytes to OOB: per sector oob = FDM + ECC + SPARE */
 	len = (config->strength * ECC_PARITY_BITS + 7) >> 3;
-	p = data + bytes;
 
-	/* write the parity bytes generated by the ECC back to the OOB region */
-	for (i = 0; i < len; i++) {
-		if ((i % 4) == 0)
-			val = readl(ecc->regs + ECC_ENCPAR(i / 4));
-		p[i] = (val >> ((i % 4) * 8)) & 0xff;
-	}
+	/* write the parity bytes generated by the ECC back to temp buffer */
+	__ioread32_copy(ecc->eccdata, ecc->regs + ECC_ENCPAR(0), round_up(len, 4));
+
+	/* copy into possibly unaligned OOB region with actual length */
+	memcpy(data + bytes, ecc->eccdata, len);
 timeout:
 
 	dma_unmap_single(ecc->dev, addr, bytes, DMA_TO_DEVICE);
-- 
2.9.0



From arnd at arndb.de  Mon Oct 17 15:10:13 2016
From: arnd at arndb.de (Arnd Bergmann)
Date: Tue, 18 Oct 2016 00:10:13 +0200
Subject: [PATCH 10/28] UBI: fix uninitialized access of vid_hdr pointer
In-Reply-To: <20161017220342.1627073-1-arnd@arndb.de>
References: <20161017220342.1627073-1-arnd@arndb.de>
Message-ID: <20161017221037.1781185-1-arnd@arndb.de>

A rework of UBI that just appeared in linux-next during the merge
window introduced caused the recover_peb to use a variable that
is never initialized as seen from this gcc warning:

drivers/mtd/ubi/eba.c: In function ?recover_peb?:
drivers/mtd/ubi/eba.c:744:40: error: ?vid_hdr? may be used uninitialized in this function [-Werror=maybe-uninitialized]

It seems clear that the change to the function arguments was missing
the initialization that I'm now adding back to restore the
way the function was working before.

Fixes: 3291b52f9ff0 ("UBI: introduce the VID buffer concept")
Cc: Boris Brezillon <boris.brezillon at free-electrons.com>
Cc: Richard Weinberger <richard at nod.at>
Signed-off-by: Arnd Bergmann <arnd at arndb.de>
---
 drivers/mtd/ubi/eba.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index 95c4048..2e152be 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -719,7 +719,7 @@ static int try_recover_peb(struct ubi_volume *vol, int pnum, int lnum,
 			   struct ubi_vid_io_buf *vidb, bool *retry)
 {
 	struct ubi_device *ubi = vol->ubi;
-	struct ubi_vid_hdr *vid_hdr;
+	struct ubi_vid_hdr *vid_hdr = ubi_get_vid_hdr(vidb);
 	int new_pnum, err, vol_id = vol->vol_id, data_size;
 	uint32_t crc;
 
-- 
2.9.0



From arnd at arndb.de  Mon Oct 17 15:19:11 2016
From: arnd at arndb.de (Arnd Bergmann)
Date: Tue, 18 Oct 2016 00:19:11 +0200
Subject: [PATCH 28/28] Kbuild: bring back -Wmaybe-uninitialized warning
In-Reply-To: <20161017220342.1627073-1-arnd@arndb.de>
References: <20161017220342.1627073-1-arnd@arndb.de>
Message-ID: <20161017222000.1934898-1-arnd@arndb.de>

Traditionally, we have always had warnings about uninitialized variables
enabled, as this is part of -Wall, and generally a good idea [1], but it
also always produced false positives, mainly because this is a variation
of the halting problem and provably impossible to get right in all cases
[2].

Various people have identified cases that are particularly bad for false
positives, and in commit e74fc973b6e5 ("Turn off -Wmaybe-uninitialized
when building with -Os"), I turned off the warning for any build that
was done with CC_OPTIMIZE_FOR_SIZE.  This drastically reduced the number
of false positive warnings in the default build but unfortunately had
the side effect of turning the warning off completely in 'allmodconfig'
builds, which in turn led to a lot of warnings (both actual bugs, and
remaining false positives) to go in unnoticed.

With commit 877417e6ffb9 ("Kbuild: change CC_OPTIMIZE_FOR_SIZE
definition") enabled the warning again for allmodconfig builds in v4.7
and in v4.8-rc1, I had finally managed to address all warnings I get in
an ARM allmodconfig build and most other maybe-uninitialized warnings
for ARM randconfig builds.

However, commit 6e8d666e9253 ("Disable "maybe-uninitialized" warning
globally") was merged at the same time and disabled it completely for
all configurations, because of false-positive warnings on x86 that
I had not addressed until then. This caused a lot of actual bugs to
get merged into mainline, and I sent several dozen patches for these
during the v4.9 development cycle. Most of these are actual bugs,
some are for correct code that is safe because it is only called
under external constraints that make it impossible to run into
the case that gcc sees, and in a few cases gcc is just stupid and
finds something that can obviously never happen.

I have now done a few thousand randconfig builds on x86 and collected
all patches that I needed to address every single warning I got
(I can provide the combined patch for the other warnings if anyone
is interested), so I hope we can get the warning back and let people
catch the actual bugs earlier.

Note that the majority of the patches I created are for the third kind
of problem (stupid false-positives), for one of two reasons:
- some of them only get triggered in certain combinations of config
  options, so we don't always run into them, and
- the actual bugs tend to get addressed much quicker as they also
  lead to incorrect runtime behavior.

These 27 patches address the warnings that either occur in one of the more
common configurations (defconfig, allmodconfig, or something built by the
kbuild robot or kernelci.org), or they are about a real bug. It would be
good to get these all into v4.9 if we want to turn on the warning again.
I have tested these extensively with gcc-4.9 and gcc-6 and done a bit
of testing with gcc-5, and all of these should now be fine. gcc-4.8
is much worse about the false-positive warnings and is also fairly old
now, so I'm leaving the warning disabled with that version. gcc-4.7 and
older don't understand the -Wno-maybe-uninitialized option and are not
affected by this patch either way.

I have another (smaller) series of patches for warnings that are both
harmless and not as easy to trigger, and I will send them for inclusion
in v4.10.

Link: https://rusty.ozlabs.org/?p=232 [1]
Link: https://gcc.gnu.org/wiki/Better_Uninitialized_Warnings [2]
Signed-off-by: Arnd Bergmann <arnd at arndb.de>
---
 Makefile               | 10 ++++++----
 arch/arc/Makefile      |  4 +++-
 scripts/Makefile.ubsan |  4 ++++
 3 files changed, 13 insertions(+), 5 deletions(-)

Cc: x86 at kernel.org
Cc: linux-media at vger.kernel.org
Cc: Mauro Carvalho Chehab <mchehab at kernel.org>
Cc: Martin Schwidefsky <schwidefsky at de.ibm.com>
Cc: linux-s390 at vger.kernel.org
Cc: Ilya Dryomov <idryomov at gmail.com>
Cc: dri-devel at lists.freedesktop.org
Cc: linux-mtd at lists.infradead.org
Cc: Herbert Xu <herbert at gondor.apana.org.au>
Cc: linux-crypto at vger.kernel.org
Cc: "David S. Miller" <davem at davemloft.net>
Cc: netdev at vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
Cc: ceph-devel at vger.kernel.org
Cc: linux-f2fs-devel at lists.sourceforge.net
Cc: linux-ext4 at vger.kernel.org
Cc: netfilter-devel at vger.kernel.org

diff --git a/Makefile b/Makefile
index 512e47a..43cd3d9 100644
--- a/Makefile
+++ b/Makefile
@@ -370,7 +370,7 @@ LDFLAGS_MODULE  =
 CFLAGS_KERNEL	=
 AFLAGS_KERNEL	=
 LDFLAGS_vmlinux =
-CFLAGS_GCOV	= -fprofile-arcs -ftest-coverage -fno-tree-loop-im
+CFLAGS_GCOV	= -fprofile-arcs -ftest-coverage -fno-tree-loop-im  -Wno-maybe-uninitialized
 CFLAGS_KCOV	:= $(call cc-option,-fsanitize-coverage=trace-pc,)
 
 
@@ -620,7 +620,6 @@ ARCH_CFLAGS :=
 include arch/$(SRCARCH)/Makefile
 
 KBUILD_CFLAGS	+= $(call cc-option,-fno-delete-null-pointer-checks,)
-KBUILD_CFLAGS	+= $(call cc-disable-warning,maybe-uninitialized,)
 KBUILD_CFLAGS	+= $(call cc-disable-warning,frame-address,)
 
 ifdef CONFIG_LD_DEAD_CODE_DATA_ELIMINATION
@@ -629,15 +628,18 @@ KBUILD_CFLAGS	+= $(call cc-option,-fdata-sections,)
 endif
 
 ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
-KBUILD_CFLAGS	+= -Os
+KBUILD_CFLAGS	+= -Os $(call cc-disable-warning,maybe-uninitialized,)
 else
 ifdef CONFIG_PROFILE_ALL_BRANCHES
-KBUILD_CFLAGS	+= -O2
+KBUILD_CFLAGS	+= -O2 $(call cc-disable-warning,maybe-uninitialized,)
 else
 KBUILD_CFLAGS   += -O2
 endif
 endif
 
+KBUILD_CFLAGS += $(call cc-ifversion, -lt, 0409, \
+			$(call cc-disable-warning,maybe-uninitialized,))
+
 # Tell gcc to never replace conditional load with a non-conditional one
 KBUILD_CFLAGS	+= $(call cc-option,--param=allow-store-data-races=0)
 
diff --git a/arch/arc/Makefile b/arch/arc/Makefile
index aa82d13..19cce22 100644
--- a/arch/arc/Makefile
+++ b/arch/arc/Makefile
@@ -71,7 +71,9 @@ cflags-$(CONFIG_ARC_DW2_UNWIND)		+= -fasynchronous-unwind-tables $(cfi)
 ifndef CONFIG_CC_OPTIMIZE_FOR_SIZE
 # Generic build system uses -O2, we want -O3
 # Note: No need to add to cflags-y as that happens anyways
-ARCH_CFLAGS += -O3
+#
+# Disable the false maybe-uninitialized warings gcc spits out at -O3
+ARCH_CFLAGS += -O3 $(call cc-disable-warning,maybe-uninitialized,)
 endif
 
 # small data is default for elf32 tool-chain. If not usable, disable it
diff --git a/scripts/Makefile.ubsan b/scripts/Makefile.ubsan
index dd779c4..3b1b138 100644
--- a/scripts/Makefile.ubsan
+++ b/scripts/Makefile.ubsan
@@ -17,4 +17,8 @@ endif
 ifdef CONFIG_UBSAN_NULL
       CFLAGS_UBSAN += $(call cc-option, -fsanitize=null)
 endif
+
+      # -fsanitize=* options makes GCC less smart than usual and
+      # increase number of 'maybe-uninitialized false-positives
+      CFLAGS_UBSAN += $(call cc-option, -Wno-maybe-uninitialized)
 endif
-- 
2.9.0



From f.fainelli at gmail.com  Mon Oct 17 17:54:57 2016
From: f.fainelli at gmail.com (Florian Fainelli)
Date: Mon, 17 Oct 2016 17:54:57 -0700
Subject: [PATCH v2 2/2] arm64: dts: Updated NAND DT properties for NS2 SVK
In-Reply-To: <8832e18c-cd77-9fe1-8bd8-a2d65390666a@broadcom.com>
References: <1469051631-7896-1-git-send-email-ray.jui@broadcom.com>
 <1469051631-7896-3-git-send-email-ray.jui@broadcom.com>
 <8832e18c-cd77-9fe1-8bd8-a2d65390666a@broadcom.com>
Message-ID: <9657d27d-dbfa-e629-f5d4-4f7a748d5033@gmail.com>

On 10/17/2016 01:49 PM, Ray Jui wrote:
> Hi Florian,
> 
> Would you be able to help to queue the following patch for v4.10? Sorry
> I did not include you in the "To" field of the original email.

Applied, thanks!
-- 
Florian


From hch at infradead.org  Mon Oct 17 22:08:04 2016
From: hch at infradead.org (Christoph Hellwig)
Date: Mon, 17 Oct 2016 22:08:04 -0700
Subject: [PATCH 00/28] Reenable maybe-uninitialized warnings
In-Reply-To: <20161017220342.1627073-1-arnd@arndb.de>
References: <20161017220342.1627073-1-arnd@arndb.de>
Message-ID: <20161018050804.GA9902@infradead.org>

On Tue, Oct 18, 2016 at 12:03:28AM +0200, Arnd Bergmann wrote:
> This is a set of patches that I hope to get into v4.9 in some form
> in order to turn on the -Wmaybe-uninitialized warnings again.

Hi Arnd,

I jsut complained to Geert that I was introducing way to many
bugs or pointless warnings for some compilers lately, but gcc didn't
warn me about them.  From a little research the lack of
-Wmaybe-uninitialized seems to be the reason for it, so I'm all
for re-enabling it.


From boris.brezillon at free-electrons.com  Mon Oct 17 22:17:35 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Tue, 18 Oct 2016 07:17:35 +0200
Subject: [PATCH 10/28] UBI: fix uninitialized access of vid_hdr pointer
In-Reply-To: <20161017221037.1781185-1-arnd@arndb.de>
References: <20161017220342.1627073-1-arnd@arndb.de>
 <20161017221037.1781185-1-arnd@arndb.de>
Message-ID: <20161018071735.1e8a0e26@bbrezillon>

Hi Arnd,

On Tue, 18 Oct 2016 00:10:13 +0200
Arnd Bergmann <arnd at arndb.de> wrote:

> A rework of UBI that just appeared in linux-next during the merge
> window introduced caused the recover_peb to use a variable that
> is never initialized as seen from this gcc warning:
> 
> drivers/mtd/ubi/eba.c: In function ?recover_peb?:
> drivers/mtd/ubi/eba.c:744:40: error: ?vid_hdr? may be used uninitialized in this function [-Werror=maybe-uninitialized]
> 
> It seems clear that the change to the function arguments was missing
> the initialization that I'm now adding back to restore the
> way the function was working before.

Thanks for the fix, but Geert already sent a patch for this bug a few
days ago.

Regards,

Boris

> 
> Fixes: 3291b52f9ff0 ("UBI: introduce the VID buffer concept")
> Cc: Boris Brezillon <boris.brezillon at free-electrons.com>
> Cc: Richard Weinberger <richard at nod.at>
> Signed-off-by: Arnd Bergmann <arnd at arndb.de>
> ---
>  drivers/mtd/ubi/eba.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
> index 95c4048..2e152be 100644
> --- a/drivers/mtd/ubi/eba.c
> +++ b/drivers/mtd/ubi/eba.c
> @@ -719,7 +719,7 @@ static int try_recover_peb(struct ubi_volume *vol, int pnum, int lnum,
>  			   struct ubi_vid_io_buf *vidb, bool *retry)
>  {
>  	struct ubi_device *ubi = vol->ubi;
> -	struct ubi_vid_hdr *vid_hdr;
> +	struct ubi_vid_hdr *vid_hdr = ubi_get_vid_hdr(vidb);
>  	int new_pnum, err, vol_id = vol->vol_id, data_size;
>  	uint32_t crc;
>  



From boris.brezillon at free-electrons.com  Mon Oct 17 22:19:48 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Tue, 18 Oct 2016 07:19:48 +0200
Subject: [PATCH 02/28] [v2] mtd: mtk: avoid warning in mtk_ecc_encode
In-Reply-To: <20161017220557.1688282-2-arnd@arndb.de>
References: <20161017220342.1627073-1-arnd@arndb.de>
 <20161017220557.1688282-2-arnd@arndb.de>
Message-ID: <20161018071948.0b7eef05@bbrezillon>

On Tue, 18 Oct 2016 00:05:31 +0200
Arnd Bergmann <arnd at arndb.de> wrote:

> When building with -Wmaybe-uninitialized, gcc produces a silly false positive
> warning for the mtk_ecc_encode function:
> 
> drivers/mtd/nand/mtk_ecc.c: In function 'mtk_ecc_encode':
> drivers/mtd/nand/mtk_ecc.c:402:15: error: 'val' may be used uninitialized in this function [-Werror=maybe-uninitialized]
> 
> The function for some reason contains a double byte swap on big-endian
> builds to get the OOB data into the correct order again, and is written
> in a slightly confusing way.
> 
> Using a simple memcpy32_fromio() to read the data simplifies it a lot
> so it becomes more readable and produces no warning. However, the
> output might not have 32-bit alignment, so we have to use another
> memcpy to avoid taking alignment faults or writing beyond the end
> of the array.
> 
> Signed-off-by: Arnd Bergmann <arnd at arndb.de>

Jorge, RogerCC, can I have an Acked-by and/or Tested-by for this patch?

> ---
> v2: move temporary buffer into struct mtk_ecc instead of having it
>     on the stack, as suggested by Boris Brezillon
> ---
>  drivers/mtd/nand/mtk_ecc.c | 19 +++++++++----------
>  1 file changed, 9 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/mtd/nand/mtk_ecc.c b/drivers/mtd/nand/mtk_ecc.c
> index d54f666..dbf2562 100644
> --- a/drivers/mtd/nand/mtk_ecc.c
> +++ b/drivers/mtd/nand/mtk_ecc.c
> @@ -86,6 +86,8 @@ struct mtk_ecc {
>  	struct completion done;
>  	struct mutex lock;
>  	u32 sectors;
> +
> +	u8 eccdata[112];
>  };
>  
>  static inline void mtk_ecc_wait_idle(struct mtk_ecc *ecc,
> @@ -366,9 +368,8 @@ int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
>  		   u8 *data, u32 bytes)
>  {
>  	dma_addr_t addr;
> -	u8 *p;
> -	u32 len, i, val;
> -	int ret = 0;
> +	u32 len;
> +	int ret;
>  
>  	addr = dma_map_single(ecc->dev, data, bytes, DMA_TO_DEVICE);
>  	ret = dma_mapping_error(ecc->dev, addr);
> @@ -393,14 +394,12 @@ int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
>  
>  	/* Program ECC bytes to OOB: per sector oob = FDM + ECC + SPARE */
>  	len = (config->strength * ECC_PARITY_BITS + 7) >> 3;
> -	p = data + bytes;
>  
> -	/* write the parity bytes generated by the ECC back to the OOB region */
> -	for (i = 0; i < len; i++) {
> -		if ((i % 4) == 0)
> -			val = readl(ecc->regs + ECC_ENCPAR(i / 4));
> -		p[i] = (val >> ((i % 4) * 8)) & 0xff;
> -	}
> +	/* write the parity bytes generated by the ECC back to temp buffer */
> +	__ioread32_copy(ecc->eccdata, ecc->regs + ECC_ENCPAR(0), round_up(len, 4));
> +
> +	/* copy into possibly unaligned OOB region with actual length */
> +	memcpy(data + bytes, ecc->eccdata, len);
>  timeout:
>  
>  	dma_unmap_single(ecc->dev, addr, bytes, DMA_TO_DEVICE);



From narmstrong at baylibre.com  Tue Oct 18 02:09:27 2016
From: narmstrong at baylibre.com (Neil Armstrong)
Date: Tue, 18 Oct 2016 11:09:27 +0200
Subject: [RFC PATCH] mtd: nand: Add OX820 NAND Support
Message-ID: <20161018090927.1990-1-narmstrong@baylibre.com>

Add NAND driver to support the Oxford Semiconductor OX820 NAND Controller.
This is a simple memory mapped NAND controller with single chip select and
software ECC.

Signed-off-by: Neil Armstrong <narmstrong at baylibre.com>
---
 .../devicetree/bindings/mtd/oxnas-nand.txt         |  24 ++++
 drivers/mtd/nand/Kconfig                           |   5 +
 drivers/mtd/nand/Makefile                          |   1 +
 drivers/mtd/nand/oxnas_nand.c                      | 144 +++++++++++++++++++++
 4 files changed, 174 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/oxnas-nand.txt
 create mode 100644 drivers/mtd/nand/oxnas_nand.c

diff --git a/Documentation/devicetree/bindings/mtd/oxnas-nand.txt b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
new file mode 100644
index 0000000..83b684d
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
@@ -0,0 +1,24 @@
+* Oxford Semiconductor OXNAS NAND Controller
+
+Please refer to nand.txt for generic information regarding MTD NAND bindings.
+
+Required properties:
+ - compatible: "oxsemi,ox820-nand"
+ - reg: Base address and length for NAND mapped memory.
+
+Optional Properties:
+ - clocks: phandle to the NAND gate clock if needed.
+ - resets: phandle to the NAND reset control if needed.
+
+Example:
+
+nand: nand at 41000000 {
+	compatible = "oxsemi,ox820-nand";
+	reg = <0x41000000 0x100000>;
+	nand-ecc-mode = "soft";
+	clocks = <&stdclk CLK_820_NAND>;
+	resets = <&reset RESET_NAND>;
+	#address-cells = <1>;
+	#size-cells = <1>;
+	status = "disabled";
+};
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 7b7a887..c023125 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -426,6 +426,11 @@ config MTD_NAND_ORION
 	  No board specific support is done by this driver, each board
 	  must advertise a platform_device for the driver to attach.
 
+config MTD_NAND_OXNAS
+	tristate "NAND Flash support for Oxford Semiconductor SoC"
+	help
+	  This enables the NAND flash controller on Oxford Semiconductor SoCs.
+
 config MTD_NAND_FSL_ELBC
 	tristate "NAND support for Freescale eLBC controllers"
 	depends on FSL_SOC
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index cafde6f..05fc054 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_MTD_NAND_TMIO)		+= tmio_nand.o
 obj-$(CONFIG_MTD_NAND_PLATFORM)		+= plat_nand.o
 obj-$(CONFIG_MTD_NAND_PASEMI)		+= pasemi_nand.o
 obj-$(CONFIG_MTD_NAND_ORION)		+= orion_nand.o
+obj-$(CONFIG_MTD_NAND_OXNAS)		+= oxnas_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_ELBC)		+= fsl_elbc_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_IFC)		+= fsl_ifc_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_UPM)		+= fsl_upm.o
diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/oxnas_nand.c
new file mode 100644
index 0000000..ee402ab
--- /dev/null
+++ b/drivers/mtd/nand/oxnas_nand.c
@@ -0,0 +1,144 @@
+/*
+ * Oxford Semiconductor OXNAS NAND driver
+ *
+ * Heavily based on plat_nand.c :
+ * Author: Vitaly Wool <vitalywool at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/reset.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
+/* nand commands */
+#define NAND_CMD_ALE		BIT(18)
+#define NAND_CMD_CLE		BIT(19)
+#define NAND_CMD_CS		0
+#define NAND_CMD_RESET		0xff
+#define NAND_CMD		(NAND_CMD_CS | NAND_CMD_CLE)
+#define NAND_ADDR		(NAND_CMD_CS | NAND_CMD_ALE)
+#define NAND_DATA		(NAND_CMD_CS)
+
+struct oxnas_nand_data {
+	struct nand_chip	chip;
+	void __iomem		*io_base;
+	struct clk		*clk;
+};
+
+static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+				unsigned int ctrl)
+{
+	struct nand_chip *this = mtd->priv;
+	unsigned long nandaddr = (unsigned long) this->IO_ADDR_W;
+
+	if (ctrl & NAND_CTRL_CHANGE) {
+		nandaddr &= ~(NAND_CMD | NAND_ADDR);
+		if (ctrl & NAND_CLE)
+			nandaddr |= NAND_CMD;
+		else if (ctrl & NAND_ALE)
+			nandaddr |= NAND_ADDR;
+		this->IO_ADDR_W = (void __iomem *) nandaddr;
+	}
+
+	if (cmd != NAND_CMD_NONE)
+		writeb(cmd, (void __iomem *) nandaddr);
+}
+
+/*
+ * Probe for the NAND device.
+ */
+static int oxnas_nand_probe(struct platform_device *pdev)
+{
+	struct oxnas_nand_data *data;
+	struct mtd_info *mtd;
+	struct resource *res;
+	int err = 0;
+
+	/* Allocate memory for the device structure (and zero it) */
+	data = devm_kzalloc(&pdev->dev, sizeof(struct oxnas_nand_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	data->io_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(data->io_base))
+		return PTR_ERR(data->io_base);
+
+	data->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(data->clk))
+		data->clk = NULL;
+
+	nand_set_flash_node(&data->chip, pdev->dev.of_node);
+	mtd = nand_to_mtd(&data->chip);
+	mtd->dev.parent = &pdev->dev;
+	mtd->priv = &data->chip;
+
+	data->chip.IO_ADDR_R = data->io_base;
+	data->chip.IO_ADDR_W = data->io_base;
+	data->chip.cmd_ctrl = oxnas_nand_cmd_ctrl;
+	data->chip.chip_delay = 30;
+	data->chip.ecc.mode = NAND_ECC_SOFT;
+	data->chip.ecc.algo = NAND_ECC_HAMMING;
+
+	platform_set_drvdata(pdev, data);
+
+	clk_prepare_enable(data->clk);
+	device_reset_optional(&pdev->dev);
+
+	/* Scan to find existence of the device */
+	if (nand_scan(mtd, 1)) {
+		err = -ENXIO;
+		goto out;
+	}
+
+	err = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
+	if (!err)
+		return err;
+
+	nand_release(mtd);
+out:
+	return err;
+}
+
+static int oxnas_nand_remove(struct platform_device *pdev)
+{
+	struct oxnas_nand_data *data = platform_get_drvdata(pdev);
+
+	nand_release(nand_to_mtd(&data->chip));
+
+	return 0;
+}
+
+static const struct of_device_id oxnas_nand_match[] = {
+	{ .compatible = "oxsemi,ox820-nand" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, oxnas_nand_match);
+
+static struct platform_driver oxnas_nand_driver = {
+	.probe	= oxnas_nand_probe,
+	.remove	= oxnas_nand_remove,
+	.driver	= {
+		.name		= "oxnas_nand",
+		.of_match_table = oxnas_nand_match,
+	},
+};
+
+module_platform_driver(oxnas_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Vitaly Wool");
+MODULE_DESCRIPTION("Oxnas NAND driver");
+MODULE_ALIAS("platform:oxnas_nand");
-- 
2.7.0



From rogercc.lin at mediatek.com  Tue Oct 18 03:12:32 2016
From: rogercc.lin at mediatek.com (RogerCC.Lin)
Date: Tue, 18 Oct 2016 18:12:32 +0800
Subject: [PATCH 02/28] [v2] mtd: mtk: avoid warning in mtk_ecc_encode
In-Reply-To: <20161018071948.0b7eef05@bbrezillon>
References: <20161017220342.1627073-1-arnd@arndb.de>
 <20161017220557.1688282-2-arnd@arndb.de>
 <20161018071948.0b7eef05@bbrezillon>
Message-ID: <1476785552.24626.4.camel@mtkswgap22>

On Tue, 2016-10-18 at 07:19 +0200, Boris Brezillon wrote:
> On Tue, 18 Oct 2016 00:05:31 +0200
> Arnd Bergmann <arnd at arndb.de> wrote:
> 
> > When building with -Wmaybe-uninitialized, gcc produces a silly false positive
> > warning for the mtk_ecc_encode function:
> > 
> > drivers/mtd/nand/mtk_ecc.c: In function 'mtk_ecc_encode':
> > drivers/mtd/nand/mtk_ecc.c:402:15: error: 'val' may be used uninitialized in this function [-Werror=maybe-uninitialized]
> > 
> > The function for some reason contains a double byte swap on big-endian
> > builds to get the OOB data into the correct order again, and is written
> > in a slightly confusing way.
> > 
> > Using a simple memcpy32_fromio() to read the data simplifies it a lot
> > so it becomes more readable and produces no warning. However, the
> > output might not have 32-bit alignment, so we have to use another
> > memcpy to avoid taking alignment faults or writing beyond the end
> > of the array.
> > 
> > Signed-off-by: Arnd Bergmann <arnd at arndb.de>
> 
> Jorge, RogerCC, can I have an Acked-by and/or Tested-by for this patch?
Tested, this patch is OK,
Tested-by: RogerCC Lin <rogercc.lin at mediatek.com>

> 
> > ---
> > v2: move temporary buffer into struct mtk_ecc instead of having it
> >     on the stack, as suggested by Boris Brezillon
> > ---
> >  drivers/mtd/nand/mtk_ecc.c | 19 +++++++++----------
> >  1 file changed, 9 insertions(+), 10 deletions(-)
> > 
> > diff --git a/drivers/mtd/nand/mtk_ecc.c b/drivers/mtd/nand/mtk_ecc.c
> > index d54f666..dbf2562 100644
> > --- a/drivers/mtd/nand/mtk_ecc.c
> > +++ b/drivers/mtd/nand/mtk_ecc.c
> > @@ -86,6 +86,8 @@ struct mtk_ecc {
> >  	struct completion done;
> >  	struct mutex lock;
> >  	u32 sectors;
> > +
> > +	u8 eccdata[112];
> >  };
> >  
> >  static inline void mtk_ecc_wait_idle(struct mtk_ecc *ecc,
> > @@ -366,9 +368,8 @@ int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
> >  		   u8 *data, u32 bytes)
> >  {
> >  	dma_addr_t addr;
> > -	u8 *p;
> > -	u32 len, i, val;
> > -	int ret = 0;
> > +	u32 len;
> > +	int ret;
> >  
> >  	addr = dma_map_single(ecc->dev, data, bytes, DMA_TO_DEVICE);
> >  	ret = dma_mapping_error(ecc->dev, addr);
> > @@ -393,14 +394,12 @@ int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
> >  
> >  	/* Program ECC bytes to OOB: per sector oob = FDM + ECC + SPARE */
> >  	len = (config->strength * ECC_PARITY_BITS + 7) >> 3;
> > -	p = data + bytes;
> >  
> > -	/* write the parity bytes generated by the ECC back to the OOB region */
> > -	for (i = 0; i < len; i++) {
> > -		if ((i % 4) == 0)
> > -			val = readl(ecc->regs + ECC_ENCPAR(i / 4));
> > -		p[i] = (val >> ((i % 4) * 8)) & 0xff;
> > -	}
> > +	/* write the parity bytes generated by the ECC back to temp buffer */
> > +	__ioread32_copy(ecc->eccdata, ecc->regs + ECC_ENCPAR(0), round_up(len, 4));
> > +
> > +	/* copy into possibly unaligned OOB region with actual length */
> > +	memcpy(data + bytes, ecc->eccdata, len);
> >  timeout:
> >  
> >  	dma_unmap_single(ecc->dev, addr, bytes, DMA_TO_DEVICE);
> 




From daniel at makrotopia.org  Tue Oct 18 04:08:07 2016
From: daniel at makrotopia.org (Daniel Golle)
Date: Tue, 18 Oct 2016 13:08:07 +0200
Subject: [RFC PATCH] mtd: nand: Add OX820 NAND Support
In-Reply-To: <20161018090927.1990-1-narmstrong@baylibre.com>
References: <20161018090927.1990-1-narmstrong@baylibre.com>
Message-ID: <20161018110807.GD1641@makrotopia.org>

Hi Neil,

great to see progress towards supporting OX820!
The NAND driver I hacked up for Kernel 4.1 and 4.4 in OpenWrt/LEDE
looks very similar, see

https://git.lede-project.org/?p=lede/dangole/staging.git;a=blob;f=target/linux/oxnas/files/drivers/mtd/nand/oxnas_nand.c;h=f5a142950e32227fee304de731e619278350a91b;hb=refs/heads/oxnas-nand

To me therefore this looks quite good, just one small question below.

Cheers

Daniel


On Tue, Oct 18, 2016 at 11:09:27AM +0200, Neil Armstrong wrote:
> Add NAND driver to support the Oxford Semiconductor OX820 NAND Controller.
> This is a simple memory mapped NAND controller with single chip select and
> software ECC.
> 
> Signed-off-by: Neil Armstrong <narmstrong at baylibre.com>
> ---
>  .../devicetree/bindings/mtd/oxnas-nand.txt         |  24 ++++
>  drivers/mtd/nand/Kconfig                           |   5 +
>  drivers/mtd/nand/Makefile                          |   1 +
>  drivers/mtd/nand/oxnas_nand.c                      | 144 +++++++++++++++++++++
>  4 files changed, 174 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mtd/oxnas-nand.txt
>  create mode 100644 drivers/mtd/nand/oxnas_nand.c
> 
> diff --git a/Documentation/devicetree/bindings/mtd/oxnas-nand.txt b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
> new file mode 100644
> index 0000000..83b684d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
> @@ -0,0 +1,24 @@
> +* Oxford Semiconductor OXNAS NAND Controller
> +
> +Please refer to nand.txt for generic information regarding MTD NAND bindings.
> +
> +Required properties:
> + - compatible: "oxsemi,ox820-nand"
> + - reg: Base address and length for NAND mapped memory.
> +
> +Optional Properties:
> + - clocks: phandle to the NAND gate clock if needed.
> + - resets: phandle to the NAND reset control if needed.
> +
> +Example:
> +
> +nand: nand at 41000000 {
> +	compatible = "oxsemi,ox820-nand";
> +	reg = <0x41000000 0x100000>;
> +	nand-ecc-mode = "soft";
> +	clocks = <&stdclk CLK_820_NAND>;
> +	resets = <&reset RESET_NAND>;
> +	#address-cells = <1>;
> +	#size-cells = <1>;
> +	status = "disabled";
> +};
> diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
> index 7b7a887..c023125 100644
> --- a/drivers/mtd/nand/Kconfig
> +++ b/drivers/mtd/nand/Kconfig
> @@ -426,6 +426,11 @@ config MTD_NAND_ORION
>  	  No board specific support is done by this driver, each board
>  	  must advertise a platform_device for the driver to attach.
>  
> +config MTD_NAND_OXNAS
> +	tristate "NAND Flash support for Oxford Semiconductor SoC"
> +	help
> +	  This enables the NAND flash controller on Oxford Semiconductor SoCs.
> +
>  config MTD_NAND_FSL_ELBC
>  	tristate "NAND support for Freescale eLBC controllers"
>  	depends on FSL_SOC
> diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
> index cafde6f..05fc054 100644
> --- a/drivers/mtd/nand/Makefile
> +++ b/drivers/mtd/nand/Makefile
> @@ -35,6 +35,7 @@ obj-$(CONFIG_MTD_NAND_TMIO)		+= tmio_nand.o
>  obj-$(CONFIG_MTD_NAND_PLATFORM)		+= plat_nand.o
>  obj-$(CONFIG_MTD_NAND_PASEMI)		+= pasemi_nand.o
>  obj-$(CONFIG_MTD_NAND_ORION)		+= orion_nand.o
> +obj-$(CONFIG_MTD_NAND_OXNAS)		+= oxnas_nand.o
>  obj-$(CONFIG_MTD_NAND_FSL_ELBC)		+= fsl_elbc_nand.o
>  obj-$(CONFIG_MTD_NAND_FSL_IFC)		+= fsl_ifc_nand.o
>  obj-$(CONFIG_MTD_NAND_FSL_UPM)		+= fsl_upm.o
> diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/oxnas_nand.c
> new file mode 100644
> index 0000000..ee402ab
> --- /dev/null
> +++ b/drivers/mtd/nand/oxnas_nand.c
> @@ -0,0 +1,144 @@
> +/*
> + * Oxford Semiconductor OXNAS NAND driver
> + *
> + * Heavily based on plat_nand.c :
> + * Author: Vitaly Wool <vitalywool at gmail.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/clk.h>
> +#include <linux/reset.h>
> +#include <linux/mtd/mtd.h>
> +#include <linux/mtd/nand.h>
> +#include <linux/mtd/partitions.h>
> +
> +/* nand commands */
> +#define NAND_CMD_ALE		BIT(18)
> +#define NAND_CMD_CLE		BIT(19)
> +#define NAND_CMD_CS		0
> +#define NAND_CMD_RESET		0xff
> +#define NAND_CMD		(NAND_CMD_CS | NAND_CMD_CLE)
> +#define NAND_ADDR		(NAND_CMD_CS | NAND_CMD_ALE)
> +#define NAND_DATA		(NAND_CMD_CS)
> +
> +struct oxnas_nand_data {
> +	struct nand_chip	chip;
> +	void __iomem		*io_base;

Why do you redundantly keep io_base in platform data rather than
just using chip.IO_ADDR_R and >chip.IO_ADDR_W?


> +	struct clk		*clk;
> +};
> +
> +static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
> +				unsigned int ctrl)
> +{
> +	struct nand_chip *this = mtd->priv;
> +	unsigned long nandaddr = (unsigned long) this->IO_ADDR_W;
> +
> +	if (ctrl & NAND_CTRL_CHANGE) {
> +		nandaddr &= ~(NAND_CMD | NAND_ADDR);
> +		if (ctrl & NAND_CLE)
> +			nandaddr |= NAND_CMD;
> +		else if (ctrl & NAND_ALE)
> +			nandaddr |= NAND_ADDR;
> +		this->IO_ADDR_W = (void __iomem *) nandaddr;
> +	}
> +
> +	if (cmd != NAND_CMD_NONE)
> +		writeb(cmd, (void __iomem *) nandaddr);
> +}
> +
> +/*
> + * Probe for the NAND device.
> + */
> +static int oxnas_nand_probe(struct platform_device *pdev)
> +{
> +	struct oxnas_nand_data *data;
> +	struct mtd_info *mtd;
> +	struct resource *res;
> +	int err = 0;
> +
> +	/* Allocate memory for the device structure (and zero it) */
> +	data = devm_kzalloc(&pdev->dev, sizeof(struct oxnas_nand_data),
> +			    GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	data->io_base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(data->io_base))
> +		return PTR_ERR(data->io_base);
> +
> +	data->clk = devm_clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(data->clk))
> +		data->clk = NULL;
> +
> +	nand_set_flash_node(&data->chip, pdev->dev.of_node);
> +	mtd = nand_to_mtd(&data->chip);
> +	mtd->dev.parent = &pdev->dev;
> +	mtd->priv = &data->chip;
> +
> +	data->chip.IO_ADDR_R = data->io_base;
> +	data->chip.IO_ADDR_W = data->io_base;
> +	data->chip.cmd_ctrl = oxnas_nand_cmd_ctrl;
> +	data->chip.chip_delay = 30;
> +	data->chip.ecc.mode = NAND_ECC_SOFT;
> +	data->chip.ecc.algo = NAND_ECC_HAMMING;
> +
> +	platform_set_drvdata(pdev, data);
> +
> +	clk_prepare_enable(data->clk);
> +	device_reset_optional(&pdev->dev);
> +
> +	/* Scan to find existence of the device */
> +	if (nand_scan(mtd, 1)) {
> +		err = -ENXIO;
> +		goto out;
> +	}
> +
> +	err = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
> +	if (!err)
> +		return err;
> +
> +	nand_release(mtd);
> +out:
> +	return err;
> +}
> +
> +static int oxnas_nand_remove(struct platform_device *pdev)
> +{
> +	struct oxnas_nand_data *data = platform_get_drvdata(pdev);
> +
> +	nand_release(nand_to_mtd(&data->chip));
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id oxnas_nand_match[] = {
> +	{ .compatible = "oxsemi,ox820-nand" },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, oxnas_nand_match);
> +
> +static struct platform_driver oxnas_nand_driver = {
> +	.probe	= oxnas_nand_probe,
> +	.remove	= oxnas_nand_remove,
> +	.driver	= {
> +		.name		= "oxnas_nand",
> +		.of_match_table = oxnas_nand_match,
> +	},
> +};
> +
> +module_platform_driver(oxnas_nand_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Vitaly Wool");
> +MODULE_DESCRIPTION("Oxnas NAND driver");
> +MODULE_ALIAS("platform:oxnas_nand");
> -- 
> 2.7.0
> 
> 
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/


From narmstrong at baylibre.com  Tue Oct 18 04:24:22 2016
From: narmstrong at baylibre.com (Neil Armstrong)
Date: Tue, 18 Oct 2016 13:24:22 +0200
Subject: [RFC PATCH] mtd: nand: Add OX820 NAND Support
In-Reply-To: <20161018110807.GD1641@makrotopia.org>
References: <20161018090927.1990-1-narmstrong@baylibre.com>
 <20161018110807.GD1641@makrotopia.org>
Message-ID: <c377cb60-a359-62c1-dc6b-7b0be8b8e228@baylibre.com>

On 10/18/2016 01:08 PM, Daniel Golle wrote:
> Hi Neil,
> 
> great to see progress towards supporting OX820!
> The NAND driver I hacked up for Kernel 4.1 and 4.4 in OpenWrt/LEDE
> looks very similar, see
> 
> https://git.lede-project.org/?p=lede/dangole/staging.git;a=blob;f=target/linux/oxnas/files/drivers/mtd/nand/oxnas_nand.c;h=f5a142950e32227fee304de731e619278350a91b;hb=refs/heads/oxnas-nand
> 
> To me therefore this looks quite good, just one small question below.

Hi Daniel,

Yes, I work step by step, I hope to have something booting for 4.10 !

Indeed, they look identical except the part_probes[] stuff, are they necessary ?

My primary source of code was Ma Haiju's tree and OPenWRT's tree, but would some people like to push some of the openwrt driver upstream somehow ?

Thanks,
Neil

> 
> Cheers
> 
> Daniel
> 
> 
> On Tue, Oct 18, 2016 at 11:09:27AM +0200, Neil Armstrong wrote:
>> Add NAND driver to support the Oxford Semiconductor OX820 NAND Controller.
>> This is a simple memory mapped NAND controller with single chip select and
>> software ECC.
>>
>> Signed-off-by: Neil Armstrong <narmstrong at baylibre.com>
>> ---
>>  .../devicetree/bindings/mtd/oxnas-nand.txt         |  24 ++++
>>  drivers/mtd/nand/Kconfig                           |   5 +
>>  drivers/mtd/nand/Makefile                          |   1 +
>>  drivers/mtd/nand/oxnas_nand.c                      | 144 +++++++++++++++++++++
>>  4 files changed, 174 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/mtd/oxnas-nand.txt
>>  create mode 100644 drivers/mtd/nand/oxnas_nand.c
>>

[...]

>> diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/oxnas_nand.c
>> new file mode 100644
>> index 0000000..ee402ab
>> --- /dev/null
>> +++ b/drivers/mtd/nand/oxnas_nand.c
>> @@ -0,0 +1,144 @@
>> +/*
>> + * Oxford Semiconductor OXNAS NAND driver
>> + *
>> + * Heavily based on plat_nand.c :
>> + * Author: Vitaly Wool <vitalywool at gmail.com>

Hmm, I forgot the OpenWRT and Ma Haijun copyrights here...

>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + */
>> +
>> +#include <linux/err.h>
>> +#include <linux/io.h>
>> +#include <linux/module.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/slab.h>
>> +#include <linux/clk.h>
>> +#include <linux/reset.h>
>> +#include <linux/mtd/mtd.h>
>> +#include <linux/mtd/nand.h>
>> +#include <linux/mtd/partitions.h>
>> +
>> +/* nand commands */
>> +#define NAND_CMD_ALE		BIT(18)
>> +#define NAND_CMD_CLE		BIT(19)
>> +#define NAND_CMD_CS		0
>> +#define NAND_CMD_RESET		0xff
>> +#define NAND_CMD		(NAND_CMD_CS | NAND_CMD_CLE)
>> +#define NAND_ADDR		(NAND_CMD_CS | NAND_CMD_ALE)
>> +#define NAND_DATA		(NAND_CMD_CS)
>> +
>> +struct oxnas_nand_data {
>> +	struct nand_chip	chip;
>> +	void __iomem		*io_base;
> 
> Why do you redundantly keep io_base in platform data rather than
> just using chip.IO_ADDR_R and >chip.IO_ADDR_W?

For no reason since it's not used in oxnas_nand_cmd_ctrl...
Will remove !

> 
> 
>> +	struct clk		*clk;
>> +};
>> +
>> +static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
>> +				unsigned int ctrl)
>> +{
>> +	struct nand_chip *this = mtd->priv;
>> +	unsigned long nandaddr = (unsigned long) this->IO_ADDR_W;
>> +
>> +	if (ctrl & NAND_CTRL_CHANGE) {
>> +		nandaddr &= ~(NAND_CMD | NAND_ADDR);
>> +		if (ctrl & NAND_CLE)
>> +			nandaddr |= NAND_CMD;
>> +		else if (ctrl & NAND_ALE)
>> +			nandaddr |= NAND_ADDR;
>> +		this->IO_ADDR_W = (void __iomem *) nandaddr;
>> +	}
>> +
>> +	if (cmd != NAND_CMD_NONE)
>> +		writeb(cmd, (void __iomem *) nandaddr);
>> +}
[...]



From daniel at makrotopia.org  Tue Oct 18 04:51:15 2016
From: daniel at makrotopia.org (Daniel Golle)
Date: Tue, 18 Oct 2016 13:51:15 +0200
Subject: [RFC PATCH] mtd: nand: Add OX820 NAND Support
In-Reply-To: <c377cb60-a359-62c1-dc6b-7b0be8b8e228@baylibre.com>
References: <20161018090927.1990-1-narmstrong@baylibre.com>
 <20161018110807.GD1641@makrotopia.org>
 <c377cb60-a359-62c1-dc6b-7b0be8b8e228@baylibre.com>
Message-ID: <20161018115115.GF1641@makrotopia.org>

Hi Neil,

On Tue, Oct 18, 2016 at 01:24:22PM +0200, Neil Armstrong wrote:
> On 10/18/2016 01:08 PM, Daniel Golle wrote:
> > Hi Neil,
> > 
> > great to see progress towards supporting OX820!
> > The NAND driver I hacked up for Kernel 4.1 and 4.4 in OpenWrt/LEDE
> > looks very similar, see
> > 
> > https://git.lede-project.org/?p=lede/dangole/staging.git;a=blob;f=target/linux/oxnas/files/drivers/mtd/nand/oxnas_nand.c;h=f5a142950e32227fee304de731e619278350a91b;hb=refs/heads/oxnas-nand
> > 
> > To me therefore this looks quite good, just one small question below.
> 
> Hi Daniel,
> 
> Yes, I work step by step, I hope to have something booting for 4.10 !
> 
> Indeed, they look identical except the part_probes[] stuff, are they necessary ?

Nah, this was dropped around kernel 4.7 from most drivers in favour of
using the default partition probes (ie. cmdline and dt) afaik.

> 
> My primary source of code was Ma Haiju's tree and OPenWRT's tree, but would some people like to push some of the openwrt driver upstream somehow ?

I was planning this somehow, but lack the resources to seriously move
forward. I've mostly been focussing on cleaning up Ma Haiju's code and
improving support for the SATA driver (ie. adding support for both
ports) and re-factoring the stmmac-based Ethernet driver to match the
current kernel driver's style.
However, I'm still using platform-specific includes (hardware.h) and
thus look forward to rebase SATA and Ethernet support on top of your
tree, as that would unluck ox820 support in multi-v6 instead of having
a platform-specific kernel.

Currently there are problems with the NAND driver failing to detect the
chip on non-PCIe platform like the PogoPlug V3 (non-Pro), MitraStar
STG-212 and probably other non-PCIe boards which I didn't check yet.
This magically happened when switching from kernel 4.1 to 4.4, I'm
bisecting this since, but the problem seems to be hidden somewhere
between the lines (ie. probe-order-related or such)...
Did you test your NAND driver on any non-PCIe boards and did it work?


For a more or less complete history of the changes I made since
branching of Ma Haijun's tree, see

https://git.lede-project.org/?p=lede/dangole/staging.git;a=history;f=target/linux/oxnas;hb=refs/heads/oxnas-nand

and for the very early history, prior to the merge into the official
OpenWrt tree, see

http://gitorious.org/openwrt-oxnas/openwrt-oxnas.git


Cheers


Daniel

> 
> Thanks,
> Neil
> 
> > 
> > Cheers
> > 
> > Daniel
> > 
> > 
> > On Tue, Oct 18, 2016 at 11:09:27AM +0200, Neil Armstrong wrote:
> >> Add NAND driver to support the Oxford Semiconductor OX820 NAND Controller.
> >> This is a simple memory mapped NAND controller with single chip select and
> >> software ECC.
> >>
> >> Signed-off-by: Neil Armstrong <narmstrong at baylibre.com>
> >> ---
> >>  .../devicetree/bindings/mtd/oxnas-nand.txt         |  24 ++++
> >>  drivers/mtd/nand/Kconfig                           |   5 +
> >>  drivers/mtd/nand/Makefile                          |   1 +
> >>  drivers/mtd/nand/oxnas_nand.c                      | 144 +++++++++++++++++++++
> >>  4 files changed, 174 insertions(+)
> >>  create mode 100644 Documentation/devicetree/bindings/mtd/oxnas-nand.txt
> >>  create mode 100644 drivers/mtd/nand/oxnas_nand.c
> >>
> 
> [...]
> 
> >> diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/oxnas_nand.c
> >> new file mode 100644
> >> index 0000000..ee402ab
> >> --- /dev/null
> >> +++ b/drivers/mtd/nand/oxnas_nand.c
> >> @@ -0,0 +1,144 @@
> >> +/*
> >> + * Oxford Semiconductor OXNAS NAND driver
> >> + *
> >> + * Heavily based on plat_nand.c :
> >> + * Author: Vitaly Wool <vitalywool at gmail.com>
> 
> Hmm, I forgot the OpenWRT and Ma Haijun copyrights here...
> 
> >> + *
> >> + * This program is free software; you can redistribute it and/or modify
> >> + * it under the terms of the GNU General Public License version 2 as
> >> + * published by the Free Software Foundation.
> >> + *
> >> + */
> >> +
> >> +#include <linux/err.h>
> >> +#include <linux/io.h>
> >> +#include <linux/module.h>
> >> +#include <linux/platform_device.h>
> >> +#include <linux/slab.h>
> >> +#include <linux/clk.h>
> >> +#include <linux/reset.h>
> >> +#include <linux/mtd/mtd.h>
> >> +#include <linux/mtd/nand.h>
> >> +#include <linux/mtd/partitions.h>
> >> +
> >> +/* nand commands */
> >> +#define NAND_CMD_ALE		BIT(18)
> >> +#define NAND_CMD_CLE		BIT(19)
> >> +#define NAND_CMD_CS		0
> >> +#define NAND_CMD_RESET		0xff
> >> +#define NAND_CMD		(NAND_CMD_CS | NAND_CMD_CLE)
> >> +#define NAND_ADDR		(NAND_CMD_CS | NAND_CMD_ALE)
> >> +#define NAND_DATA		(NAND_CMD_CS)
> >> +
> >> +struct oxnas_nand_data {
> >> +	struct nand_chip	chip;
> >> +	void __iomem		*io_base;
> > 
> > Why do you redundantly keep io_base in platform data rather than
> > just using chip.IO_ADDR_R and >chip.IO_ADDR_W?
> 
> For no reason since it's not used in oxnas_nand_cmd_ctrl...
> Will remove !
> 
> > 
> > 
> >> +	struct clk		*clk;
> >> +};
> >> +
> >> +static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
> >> +				unsigned int ctrl)
> >> +{
> >> +	struct nand_chip *this = mtd->priv;
> >> +	unsigned long nandaddr = (unsigned long) this->IO_ADDR_W;
> >> +
> >> +	if (ctrl & NAND_CTRL_CHANGE) {
> >> +		nandaddr &= ~(NAND_CMD | NAND_ADDR);
> >> +		if (ctrl & NAND_CLE)
> >> +			nandaddr |= NAND_CMD;
> >> +		else if (ctrl & NAND_ALE)
> >> +			nandaddr |= NAND_ADDR;
> >> +		this->IO_ADDR_W = (void __iomem *) nandaddr;
> >> +	}
> >> +
> >> +	if (cmd != NAND_CMD_NONE)
> >> +		writeb(cmd, (void __iomem *) nandaddr);
> >> +}
> [...]
> 
> 
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/


From narmstrong at baylibre.com  Tue Oct 18 05:08:38 2016
From: narmstrong at baylibre.com (Neil Armstrong)
Date: Tue, 18 Oct 2016 14:08:38 +0200
Subject: [RFC PATCH] mtd: nand: Add OX820 NAND Support
In-Reply-To: <20161018115115.GF1641@makrotopia.org>
References: <20161018090927.1990-1-narmstrong@baylibre.com>
 <20161018110807.GD1641@makrotopia.org>
 <c377cb60-a359-62c1-dc6b-7b0be8b8e228@baylibre.com>
 <20161018115115.GF1641@makrotopia.org>
Message-ID: <ff8fb0cf-a442-12dc-3365-fd3417ae887c@baylibre.com>

On 10/18/2016 01:51 PM, Daniel Golle wrote:
> Hi Neil,
> 
> On Tue, Oct 18, 2016 at 01:24:22PM +0200, Neil Armstrong wrote:
>> On 10/18/2016 01:08 PM, Daniel Golle wrote:
>>> Hi Neil,
>>>
>>> great to see progress towards supporting OX820!
>>> The NAND driver I hacked up for Kernel 4.1 and 4.4 in OpenWrt/LEDE
>>> looks very similar, see
>>>
>>> https://git.lede-project.org/?p=lede/dangole/staging.git;a=blob;f=target/linux/oxnas/files/drivers/mtd/nand/oxnas_nand.c;h=f5a142950e32227fee304de731e619278350a91b;hb=refs/heads/oxnas-nand
>>>
>>> To me therefore this looks quite good, just one small question below.
>>
>> Hi Daniel,
>>
>> Yes, I work step by step, I hope to have something booting for 4.10 !
>>
>> Indeed, they look identical except the part_probes[] stuff, are they necessary ?
> 
> Nah, this was dropped around kernel 4.7 from most drivers in favour of
> using the default partition probes (ie. cmdline and dt) afaik.
> 
>>
>> My primary source of code was Ma Haiju's tree and OPenWRT's tree, but would some people like to push some of the openwrt driver upstream somehow ?
> 
> I was planning this somehow, but lack the resources to seriously move
> forward. I've mostly been focussing on cleaning up Ma Haiju's code and
> improving support for the SATA driver (ie. adding support for both
> ports) and re-factoring the stmmac-based Ethernet driver to match the
> current kernel driver's style.
> However, I'm still using platform-specific includes (hardware.h) and
> thus look forward to rebase SATA and Ethernet support on top of your
> tree, as that would unluck ox820 support in multi-v6 instead of having
> a platform-specific kernel.

I made a fork of the SATA driver for the OX810SE who needs the external DMA
to work since it lacks the SATA-sgdma as used in OX820.
But it seems having Ethernet support would be easy, I can rework it and post it.

Yes, It would be great to sync with the upstream tree at some point, please tell
me how my work could be useful.

I only own a PogoPlug v3 to support the basic OX820, but I will lack hardware to
support PCIe and the dual SATA setup at some point.

The next work I plan to do once the basic OX820 boot is merged is to push the USB,
and the PLL support in the clock driver. The SATA and PCIe would be a natural following work.

> 
> Currently there are problems with the NAND driver failing to detect the
> chip on non-PCIe platform like the PogoPlug V3 (non-Pro), MitraStar
> STG-212 and probably other non-PCIe boards which I didn't check yet.
> This magically happened when switching from kernel 4.1 to 4.4, I'm
> bisecting this since, but the problem seems to be hidden somewhere
> between the lines (ie. probe-order-related or such)...
> Did you test your NAND driver on any non-PCIe boards and did it work?

Actually I tested only on non-PCIe, since I only own a PogoPlug v3 (non-pro) and the
probe works perfectly on 4.9-rc1 :
[...]
nand: Could not find valid ONFI parameter page; aborting
nand: device found, Manufacturer ID: 0xad, Chip ID: 0xf1
nand: Hynix NAND 128MiB 3,3V 8-bit
nand: 128 MiB, SLC, erase size: 128 KiB, page size: 2048, OOB size: 64
Scanning device for bad blocks
Bad eraseblock 511 at 0x000003fe0000
2 ofpart partitions found on MTD device 41000000.nand
Creating 2 MTD partitions on "41000000.nand":
0x000000000000-0x000000e00000 : "boot"
0x000000e00000-0x000008000000 : "ubi"
[...]
# ubiattach -p /dev/mtd1
ubi0: attaching mtd1
ubi0: scanning is finished
ubi0 warning: ubi_eba_init: cannot reserve enough PEBs for bad PEB handling, reserved 9, need 19
ubi0: attached mtd1 (name "ubi", size 114 MiB)
ubi0: PEB size: 131072 bytes (128 KiB), LEB size: 129024 bytes
ubi0: min./max. I/O unit sizes: 2048/2048, sub-page size 512
ubi0: VID header offset: 512 (aligned 512), data offset: 2048
ubi0: good PEBs: 911, bad PEBs: 1, corrupted PEBs: 0
ubi0: user volume: 1, internal volumes: 1, max. volumes count: 128
ubi0: max/mean erase counter: 2/0, WL threshold: 4096, image sequence number: 0
ubi0: available PEBs: 0, total reserved PEBs: 911, PEBs reserved for bad PEB handling: 9
ubi0: background thread "ubi_bgt0d" started, PID 824
UBI device number 0, total 911 LEBs (117540864 bytes, 112.1 MiB), available 0 LEBs (0 bytes), LEB size 129024 bytes (126.0 KiB)
[...]

> 
> 
> For a more or less complete history of the changes I made since
> branching of Ma Haijun's tree, see
> 
> https://git.lede-project.org/?p=lede/dangole/staging.git;a=history;f=target/linux/oxnas;hb=refs/heads/oxnas-nand
> 
> and for the very early history, prior to the merge into the official
> OpenWrt tree, see
> 
> http://gitorious.org/openwrt-oxnas/openwrt-oxnas.git
> 

Great, thanks for the hints.

I did set up a ML for the upstream work at linux-oxnas at lists.tuxfamily.org and a patchwork interface https://patchwork.kernel.org/project/linux-oxnas/list/ if it can be helpful.

I also idle on #linux-oxnas on freenode...

Neil



From cyrille.pitchen at atmel.com  Tue Oct 18 07:58:44 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Tue, 18 Oct 2016 16:58:44 +0200
Subject: [PATCH 1/1] MAINTAINERS: add a maintainer for the SPI NOR subsystem
Message-ID: <0a3eaa21fb0f38743308c9cc9fc5d2373f4877de.1476802288.git.cyrille.pitchen@atmel.com>

I would like to volunteer as a maintainer for the SPI NOR part of the MTD
subsystem.

Over the last months, a significant number of SPI NOR related patches have
been submitted, some of them have been reviewed, but very few have finally
been merged. Hence, the number of pending SPI NOR related patches continues
to increase over the time.

Through my work on SPI NOR memories from many manufacturers over the last
two years, I've gained a solid understanding of this technology.
I've already helped by reviewing patches from other contributors on the
mailing list, and would like to help getting those patches integrated by
volunteering as a maintainer for this specific area.

Boris Brezillon has already stepped up as a maintainer for the NAND
sub-subsystem in MTD, and the SPI NOR sub-subsystem could be handled in
the same way: I would be reviewing patches touching this area, collecting
them and sending pull requests to Brian Norris.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
 MAINTAINERS | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 757f9c4b388d..73e9319b3f9f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11390,6 +11390,16 @@ W:	http://www.st.com/spear
 S:	Maintained
 F:	drivers/clk/spear/
 
+SPI NOR SUBSYSTEM
+M:	Cyrille Pitchen <cyrille.pitchen at atmel.com>
+L:	linux-mtd at lists.infradead.org
+W:	http://www.linux-mtd.infradead.org/
+Q:	http://patchwork.ozlabs.org/project/linux-mtd/list/
+T:	git git://github.com/spi-nor/linux.git
+S:	Maintained
+F:	drivers/mtd/spi-nor/
+F:	include/linux/mtd/spi-nor.h
+
 SPI SUBSYSTEM
 M:	Mark Brown <broonie at kernel.org>
 L:	linux-spi at vger.kernel.org
-- 
2.7.4



From marex at denx.de  Tue Oct 18 08:17:07 2016
From: marex at denx.de (Marek Vasut)
Date: Tue, 18 Oct 2016 17:17:07 +0200
Subject: [PATCH 1/1] MAINTAINERS: add a maintainer for the SPI NOR
 subsystem
In-Reply-To: <0a3eaa21fb0f38743308c9cc9fc5d2373f4877de.1476802288.git.cyrille.pitchen@atmel.com>
References: <0a3eaa21fb0f38743308c9cc9fc5d2373f4877de.1476802288.git.cyrille.pitchen@atmel.com>
Message-ID: <d4e954c1-0bbb-fc16-4e9a-46c25ec4fb9e@denx.de>

On 10/18/2016 04:58 PM, Cyrille Pitchen wrote:
> I would like to volunteer as a maintainer for the SPI NOR part of the MTD
> subsystem.
> 
> Over the last months, a significant number of SPI NOR related patches have
> been submitted, some of them have been reviewed, but very few have finally
> been merged. Hence, the number of pending SPI NOR related patches continues
> to increase over the time.
> 
> Through my work on SPI NOR memories from many manufacturers over the last
> two years, I've gained a solid understanding of this technology.
> I've already helped by reviewing patches from other contributors on the
> mailing list, and would like to help getting those patches integrated by
> volunteering as a maintainer for this specific area.
> 
> Boris Brezillon has already stepped up as a maintainer for the NAND
> sub-subsystem in MTD, and the SPI NOR sub-subsystem could be handled in
> the same way: I would be reviewing patches touching this area, collecting
> them and sending pull requests to Brian Norris.
> 
> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>

Let me know if you need co-maintainer.

> ---
>  MAINTAINERS | 10 ++++++++++
>  1 file changed, 10 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 757f9c4b388d..73e9319b3f9f 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -11390,6 +11390,16 @@ W:	http://www.st.com/spear
>  S:	Maintained
>  F:	drivers/clk/spear/
>  
> +SPI NOR SUBSYSTEM
> +M:	Cyrille Pitchen <cyrille.pitchen at atmel.com>
> +L:	linux-mtd at lists.infradead.org
> +W:	http://www.linux-mtd.infradead.org/
> +Q:	http://patchwork.ozlabs.org/project/linux-mtd/list/
> +T:	git git://github.com/spi-nor/linux.git
> +S:	Maintained
> +F:	drivers/mtd/spi-nor/
> +F:	include/linux/mtd/spi-nor.h
> +
>  SPI SUBSYSTEM
>  M:	Mark Brown <broonie at kernel.org>
>  L:	linux-spi at vger.kernel.org
> 


-- 
Best regards,
Marek Vasut


From richard.weinberger at gmail.com  Tue Oct 18 08:30:34 2016
From: richard.weinberger at gmail.com (Richard Weinberger)
Date: Tue, 18 Oct 2016 17:30:34 +0200
Subject: [PATCH 1/1] MAINTAINERS: add a maintainer for the SPI NOR
 subsystem
In-Reply-To: <d4e954c1-0bbb-fc16-4e9a-46c25ec4fb9e@denx.de>
References: <0a3eaa21fb0f38743308c9cc9fc5d2373f4877de.1476802288.git.cyrille.pitchen@atmel.com>
 <d4e954c1-0bbb-fc16-4e9a-46c25ec4fb9e@denx.de>
Message-ID: <CAFLxGvy9okx1cHnRhq2U-u574PzAk=Tampw1Fmvp4KzY8vnDnw@mail.gmail.com>

On Tue, Oct 18, 2016 at 5:17 PM, Marek Vasut <marex at denx.de> wrote:
> On 10/18/2016 04:58 PM, Cyrille Pitchen wrote:
>> I would like to volunteer as a maintainer for the SPI NOR part of the MTD
>> subsystem.
>>
>> Over the last months, a significant number of SPI NOR related patches have
>> been submitted, some of them have been reviewed, but very few have finally
>> been merged. Hence, the number of pending SPI NOR related patches continues
>> to increase over the time.
>>
>> Through my work on SPI NOR memories from many manufacturers over the last
>> two years, I've gained a solid understanding of this technology.
>> I've already helped by reviewing patches from other contributors on the
>> mailing list, and would like to help getting those patches integrated by
>> volunteering as a maintainer for this specific area.
>>
>> Boris Brezillon has already stepped up as a maintainer for the NAND
>> sub-subsystem in MTD, and the SPI NOR sub-subsystem could be handled in
>> the same way: I would be reviewing patches touching this area, collecting
>> them and sending pull requests to Brian Norris.

I'd suggest you send pull requests directly to Linus.
Same for NAND.

>> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
>
> Let me know if you need co-maintainer.

+1

While we are here, what about forming a MTD maintainer team?
This concept works very well for other subsystems.

-- 
Thanks,
//richard


From cyrille.pitchen at atmel.com  Tue Oct 18 08:55:23 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Tue, 18 Oct 2016 17:55:23 +0200
Subject: [PATCH 1/1] MAINTAINERS: add a maintainer for the SPI NOR
 subsystem
In-Reply-To: <CAFLxGvy9okx1cHnRhq2U-u574PzAk=Tampw1Fmvp4KzY8vnDnw@mail.gmail.com>
References: <0a3eaa21fb0f38743308c9cc9fc5d2373f4877de.1476802288.git.cyrille.pitchen@atmel.com>
 <d4e954c1-0bbb-fc16-4e9a-46c25ec4fb9e@denx.de>
 <CAFLxGvy9okx1cHnRhq2U-u574PzAk=Tampw1Fmvp4KzY8vnDnw@mail.gmail.com>
Message-ID: <3d45f698-08e9-e672-d405-1ab9bfec1222@atmel.com>

Le 18/10/2016 ? 17:30, Richard Weinberger a ?crit :
> On Tue, Oct 18, 2016 at 5:17 PM, Marek Vasut <marex at denx.de> wrote:
>> On 10/18/2016 04:58 PM, Cyrille Pitchen wrote:
>>> I would like to volunteer as a maintainer for the SPI NOR part of the MTD
>>> subsystem.
>>>
>>> Over the last months, a significant number of SPI NOR related patches have
>>> been submitted, some of them have been reviewed, but very few have finally
>>> been merged. Hence, the number of pending SPI NOR related patches continues
>>> to increase over the time.
>>>
>>> Through my work on SPI NOR memories from many manufacturers over the last
>>> two years, I've gained a solid understanding of this technology.
>>> I've already helped by reviewing patches from other contributors on the
>>> mailing list, and would like to help getting those patches integrated by
>>> volunteering as a maintainer for this specific area.
>>>
>>> Boris Brezillon has already stepped up as a maintainer for the NAND
>>> sub-subsystem in MTD, and the SPI NOR sub-subsystem could be handled in
>>> the same way: I would be reviewing patches touching this area, collecting
>>> them and sending pull requests to Brian Norris.
> 
> I'd suggest you send pull requests directly to Linus.
> Same for NAND.
> 
>>> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
>>
>> Let me know if you need co-maintainer.
> 
> +1
> 
> While we are here, what about forming a MTD maintainer team?
> This concept works very well for other subsystems.
> 

I totally agree with you so if Marek and you volunteer as well, your help
will be precious!


From richard at nod.at  Tue Oct 18 09:15:23 2016
From: richard at nod.at (Richard Weinberger)
Date: Tue, 18 Oct 2016 18:15:23 +0200
Subject: [PATCH 1/1] MAINTAINERS: add a maintainer for the SPI NOR
 subsystem
In-Reply-To: <3d45f698-08e9-e672-d405-1ab9bfec1222@atmel.com>
References: <0a3eaa21fb0f38743308c9cc9fc5d2373f4877de.1476802288.git.cyrille.pitchen@atmel.com>
 <d4e954c1-0bbb-fc16-4e9a-46c25ec4fb9e@denx.de>
 <CAFLxGvy9okx1cHnRhq2U-u574PzAk=Tampw1Fmvp4KzY8vnDnw@mail.gmail.com>
 <3d45f698-08e9-e672-d405-1ab9bfec1222@atmel.com>
Message-ID: <cf010a6c-b642-0994-bbfd-c86d5ab24e6e@nod.at>

On 18.10.2016 17:55, Cyrille Pitchen wrote:
> Le 18/10/2016 ? 17:30, Richard Weinberger a ?crit :
>> On Tue, Oct 18, 2016 at 5:17 PM, Marek Vasut <marex at denx.de> wrote:
>>> On 10/18/2016 04:58 PM, Cyrille Pitchen wrote:
>>>> I would like to volunteer as a maintainer for the SPI NOR part of the MTD
>>>> subsystem.
>>>>
>>>> Over the last months, a significant number of SPI NOR related patches have
>>>> been submitted, some of them have been reviewed, but very few have finally
>>>> been merged. Hence, the number of pending SPI NOR related patches continues
>>>> to increase over the time.
>>>>
>>>> Through my work on SPI NOR memories from many manufacturers over the last
>>>> two years, I've gained a solid understanding of this technology.
>>>> I've already helped by reviewing patches from other contributors on the
>>>> mailing list, and would like to help getting those patches integrated by
>>>> volunteering as a maintainer for this specific area.
>>>>
>>>> Boris Brezillon has already stepped up as a maintainer for the NAND
>>>> sub-subsystem in MTD, and the SPI NOR sub-subsystem could be handled in
>>>> the same way: I would be reviewing patches touching this area, collecting
>>>> them and sending pull requests to Brian Norris.
>>
>> I'd suggest you send pull requests directly to Linus.
>> Same for NAND.
>>
>>>> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
>>>
>>> Let me know if you need co-maintainer.
>>
>> +1
>>
>> While we are here, what about forming a MTD maintainer team?
>> This concept works very well for other subsystems.
>>
> 
> I totally agree with you so if Marek and you volunteer as well, your help
> will be precious!

Well, my SPI-NOR fu is not strong. And UBI/UBIFS keeps me busy.
But if Brian likes the idea of having a MTD maintainer team I'll offer my help.

Thanks,
//richard


From robh at kernel.org  Tue Oct 18 09:39:13 2016
From: robh at kernel.org (Rob Herring)
Date: Tue, 18 Oct 2016 11:39:13 -0500
Subject: [PATCH] mtd/spi-nor: Add SPI memory controllers for Aspeed SoCs
In-Reply-To: <1476723427-13243-1-git-send-email-clg@kaod.org>
References: <1476723427-13243-1-git-send-email-clg@kaod.org>
Message-ID: <20161018163913.7z337iyc53atp4yd@rob-hp-laptop>

On Mon, Oct 17, 2016 at 06:57:07PM +0200, C?dric Le Goater wrote:
> This driver adds mtd support for spi-nor attached to either or both of
> the Firmware Memory Controller or the SPI Flash Controller (AST2400
> only).
> 
> The SMC controllers on the Aspeed AST2500 SoC are very similar to the
> ones found on the AST2400. The differences are on the number of
> supported flash modules and their default mappings in the SoC address
> space.
> 
> The Aspeed AST2500 has one SPI controller for the BMC firmware and two
> for the host firmware. All controllers have now the same set of
> registers compatible with the AST2400 FMC controller and the legacy
> 'SMC' controller is fully gone.
> 
> Based on previous work from Milton D. Miller II <miltonm at us.ibm.com>
> 
> Signed-off-by: C?dric Le Goater <clg at kaod.org>
> ---
>  .../devicetree/bindings/mtd/aspeed-smc.txt         |  86 +++
>  drivers/mtd/spi-nor/Kconfig                        |  12 +
>  drivers/mtd/spi-nor/Makefile                       |   1 +
>  drivers/mtd/spi-nor/aspeed-smc.c                   | 746 +++++++++++++++++++++
>  4 files changed, 845 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mtd/aspeed-smc.txt
>  create mode 100644 drivers/mtd/spi-nor/aspeed-smc.c
> 
> diff --git a/Documentation/devicetree/bindings/mtd/aspeed-smc.txt b/Documentation/devicetree/bindings/mtd/aspeed-smc.txt
> new file mode 100644
> index 000000000000..f6bfa7761205
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mtd/aspeed-smc.txt
> @@ -0,0 +1,86 @@
> +* Aspeed Static Memory controller
> +* Aspeed SPI Flash Controller
> +
> +The Static memory controller in the ast2400 supports 5 chip selects each
> +can be attached to NAND, parallel NOR, or SPI NOR attached flash.  The
> +Firmware Memory Controller in the ast2500 supports 3 chip selects, two of
> +which are always in SPI-NOR mode and the third can be SPI-NOR or parallel
> +flash.  The SPI flash controller in the ast2400 supports one of 2 chip
> +selects selected by pinmux.  The two SPI flash controllers in the ast2500
> +each support two chip selects.
> +
> +Required properties:
> +  - compatible : Should be one of
> +	"aspeed,ast2400-fmc" for the AST2400 Static Memory Controller
> +	"aspeed,ast2400-smc" for the AST2400 SPI Flash Controller
> +	"aspeed,ast2500-fmc" for the AST2500 Firmware SPI Memory Controller
> +	"aspeed,ast2500-smc" for the AST2500 SPI Flash Controllers
> +  - reg : the first contains the control register location and length,
> +          the second contains the memory window mapping address and length
> +  - clocks : The APB clock input to the controller
> +  - #address-cells : must be 1 corresponding to chip select child binding
> +  - #size-cells : must be 0 corresponding to chip select child binding
> +
> +Optional properties:
> +  - aspeed,fmc-has-dma : controller supports DMA transfers

The compatible should imply this.

> +  - interrupts : Should contain the interrupt for the dma device if an fmc
> +
> +Child node required properties:

Need to say what the child nodes are.

> +  - reg : must contain chip select number in first cell of address, must
> +	  be 1 tuple long
> +  - compatible : may contain "vendor,part", must include "jedec,spi-nor"
> +		when attached to SPI flash (see spi-nor.txt binding).
> +
> +Child node optional properties:
> +  - label           - (optional) name to assign to mtd, default os assigned
> +
> +Child node optional properties for SPI mode (may be ignored):
> +  - spi-max-frequency - (optional) max frequency of spi bus
> +  - spi-cpol        - (optional) Empty property indicating device requires
> +			inverse clock polarity (CPOL) mode (boolean)
> +  - spi-cpha        - (optional) Empty property indicating device requires
> +			shifted clock phase (CPHA) mode (boolean)
> +  - spi-tx-bus-width - (optional) The bus width(number of data wires) that
> +                        used for MOSI. Defaults to 1 if not present.
> +  - spi-rx-bus-width - (optional) The bus width(number of data wires) that
> +                        used for MOSI. Defaults to 1 if not present.
> +
> +Grandchild node optional properties:
> + - see mtd/partiton.txt for partitioning bindings and mtd naming
> +
> +
> +Example:
> +
> +fmc: fmc at 1e620000 {
> +	compatible = "aspeed,ast2400-fmc";
> +	reg = < 0x1e620000 0x94
> +		0x20000000 0x02000000
> +		0x22000000 0x02000000 >;
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +	flash at 0 {
> +		reg = < 0 >;
> +		compatible = "jedec,spi-nor" ;
> +		label = "bmc";

label isn't really a defined property here. Belongs in jedec,spi-nor 
binding if you want to add it.

> +		/* spi-max-frequency = <>; */
> +		/* m25p,fast-read; */
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +		boot at 0 {

Use the newer style with all partitions under a 'partitions' node.

> +			label = "boot-loader";
> +			reg = < 0 0x8000 >

Missing ';'

> +		}
> +		image at 8000 {
> +			label = "kernel-image";
> +			reg = < 0x8000 0x1f8000 >

ditto

> +		}
> +	};
> +	flash at 1 {
> +		reg = < 1 >;
> +		compatible = "jedec,spi-nor" ;
> +		label = "alt";
> +		/* spi-max-frequency = <>; */
> +		status = "fail";
> +		/* m25p,fast-read; */
> +	};
> +};


From computersforpeace at gmail.com  Tue Oct 18 11:46:51 2016
From: computersforpeace at gmail.com (Brian Norris)
Date: Tue, 18 Oct 2016 11:46:51 -0700
Subject: [PATCH 1/1] MAINTAINERS: add a maintainer for the SPI NOR
 subsystem
In-Reply-To: <cf010a6c-b642-0994-bbfd-c86d5ab24e6e@nod.at>
References: <0a3eaa21fb0f38743308c9cc9fc5d2373f4877de.1476802288.git.cyrille.pitchen@atmel.com>
 <d4e954c1-0bbb-fc16-4e9a-46c25ec4fb9e@denx.de>
 <CAFLxGvy9okx1cHnRhq2U-u574PzAk=Tampw1Fmvp4KzY8vnDnw@mail.gmail.com>
 <3d45f698-08e9-e672-d405-1ab9bfec1222@atmel.com>
 <cf010a6c-b642-0994-bbfd-c86d5ab24e6e@nod.at>
Message-ID: <20161018184651.GA71760@google.com>

+ others

On Tue, Oct 18, 2016 at 06:15:23PM +0200, Richard Weinberger wrote:
> On 18.10.2016 17:55, Cyrille Pitchen wrote:
> > Le 18/10/2016 ? 17:30, Richard Weinberger a ?crit :
> >> On Tue, Oct 18, 2016 at 5:17 PM, Marek Vasut <marex at denx.de> wrote:
> >>> On 10/18/2016 04:58 PM, Cyrille Pitchen wrote:
> >>>> I would like to volunteer as a maintainer for the SPI NOR part of the MTD
> >>>> subsystem.

Awesome!

> >>>> Over the last months, a significant number of SPI NOR related patches have
> >>>> been submitted, some of them have been reviewed, but very few have finally
> >>>> been merged. Hence, the number of pending SPI NOR related patches continues
> >>>> to increase over the time.

Agreed, and sorry. But I guess the delays had the side effect of forcing
peoples hands, instead of delaying the inevitable.

> >>>> Through my work on SPI NOR memories from many manufacturers over the last
> >>>> two years, I've gained a solid understanding of this technology.
> >>>> I've already helped by reviewing patches from other contributors on the
> >>>> mailing list, and would like to help getting those patches integrated by
> >>>> volunteering as a maintainer for this specific area.

Agreed.

> >>>> Boris Brezillon has already stepped up as a maintainer for the NAND
> >>>> sub-subsystem in MTD, and the SPI NOR sub-subsystem could be handled in
> >>>> the same way: I would be reviewing patches touching this area, collecting
> >>>> them and sending pull requests to Brian Norris.
> >>
> >> I'd suggest you send pull requests directly to Linus.
> >> Same for NAND.

I could go with either method I suppose, but I don't personally like the
idea of splitting out the various bits of MTD into *completely*
independent lines of development. As long as someone (not necessarily
me) can manage pulling the sub-subsystems together, I think it would
make sense to have 1 PR for Linus for non-UBI/FS MTD changes.

> >>>> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
> >>>
> >>> Let me know if you need co-maintainer.
> >>
> >> +1

+1, I think I've not-so-subtly suggested this to Marek previously.

> >> While we are here, what about forming a MTD maintainer team?
> >> This concept works very well for other subsystems.
> >>
> > 
> > I totally agree with you so if Marek and you volunteer as well, your help
> > will be precious!
> 
> Well, my SPI-NOR fu is not strong. And UBI/UBIFS keeps me busy.
> But if Brian likes the idea of having a MTD maintainer team I'll offer my help.

I think a MTD maintainer team would be good to try, and I think it might
help to resolve my above complaint; a maintainer team could help to make
sure that everything can be coordinated in one tree + pull request,
without adding too many extra points of failure (e.g., so we don't have
awesome SPI NOR and NAND trees get bogged down by a slow MTD pull).

Random thoughts:

 Does it make sense to still use infradead.org? We'd need to add a few
 users there.

 Trust? I have met most of you in person, but not all, and I don't have
 signed keys from all of you. I don't know what the best way to get a
 group-writeable repo with credentials for all of you that we can trust.
 (FWIW, neither Artem nor David met me, but they saw it fit to grant me
 infradead.org access ;) )

 Coordination: how do we avoid stepping on each other's toes? We'd have
 to definitely 100% kill 'git push -f' and 'git rebase'. Also, would
 patchwork help or hurt us here? I think Boris and I have been sort of
 using it, but it's still got a pretty good backlog (partly real --
 i.e., the cause for this thread; and partly artificial, due to
 accounting).

 What to do about mtd-utils.git? That's been languishing a bit, and it
 has no release schedule. Maybe we want a plan for that too.

BTW, will anybody be at Linux Plumbers? I plan to be there in a few
weeks. And something tells me dwmw2 will be there.

Brian


From richard at nod.at  Tue Oct 18 12:02:27 2016
From: richard at nod.at (Richard Weinberger)
Date: Tue, 18 Oct 2016 21:02:27 +0200
Subject: [PATCH 1/1] MAINTAINERS: add a maintainer for the SPI NOR
 subsystem
In-Reply-To: <20161018184651.GA71760@google.com>
References: <0a3eaa21fb0f38743308c9cc9fc5d2373f4877de.1476802288.git.cyrille.pitchen@atmel.com>
 <d4e954c1-0bbb-fc16-4e9a-46c25ec4fb9e@denx.de>
 <CAFLxGvy9okx1cHnRhq2U-u574PzAk=Tampw1Fmvp4KzY8vnDnw@mail.gmail.com>
 <3d45f698-08e9-e672-d405-1ab9bfec1222@atmel.com>
 <cf010a6c-b642-0994-bbfd-c86d5ab24e6e@nod.at>
 <20161018184651.GA71760@google.com>
Message-ID: <09ac9f8a-d6a0-97a8-c73a-ffb53bc1a4c8@nod.at>

Brian,

On 18.10.2016 20:46, Brian Norris wrote:
>>> I totally agree with you so if Marek and you volunteer as well, your help
>>> will be precious!
>>
>> Well, my SPI-NOR fu is not strong. And UBI/UBIFS keeps me busy.
>> But if Brian likes the idea of having a MTD maintainer team I'll offer my help.
> 
> I think a MTD maintainer team would be good to try, and I think it might
> help to resolve my above complaint; a maintainer team could help to make
> sure that everything can be coordinated in one tree + pull request,
> without adding too many extra points of failure (e.g., so we don't have
> awesome SPI NOR and NAND trees get bogged down by a slow MTD pull).
> 
> Random thoughts:
> 
>  Does it make sense to still use infradead.org? We'd need to add a few
>  users there.

What else do you have in mind? kernel.org?
As long all users with commit access are member of the kernel.org web of
trust any host should be fine.

>  Trust? I have met most of you in person, but not all, and I don't have
>  signed keys from all of you. I don't know what the best way to get a
>  group-writeable repo with credentials for all of you that we can trust.
>  (FWIW, neither Artem nor David met me, but they saw it fit to grant me
>  infradead.org access ;) )

I'd go with the kernel.org web of trust.

>  Coordination: how do we avoid stepping on each other's toes? We'd have
>  to definitely 100% kill 'git push -f' and 'git rebase'. Also, would
>  patchwork help or hurt us here? I think Boris and I have been sort of
>  using it, but it's still got a pretty good backlog (partly real --
>  i.e., the cause for this thread; and partly artificial, due to
>  accounting).

patchwork should be a good start. We could also try the tip scripts used
by the x86 maintainer team.
https://git.kernel.org/cgit/linux/kernel/git/tip/tip.git/tree/.tip?h=tip

>  What to do about mtd-utils.git? That's been languishing a bit, and it
>  has no release schedule. Maybe we want a plan for that too.

I'd volunteer to nurse it together with David Oberhollenzer.
In fact, David is currently preparing a v2 pre-release of mtd-utils.
https://github.com/sigma-star/mtd-utils/commits/wip_v2-rc1

We reworked a lot of code and added new tools.

Thanks,
//richard


From boris.brezillon at free-electrons.com  Tue Oct 18 12:15:48 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Tue, 18 Oct 2016 21:15:48 +0200
Subject: [PATCH 1/1] MAINTAINERS: add a maintainer for the SPI NOR
 subsystem
In-Reply-To: <20161018184651.GA71760@google.com>
References: <0a3eaa21fb0f38743308c9cc9fc5d2373f4877de.1476802288.git.cyrille.pitchen@atmel.com>
 <d4e954c1-0bbb-fc16-4e9a-46c25ec4fb9e@denx.de>
 <CAFLxGvy9okx1cHnRhq2U-u574PzAk=Tampw1Fmvp4KzY8vnDnw@mail.gmail.com>
 <3d45f698-08e9-e672-d405-1ab9bfec1222@atmel.com>
 <cf010a6c-b642-0994-bbfd-c86d5ab24e6e@nod.at>
 <20161018184651.GA71760@google.com>
Message-ID: <20161018211548.08dded8a@bbrezillon>

On Tue, 18 Oct 2016 11:46:51 -0700
Brian Norris <computersforpeace at gmail.com> wrote:

> + others
> 
> On Tue, Oct 18, 2016 at 06:15:23PM +0200, Richard Weinberger wrote:
> > On 18.10.2016 17:55, Cyrille Pitchen wrote:  
> > > Le 18/10/2016 ? 17:30, Richard Weinberger a ?crit :  
> > >> On Tue, Oct 18, 2016 at 5:17 PM, Marek Vasut <marex at denx.de> wrote:  
> > >>> On 10/18/2016 04:58 PM, Cyrille Pitchen wrote:  
> > >>>> I would like to volunteer as a maintainer for the SPI NOR part of the MTD
> > >>>> subsystem.  
> 
> Awesome!
> 
> > >>>> Over the last months, a significant number of SPI NOR related patches have
> > >>>> been submitted, some of them have been reviewed, but very few have finally
> > >>>> been merged. Hence, the number of pending SPI NOR related patches continues
> > >>>> to increase over the time.  
> 
> Agreed, and sorry. But I guess the delays had the side effect of forcing
> peoples hands, instead of delaying the inevitable.
> 
> > >>>> Through my work on SPI NOR memories from many manufacturers over the last
> > >>>> two years, I've gained a solid understanding of this technology.
> > >>>> I've already helped by reviewing patches from other contributors on the
> > >>>> mailing list, and would like to help getting those patches integrated by
> > >>>> volunteering as a maintainer for this specific area.  
> 
> Agreed.
> 
> > >>>> Boris Brezillon has already stepped up as a maintainer for the NAND
> > >>>> sub-subsystem in MTD, and the SPI NOR sub-subsystem could be handled in
> > >>>> the same way: I would be reviewing patches touching this area, collecting
> > >>>> them and sending pull requests to Brian Norris.  
> > >>
> > >> I'd suggest you send pull requests directly to Linus.
> > >> Same for NAND.  
> 
> I could go with either method I suppose, but I don't personally like the
> idea of splitting out the various bits of MTD into *completely*
> independent lines of development. As long as someone (not necessarily
> me) can manage pulling the sub-subsystems together, I think it would
> make sense to have 1 PR for Linus for non-UBI/FS MTD changes.
> 
> > >>>> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>  
> > >>>
> > >>> Let me know if you need co-maintainer.  
> > >>
> > >> +1  
> 
> +1, I think I've not-so-subtly suggested this to Marek previously.

Okay, that's all great news!
You can add my ack after adding Marek as a co-maintainer.

> 
> > >> While we are here, what about forming a MTD maintainer team?
> > >> This concept works very well for other subsystems.
> > >>  
> > > 
> > > I totally agree with you so if Marek and you volunteer as well, your help
> > > will be precious!  
> > 
> > Well, my SPI-NOR fu is not strong. And UBI/UBIFS keeps me busy.
> > But if Brian likes the idea of having a MTD maintainer team I'll offer my help.  
> 
> I think a MTD maintainer team would be good to try, and I think it might
> help to resolve my above complaint; a maintainer team could help to make
> sure that everything can be coordinated in one tree + pull request,
> without adding too many extra points of failure (e.g., so we don't have
> awesome SPI NOR and NAND trees get bogged down by a slow MTD pull).
> 
> Random thoughts:
> 
>  Does it make sense to still use infradead.org? We'd need to add a few
>  users there.
> 
>  Trust? I have met most of you in person, but not all, and I don't have
>  signed keys from all of you. I don't know what the best way to get a
>  group-writeable repo with credentials for all of you that we can trust.
>  (FWIW, neither Artem nor David met me, but they saw it fit to grant me
>  infradead.org access ;) )
> 
>  Coordination: how do we avoid stepping on each other's toes? We'd have
>  to definitely 100% kill 'git push -f' and 'git rebase'. Also, would
>  patchwork help or hurt us here? I think Boris and I have been sort of
>  using it, but it's still got a pretty good backlog (partly real --
>  i.e., the cause for this thread; and partly artificial, due to
>  accounting).

I really think we should keep separate trees for the spi-nor and nand
sub-subsystems, and then do PRs. The question is, how do we agree that
a PR should be pulled in the MTD tree.

I guess we could have a simple rule like, if it's been reviewed by at
least X person (I guess 2 is acceptable), then we can merge it.

> 
>  What to do about mtd-utils.git? That's been languishing a bit, and it
>  has no release schedule. Maybe we want a plan for that too.

Richard and David had some plans for the mtd-utils repo, and I think
they already have the permissions to push things to this repo, so the
best solution is probably to officially promote them maintainers of
mtd-utils.

> 
> BTW, will anybody be at Linux Plumbers? I plan to be there in a few
> weeks. And something tells me dwmw2 will be there.

Unfortunately I won't attend plumbers :-(.




From richard at nod.at  Tue Oct 18 12:25:43 2016
From: richard at nod.at (Richard Weinberger)
Date: Tue, 18 Oct 2016 21:25:43 +0200
Subject: [PATCH][V2] ubi: fix swapped arguments to call to ubi_alloc_aeb
In-Reply-To: <20161016173856.11d486aa@bbrezillon>
References: <20161015160011.27600-1-colin.king@canonical.com>
 <20161016173856.11d486aa@bbrezillon>
Message-ID: <3b4f59d5-0795-c8fe-0a5e-3f36813b8133@nod.at>

On 16.10.2016 17:38, Boris Brezillon wrote:
> On Sat, 15 Oct 2016 17:00:11 +0100
> Colin King <colin.king at canonical.com> wrote:
> 
>> From: Colin Ian King <colin.king at canonical.com>
>>
>> Static analysis by CoverityScan detected the ec and pnum
>> arguments are in the wrong order on a call to ubi_alloc_aeb.
>> Swap the order to fix this.
>>
>> Fixes: 91f4285fe389a27 ("UBI: provide helpers to allocate and free aeb elements")
>> Signed-off-by: Colin Ian King <colin.king at canonical.com>
> 
> Reviewed-by: Boris Brezillon <boris.brezillon at free-electrons.com>

Applied. :)

Thanks,
//richard


From marex at denx.de  Tue Oct 18 09:37:40 2016
From: marex at denx.de (Marek Vasut)
Date: Tue, 18 Oct 2016 18:37:40 +0200
Subject: [PATCH 1/1] MAINTAINERS: add a maintainer for the SPI NOR
 subsystem
In-Reply-To: <cf010a6c-b642-0994-bbfd-c86d5ab24e6e@nod.at>
References: <0a3eaa21fb0f38743308c9cc9fc5d2373f4877de.1476802288.git.cyrille.pitchen@atmel.com>
 <d4e954c1-0bbb-fc16-4e9a-46c25ec4fb9e@denx.de>
 <CAFLxGvy9okx1cHnRhq2U-u574PzAk=Tampw1Fmvp4KzY8vnDnw@mail.gmail.com>
 <3d45f698-08e9-e672-d405-1ab9bfec1222@atmel.com>
 <cf010a6c-b642-0994-bbfd-c86d5ab24e6e@nod.at>
Message-ID: <326eced2-6766-e90a-7eaa-42ccdb5016a9@denx.de>

On 10/18/2016 06:15 PM, Richard Weinberger wrote:
> On 18.10.2016 17:55, Cyrille Pitchen wrote:
>> Le 18/10/2016 ? 17:30, Richard Weinberger a ?crit :
>>> On Tue, Oct 18, 2016 at 5:17 PM, Marek Vasut <marex at denx.de> wrote:
>>>> On 10/18/2016 04:58 PM, Cyrille Pitchen wrote:
>>>>> I would like to volunteer as a maintainer for the SPI NOR part of the MTD
>>>>> subsystem.
>>>>>
>>>>> Over the last months, a significant number of SPI NOR related patches have
>>>>> been submitted, some of them have been reviewed, but very few have finally
>>>>> been merged. Hence, the number of pending SPI NOR related patches continues
>>>>> to increase over the time.
>>>>>
>>>>> Through my work on SPI NOR memories from many manufacturers over the last
>>>>> two years, I've gained a solid understanding of this technology.
>>>>> I've already helped by reviewing patches from other contributors on the
>>>>> mailing list, and would like to help getting those patches integrated by
>>>>> volunteering as a maintainer for this specific area.
>>>>>
>>>>> Boris Brezillon has already stepped up as a maintainer for the NAND
>>>>> sub-subsystem in MTD, and the SPI NOR sub-subsystem could be handled in
>>>>> the same way: I would be reviewing patches touching this area, collecting
>>>>> them and sending pull requests to Brian Norris.
>>>
>>> I'd suggest you send pull requests directly to Linus.
>>> Same for NAND.
>>>
>>>>> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
>>>>
>>>> Let me know if you need co-maintainer.
>>>
>>> +1
>>>
>>> While we are here, what about forming a MTD maintainer team?
>>> This concept works very well for other subsystems.
>>>
>>
>> I totally agree with you so if Marek and you volunteer as well, your help
>> will be precious!
> 
> Well, my SPI-NOR fu is not strong. And UBI/UBIFS keeps me busy.
> But if Brian likes the idea of having a MTD maintainer team I'll offer my help.

After talking to Wolfram Sang a bit about the maintainer overload at
ELCE, I think the least I can do here is help reviewing patches. The
CQSPI upstreaming experience was real crap, it took a long time, so
we should certainly do something about it.

-- 
Best regards,
Marek Vasut


From marex at denx.de  Tue Oct 18 12:31:06 2016
From: marex at denx.de (Marek Vasut)
Date: Tue, 18 Oct 2016 21:31:06 +0200
Subject: [PATCH 1/1] MAINTAINERS: add a maintainer for the SPI NOR
 subsystem
In-Reply-To: <20161018184651.GA71760@google.com>
References: <0a3eaa21fb0f38743308c9cc9fc5d2373f4877de.1476802288.git.cyrille.pitchen@atmel.com>
 <d4e954c1-0bbb-fc16-4e9a-46c25ec4fb9e@denx.de>
 <CAFLxGvy9okx1cHnRhq2U-u574PzAk=Tampw1Fmvp4KzY8vnDnw@mail.gmail.com>
 <3d45f698-08e9-e672-d405-1ab9bfec1222@atmel.com>
 <cf010a6c-b642-0994-bbfd-c86d5ab24e6e@nod.at>
 <20161018184651.GA71760@google.com>
Message-ID: <23317635-426e-fbf8-f0b2-b59dde75900a@denx.de>

On 10/18/2016 08:46 PM, Brian Norris wrote:

[...]

>>>>>> Boris Brezillon has already stepped up as a maintainer for the NAND
>>>>>> sub-subsystem in MTD, and the SPI NOR sub-subsystem could be handled in
>>>>>> the same way: I would be reviewing patches touching this area, collecting
>>>>>> them and sending pull requests to Brian Norris.
>>>>
>>>> I'd suggest you send pull requests directly to Linus.
>>>> Same for NAND.
> 
> I could go with either method I suppose, but I don't personally like the
> idea of splitting out the various bits of MTD into *completely*
> independent lines of development. As long as someone (not necessarily
> me) can manage pulling the sub-subsystems together, I think it would
> make sense to have 1 PR for Linus for non-UBI/FS MTD changes.

Yes please, agreed. This looks far more systematic and it's what other
subsystems do.

[...]

> Random thoughts:

[...]

>  Coordination: how do we avoid stepping on each other's toes? We'd have
>  to definitely 100% kill 'git push -f' and 'git rebase'. Also, would
>  patchwork help or hurt us here?

Patchwork is nice, it helps keeping track of the patch status real well.
But there is always the problem of keeping the patchwork up-to-date when
the status of patch changes, esp. if one is offline (or maybe I didn't
look hard enough).

> I think Boris and I have been sort of
>  using it, but it's still got a pretty good backlog (partly real --
>  i.e., the cause for this thread; and partly artificial, due to
>  accounting).
> 
>  What to do about mtd-utils.git? That's been languishing a bit, and it
>  has no release schedule. Maybe we want a plan for that too.
> 
> BTW, will anybody be at Linux Plumbers? I plan to be there in a few
> weeks. And something tells me dwmw2 will be there.
> 
> Brian
> 


-- 
Best regards,
Marek Vasut


From boris.brezillon at free-electrons.com  Tue Oct 18 12:41:53 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Tue, 18 Oct 2016 21:41:53 +0200
Subject: [PATCH 1/1] MAINTAINERS: add a maintainer for the SPI NOR
 subsystem
In-Reply-To: <23317635-426e-fbf8-f0b2-b59dde75900a@denx.de>
References: <0a3eaa21fb0f38743308c9cc9fc5d2373f4877de.1476802288.git.cyrille.pitchen@atmel.com>
 <d4e954c1-0bbb-fc16-4e9a-46c25ec4fb9e@denx.de>
 <CAFLxGvy9okx1cHnRhq2U-u574PzAk=Tampw1Fmvp4KzY8vnDnw@mail.gmail.com>
 <3d45f698-08e9-e672-d405-1ab9bfec1222@atmel.com>
 <cf010a6c-b642-0994-bbfd-c86d5ab24e6e@nod.at>
 <20161018184651.GA71760@google.com>
 <23317635-426e-fbf8-f0b2-b59dde75900a@denx.de>
Message-ID: <20161018214153.69c95a06@bbrezillon>

On Tue, 18 Oct 2016 21:31:06 +0200
Marek Vasut <marex at denx.de> wrote:

> On 10/18/2016 08:46 PM, Brian Norris wrote:
> 
> [...]
> 
> >>>>>> Boris Brezillon has already stepped up as a maintainer for the NAND
> >>>>>> sub-subsystem in MTD, and the SPI NOR sub-subsystem could be handled in
> >>>>>> the same way: I would be reviewing patches touching this area, collecting
> >>>>>> them and sending pull requests to Brian Norris.  
> >>>>
> >>>> I'd suggest you send pull requests directly to Linus.
> >>>> Same for NAND.  
> > 
> > I could go with either method I suppose, but I don't personally like the
> > idea of splitting out the various bits of MTD into *completely*
> > independent lines of development. As long as someone (not necessarily
> > me) can manage pulling the sub-subsystems together, I think it would
> > make sense to have 1 PR for Linus for non-UBI/FS MTD changes.  
> 
> Yes please, agreed. This looks far more systematic and it's what other
> subsystems do.
> 
> [...]
> 
> > Random thoughts:  
> 
> [...]
> 
> >  Coordination: how do we avoid stepping on each other's toes? We'd have
> >  to definitely 100% kill 'git push -f' and 'git rebase'. Also, would
> >  patchwork help or hurt us here?  
> 
> Patchwork is nice, it helps keeping track of the patch status real well.
> But there is always the problem of keeping the patchwork up-to-date when
> the status of patch changes, esp. if one is offline (or maybe I didn't
> look hard enough).

I use git notes + a pre-push hook to help mark a patch as 'Accepted' in
patchwork, but still, it does not automate moving patches to the
'Superseeded' state (which IMO should be directly handled in patchwork)
and those who are rejected. This is why the backlog tend to grow until
I decide to do some cleanup.

We also have all those patches which are over 1 year old, but that we
keep just in case someone wants to revive them.

Anyway, I think patchwork is very useful if it's well maintained, so
maybe we should cleanup things after each release.

> 
> > I think Boris and I have been sort of
> >  using it, but it's still got a pretty good backlog (partly real --
> >  i.e., the cause for this thread; and partly artificial, due to
> >  accounting).
> > 
> >  What to do about mtd-utils.git? That's been languishing a bit, and it
> >  has no release schedule. Maybe we want a plan for that too.
> > 
> > BTW, will anybody be at Linux Plumbers? I plan to be there in a few
> > weeks. And something tells me dwmw2 will be there.
> > 
> > Brian
> >   
> 
> 



From boris.brezillon at free-electrons.com  Tue Oct 18 12:45:05 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Tue, 18 Oct 2016 21:45:05 +0200
Subject: [PATCH 02/28] [v2] mtd: mtk: avoid warning in mtk_ecc_encode
In-Reply-To: <1476785552.24626.4.camel@mtkswgap22>
References: <20161017220342.1627073-1-arnd@arndb.de>
 <20161017220557.1688282-2-arnd@arndb.de>
 <20161018071948.0b7eef05@bbrezillon>
 <1476785552.24626.4.camel@mtkswgap22>
Message-ID: <20161018214505.489628db@bbrezillon>

On Tue, 18 Oct 2016 18:12:32 +0800
RogerCC.Lin <rogercc.lin at mediatek.com> wrote:

> On Tue, 2016-10-18 at 07:19 +0200, Boris Brezillon wrote:
> > On Tue, 18 Oct 2016 00:05:31 +0200
> > Arnd Bergmann <arnd at arndb.de> wrote:
> >   
> > > When building with -Wmaybe-uninitialized, gcc produces a silly false positive
> > > warning for the mtk_ecc_encode function:
> > > 
> > > drivers/mtd/nand/mtk_ecc.c: In function 'mtk_ecc_encode':
> > > drivers/mtd/nand/mtk_ecc.c:402:15: error: 'val' may be used uninitialized in this function [-Werror=maybe-uninitialized]
> > > 
> > > The function for some reason contains a double byte swap on big-endian
> > > builds to get the OOB data into the correct order again, and is written
> > > in a slightly confusing way.
> > > 
> > > Using a simple memcpy32_fromio() to read the data simplifies it a lot
> > > so it becomes more readable and produces no warning. However, the
> > > output might not have 32-bit alignment, so we have to use another
> > > memcpy to avoid taking alignment faults or writing beyond the end
> > > of the array.
> > > 
> > > Signed-off-by: Arnd Bergmann <arnd at arndb.de>  
> > 
> > Jorge, RogerCC, can I have an Acked-by and/or Tested-by for this patch?  
> Tested, this patch is OK,
> Tested-by: RogerCC Lin <rogercc.lin at mediatek.com>

Acked-by: Boris Brezillon <boris.brezillon at free-electrons.com>

Brian, can you take this patch for the next -rc?

> 
> >   
> > > ---
> > > v2: move temporary buffer into struct mtk_ecc instead of having it
> > >     on the stack, as suggested by Boris Brezillon
> > > ---
> > >  drivers/mtd/nand/mtk_ecc.c | 19 +++++++++----------
> > >  1 file changed, 9 insertions(+), 10 deletions(-)
> > > 
> > > diff --git a/drivers/mtd/nand/mtk_ecc.c b/drivers/mtd/nand/mtk_ecc.c
> > > index d54f666..dbf2562 100644
> > > --- a/drivers/mtd/nand/mtk_ecc.c
> > > +++ b/drivers/mtd/nand/mtk_ecc.c
> > > @@ -86,6 +86,8 @@ struct mtk_ecc {
> > >  	struct completion done;
> > >  	struct mutex lock;
> > >  	u32 sectors;
> > > +
> > > +	u8 eccdata[112];
> > >  };
> > >  
> > >  static inline void mtk_ecc_wait_idle(struct mtk_ecc *ecc,
> > > @@ -366,9 +368,8 @@ int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
> > >  		   u8 *data, u32 bytes)
> > >  {
> > >  	dma_addr_t addr;
> > > -	u8 *p;
> > > -	u32 len, i, val;
> > > -	int ret = 0;
> > > +	u32 len;
> > > +	int ret;
> > >  
> > >  	addr = dma_map_single(ecc->dev, data, bytes, DMA_TO_DEVICE);
> > >  	ret = dma_mapping_error(ecc->dev, addr);
> > > @@ -393,14 +394,12 @@ int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
> > >  
> > >  	/* Program ECC bytes to OOB: per sector oob = FDM + ECC + SPARE */
> > >  	len = (config->strength * ECC_PARITY_BITS + 7) >> 3;
> > > -	p = data + bytes;
> > >  
> > > -	/* write the parity bytes generated by the ECC back to the OOB region */
> > > -	for (i = 0; i < len; i++) {
> > > -		if ((i % 4) == 0)
> > > -			val = readl(ecc->regs + ECC_ENCPAR(i / 4));
> > > -		p[i] = (val >> ((i % 4) * 8)) & 0xff;
> > > -	}
> > > +	/* write the parity bytes generated by the ECC back to temp buffer */
> > > +	__ioread32_copy(ecc->eccdata, ecc->regs + ECC_ENCPAR(0), round_up(len, 4));
> > > +
> > > +	/* copy into possibly unaligned OOB region with actual length */
> > > +	memcpy(data + bytes, ecc->eccdata, len);
> > >  timeout:
> > >  
> > >  	dma_unmap_single(ecc->dev, addr, bytes, DMA_TO_DEVICE);  
> >   
> 
> 



From marex at denx.de  Tue Oct 18 12:51:28 2016
From: marex at denx.de (Marek Vasut)
Date: Tue, 18 Oct 2016 21:51:28 +0200
Subject: [PATCH 1/1] MAINTAINERS: add a maintainer for the SPI NOR
 subsystem
In-Reply-To: <20161018214153.69c95a06@bbrezillon>
References: <0a3eaa21fb0f38743308c9cc9fc5d2373f4877de.1476802288.git.cyrille.pitchen@atmel.com>
 <d4e954c1-0bbb-fc16-4e9a-46c25ec4fb9e@denx.de>
 <CAFLxGvy9okx1cHnRhq2U-u574PzAk=Tampw1Fmvp4KzY8vnDnw@mail.gmail.com>
 <3d45f698-08e9-e672-d405-1ab9bfec1222@atmel.com>
 <cf010a6c-b642-0994-bbfd-c86d5ab24e6e@nod.at>
 <20161018184651.GA71760@google.com>
 <23317635-426e-fbf8-f0b2-b59dde75900a@denx.de>
 <20161018214153.69c95a06@bbrezillon>
Message-ID: <0c6e5a80-3f34-0e76-088a-35dad443ca2f@denx.de>

On 10/18/2016 09:41 PM, Boris Brezillon wrote:

[...]

>> Patchwork is nice, it helps keeping track of the patch status real well.
>> But there is always the problem of keeping the patchwork up-to-date when
>> the status of patch changes, esp. if one is offline (or maybe I didn't
>> look hard enough).
> 
> I use git notes + a pre-push hook to help mark a patch as 'Accepted' in
> patchwork, but still, it does not automate moving patches to the
> 'Superseeded' state (which IMO should be directly handled in patchwork)
> and those who are rejected. This is why the backlog tend to grow until
> I decide to do some cleanup.
> 
> We also have all those patches which are over 1 year old, but that we
> keep just in case someone wants to revive them.
> 
> Anyway, I think patchwork is very useful if it's well maintained, so
> maybe we should cleanup things after each release.

You've very much nailed it. Those are all my complaints about patchwork
and problems we had in U-Boot. Cleaning it up took a while.

One just has to keep an eye on patchwork so it doesn't get out of
control, otherwise the mountain of patches you have no clue about
anymore becomes the source of utter frustration.

>>> I think Boris and I have been sort of
>>>  using it, but it's still got a pretty good backlog (partly real --
>>>  i.e., the cause for this thread; and partly artificial, due to
>>>  accounting).
>>>
>>>  What to do about mtd-utils.git? That's been languishing a bit, and it
>>>  has no release schedule. Maybe we want a plan for that too.
>>>
>>> BTW, will anybody be at Linux Plumbers? I plan to be there in a few
>>> weeks. And something tells me dwmw2 will be there.
>>>
>>> Brian
>>>   
>>
>>
> 


-- 
Best regards,
Marek Vasut


From stefan at agner.ch  Tue Oct 18 12:51:00 2016
From: stefan at agner.ch (Stefan Agner)
Date: Tue, 18 Oct 2016 12:51:00 -0700
Subject: UBI assert failed in wl_tree_add at 168 using v4.9-rc1
Message-ID: <5d8e8bc09c75405a783990312dd1dc41@agner.ch>

Hi All,

After flashing and 2-3 hard resets (power-cut), I happen to get a lot of
the following stack traces:

[   33.031951] UBI assert failed in wl_tree_add at 168 (pid 1)
[   33.037763] CPU: 0 PID: 1 Comm: swapper/0 Not tainted
4.9.0-rc1-00001-g4b1532a-dirty #568
[   33.046071] Hardware name: Freescale Vybrid VF5xx/VF6xx (Device Tree)
[   33.052596] Backtrace:
[   33.055143] [<c010c3b8>] (dump_backtrace) from [<c010c5b0>]
(show_stack+0x18/0x1c)
[   33.062831]  r7:00000000[   33.065223]  r6:60000013
 r5:00000000[   33.068891]  r4:c0e2352c
[   33.071484]
[   33.073043] [<c010c598>] (show_stack) from [<c03f7da8>]
(dump_stack+0xb4/0xe8)
[   33.080402] [<c03f7cf4>] (dump_stack) from [<c05b80dc>]
(wl_tree_add+0xb8/0xd0)
[   33.087829]  r9:c0c54860[   33.090215]  r8:cdd62e88
 r7:ce458000[   33.093885]  r6:cddfdcd8
 r5:cddfc82c[   33.097556]  r4:cddfdaf8
[   33.100167] [<c05b8024>] (wl_tree_add) from [<c05b9f68>]
(ubi_wl_init+0x218/0x6d8)
[   33.107860]  r10:c165e66c[   33.110341]  r9:cdd5a90c
 r8:cdd62e88[   33.114010]  r7:00000d27
 r6:cddfdcd8[   33.117681]  r5:cdd62000
[   33.120275]  r4:cddd8cc0[   33.122663]  r3:0000069c
[   33.125254]
[   33.126810] [<c05b9d50>] (ubi_wl_init) from [<c05bd2a0>]
(ubi_attach+0x1fc/0x394)
[   33.134415]  r10:00000001[   33.136889]  r9:cdd5a980
 r8:cdd63000[   33.140557]  r7:cdd5a900
 r6:cdd62000[   33.144228]  r5:00000000
[   33.146822]  r4:cdd68500[   33.149208]
[   33.150770] [<c05bd0a4>] (ubi_attach) from [<c05af73c>]
(ubi_attach_mtd_dev+0x4d8/0xdd0)
[   33.158980]  r10:00000014[   33.161457]  r9:00000800
 r8:00000000[   33.165126]  r7:cdd63000
 r6:cdc97400[   33.168796]  r5:cdd62000
[   33.171391]  r4:fffff800[   33.173779]  r3:00000002
[   33.176370]
[   33.177931] [<c05af264>] (ubi_attach_mtd_dev) from [<c0d46f54>]
(ubi_init+0x1cc/0x28c)
[   33.185969]  r10:c0d00618[   33.188447]  r9:000fffff
 r8:c0e3a9cc[   33.192116]  r7:c0d69370
 r6:c0d69374[   33.195787]  r5:cdc97400
[   33.198380]  r4:00000000[   33.200766]
[   33.202331] [<c0d46d88>] (ubi_init) from [<c010194c>]
(do_one_initcall+0x44/0x180)
[   33.210022]  r10:c0d00618[   33.212494]  r9:00000000
 r8:00000000[   33.216163]  r7:c0d5e854
 r6:c0e72000[   33.219834]  r5:c0d46d88
[   33.222428]  r4:ffffe000[   33.224814]
[   33.226375] [<c0101908>] (do_one_initcall) from [<c0d00e58>]
(kernel_init_freeable+0x128/0x1f0)
[   33.235198]  r8:000000e9[   33.237583]  r7:c0d5e854
 r6:c0e72000[   33.241252]  r5:c0e72000
 r4:00000008[   33.244920]
[   33.246488] [<c0d00d30>] (kernel_init_freeable) from [<c0967908>]
(kernel_init+0x10/0x11c)
[   33.254877]  r10:00000000[   33.257352]  r9:00000000
 r8:00000000[   33.261021]  r7:00000000
 r6:00000000[   33.264692]  r5:c09678f8
[   33.267286]  r4:00000000[   33.269672]
[   33.271238] [<c09678f8>] (kernel_init) from [<c0107e70>]
(ret_from_fork+0x14/0x24)
[   33.278929]  r5:c09678f8[   33.281321]  r4:00000000
[   33.283912]

The system successfully boots in the end (after printing out such traces
for a minute or so). 

This is on a NXP Vybrid using the vf610-nfc driver. The driver is
mainline since some releases now, and I haven't seen such a stack trace
before.

I do use fastmap and a 2015.04 U-Boot to read the kernel/device tree
from a separate volume.

Anybody else seen this?

--
Stefan


From moritz.fischer at ettus.com  Tue Oct 18 12:59:26 2016
From: moritz.fischer at ettus.com (Moritz Fischer)
Date: Tue, 18 Oct 2016 21:59:26 +0200
Subject: [PATCH 1/1] MAINTAINERS: add a maintainer for the SPI NOR
 subsystem
In-Reply-To: <cf010a6c-b642-0994-bbfd-c86d5ab24e6e@nod.at>
References: <0a3eaa21fb0f38743308c9cc9fc5d2373f4877de.1476802288.git.cyrille.pitchen@atmel.com>
 <d4e954c1-0bbb-fc16-4e9a-46c25ec4fb9e@denx.de>
 <CAFLxGvy9okx1cHnRhq2U-u574PzAk=Tampw1Fmvp4KzY8vnDnw@mail.gmail.com>
 <3d45f698-08e9-e672-d405-1ab9bfec1222@atmel.com>
 <cf010a6c-b642-0994-bbfd-c86d5ab24e6e@nod.at>
Message-ID: <CAAtXAHfvVqk4zdQezF5jNiTRY2Ufc-nasWN5rwyF=J63hi6Tsw@mail.gmail.com>

Hi all,

On Tue, Oct 18, 2016 at 6:15 PM, Richard Weinberger <richard at nod.at> wrote:

>> I totally agree with you so if Marek and you volunteer as well, your help
>> will be precious!

I had talked to Richard about helping out during ELCE, but tbh I think
Marek is the better choice ;-)
He has way more experience in that area.
Happy to see things moving in the right direction! If you feel you
need more help one day,
don't hesitate to ping me.

Moritz


From albert.aribaud at 3adev.fr  Tue Oct 18 13:03:34 2016
From: albert.aribaud at 3adev.fr (Albert ARIBAUD)
Date: Tue, 18 Oct 2016 22:03:34 +0200
Subject: [PATCH 2/2] fsl-quadspi: introduce per-bus spi-bus-width property
In-Reply-To: <CAMuHMdW6WJBj3TiXU0mmwKJmcwp28HEVUSD17-7RH7-UXFtX1g@mail.gmail.com>
References: <20160927055957.427-1-albert.aribaud@3adev.fr>
 <20160927055957.427-2-albert.aribaud@3adev.fr>
 <20161003185143.GA27634@rob-hp-laptop>
 <CAMuHMdW6WJBj3TiXU0mmwKJmcwp28HEVUSD17-7RH7-UXFtX1g@mail.gmail.com>
Message-ID: <20161018220334.6452fc5b.albert.aribaud@3adev.fr>

Hi Rob and Geert,

Le Mon, 3 Oct 2016 21:57:58 +0200, Geert Uytterhoeven
<geert at linux-m68k.org> a ?crit :

> On Mon, Oct 3, 2016 at 8:51 PM, Rob Herring <robh at kernel.org> wrote:
> > On Tue, Sep 27, 2016 at 07:59:57AM +0200, Albert ARIBAUD (3ADEV) wrote:  
> >> Introduce spi-bus-width property for bus subnodes, to
> >> specify per-bus capability to use NORMAL, FAST, DUAL,
> >> and/or QUAD reads.
> >>
> >> Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud at 3adev.fr>
> >> ---
> >>  Documentation/devicetree/bindings/mtd/fsl-quadspi.txt | 18 ++++++++++++++++++
> >>  1 file changed, 18 insertions(+)  
> >
> > Make this a common property.  

@Rob: do you mean common to all slaves, i.e. described
in ./Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt?

> They already exist:
> 
> Documentation/devicetree/bindings/spi/spi-bus.txt:
> - spi-tx-bus-width - (optional) The bus width (number of data wires)
> that is used for MOSI. Defaults to 1 if not present.
> - spi-rx-bus-width - (optional) The bus width (number of data wires)
> that is used for MISO. Defaults to 1 if not present.
> 
> The above are for normal/dual/quad.
> 
> "Fast" is not a property of the bus, but of the SPI slave, right? Cfr.
> 
> Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt:
> - m25p,fast-read : Use the "fast read" opcode to read data from the
> chip instead of the usual "read" opcode. This opcode is not supported
> by all chips and support for it can not be detected at runtime.
>                    Refer to your chips' datasheet to check if this is
> supported by your chip.
> 
> Gr{oetje,eeting}s,

@Geert: the problem here is that on the board for which I wrote this
patch, only one of the two NOR slaves can do quad SPI; the other one
can do dual at best. Setting a bus property would prevent the
quad-capable device from doing actual quad reads.

The fsl-quadspi driver already supports per-NOR read and erase commands
to support heterogeneous NOR setups. A per-NOR bus width property would
make sense in this light.

Cordialement,
Albert ARIBAUD
3ADEV


From richard.weinberger at gmail.com  Tue Oct 18 13:09:39 2016
From: richard.weinberger at gmail.com (Richard Weinberger)
Date: Tue, 18 Oct 2016 22:09:39 +0200
Subject: UBI assert failed in wl_tree_add at 168 using v4.9-rc1
In-Reply-To: <5d8e8bc09c75405a783990312dd1dc41@agner.ch>
References: <5d8e8bc09c75405a783990312dd1dc41@agner.ch>
Message-ID: <CAFLxGvxTgNm3H9NvOGVjA9=0yLTdnMQBW9UUFmsX7kLChCeo2A@mail.gmail.com>

Stefan,

On Tue, Oct 18, 2016 at 9:51 PM, Stefan Agner <stefan at agner.ch> wrote:
> Hi All,
>
> After flashing and 2-3 hard resets (power-cut), I happen to get a lot of
> the following stack traces:
>
> [   33.031951] UBI assert failed in wl_tree_add at 168 (pid 1)
> [   33.037763] CPU: 0 PID: 1 Comm: swapper/0 Not tainted
> 4.9.0-rc1-00001-g4b1532a-dirty #568
> [   33.046071] Hardware name: Freescale Vybrid VF5xx/VF6xx (Device Tree)
> [   33.052596] Backtrace:
> [   33.055143] [<c010c3b8>] (dump_backtrace) from [<c010c5b0>]
> (show_stack+0x18/0x1c)
> [   33.062831]  r7:00000000[   33.065223]  r6:60000013
>  r5:00000000[   33.068891]  r4:c0e2352c
> [   33.071484]
> [   33.073043] [<c010c598>] (show_stack) from [<c03f7da8>]
> (dump_stack+0xb4/0xe8)
> [   33.080402] [<c03f7cf4>] (dump_stack) from [<c05b80dc>]
> (wl_tree_add+0xb8/0xd0)
> [   33.087829]  r9:c0c54860[   33.090215]  r8:cdd62e88
>  r7:ce458000[   33.093885]  r6:cddfdcd8
>  r5:cddfc82c[   33.097556]  r4:cddfdaf8
> [   33.100167] [<c05b8024>] (wl_tree_add) from [<c05b9f68>]
> (ubi_wl_init+0x218/0x6d8)
> [   33.107860]  r10:c165e66c[   33.110341]  r9:cdd5a90c
>  r8:cdd62e88[   33.114010]  r7:00000d27
>  r6:cddfdcd8[   33.117681]  r5:cdd62000
> [   33.120275]  r4:cddd8cc0[   33.122663]  r3:0000069c
> [   33.125254]
> [   33.126810] [<c05b9d50>] (ubi_wl_init) from [<c05bd2a0>]
> (ubi_attach+0x1fc/0x394)
> [   33.134415]  r10:00000001[   33.136889]  r9:cdd5a980
>  r8:cdd63000[   33.140557]  r7:cdd5a900
>  r6:cdd62000[   33.144228]  r5:00000000
> [   33.146822]  r4:cdd68500[   33.149208]
> [   33.150770] [<c05bd0a4>] (ubi_attach) from [<c05af73c>]
> (ubi_attach_mtd_dev+0x4d8/0xdd0)
> [   33.158980]  r10:00000014[   33.161457]  r9:00000800
>  r8:00000000[   33.165126]  r7:cdd63000
>  r6:cdc97400[   33.168796]  r5:cdd62000
> [   33.171391]  r4:fffff800[   33.173779]  r3:00000002
> [   33.176370]
> [   33.177931] [<c05af264>] (ubi_attach_mtd_dev) from [<c0d46f54>]
> (ubi_init+0x1cc/0x28c)
> [   33.185969]  r10:c0d00618[   33.188447]  r9:000fffff
>  r8:c0e3a9cc[   33.192116]  r7:c0d69370
>  r6:c0d69374[   33.195787]  r5:cdc97400
> [   33.198380]  r4:00000000[   33.200766]
> [   33.202331] [<c0d46d88>] (ubi_init) from [<c010194c>]
> (do_one_initcall+0x44/0x180)
> [   33.210022]  r10:c0d00618[   33.212494]  r9:00000000
>  r8:00000000[   33.216163]  r7:c0d5e854
>  r6:c0e72000[   33.219834]  r5:c0d46d88
> [   33.222428]  r4:ffffe000[   33.224814]
> [   33.226375] [<c0101908>] (do_one_initcall) from [<c0d00e58>]
> (kernel_init_freeable+0x128/0x1f0)
> [   33.235198]  r8:000000e9[   33.237583]  r7:c0d5e854
>  r6:c0e72000[   33.241252]  r5:c0e72000
>  r4:00000008[   33.244920]
> [   33.246488] [<c0d00d30>] (kernel_init_freeable) from [<c0967908>]
> (kernel_init+0x10/0x11c)
> [   33.254877]  r10:00000000[   33.257352]  r9:00000000
>  r8:00000000[   33.261021]  r7:00000000
>  r6:00000000[   33.264692]  r5:c09678f8
> [   33.267286]  r4:00000000[   33.269672]
> [   33.271238] [<c09678f8>] (kernel_init) from [<c0107e70>]
> (ret_from_fork+0x14/0x24)
> [   33.278929]  r5:c09678f8[   33.281321]  r4:00000000
> [   33.283912]
>
> The system successfully boots in the end (after printing out such traces
> for a minute or so).
>
> This is on a NXP Vybrid using the vf610-nfc driver. The driver is
> mainline since some releases now, and I haven't seen such a stack trace
> before.
>
> I do use fastmap and a 2015.04 U-Boot to read the kernel/device tree
> from a separate volume.
>
> Anybody else seen this?

Does this patch help?
http://lists.infradead.org/pipermail/linux-mtd/2016-October/069702.html

I'm assuming that the problem first appeared in v4.9-rc1, right?

-- 
Thanks,
//richard


From boris.brezillon at free-electrons.com  Tue Oct 18 13:17:44 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Tue, 18 Oct 2016 22:17:44 +0200
Subject: [RFC PATCH] mtd: nand: Add OX820 NAND Support
In-Reply-To: <20161018090927.1990-1-narmstrong@baylibre.com>
References: <20161018090927.1990-1-narmstrong@baylibre.com>
Message-ID: <20161018221744.5e574e82@bbrezillon>

Hi Neil,

On Tue, 18 Oct 2016 11:09:27 +0200
Neil Armstrong <narmstrong at baylibre.com> wrote:

> Add NAND driver to support the Oxford Semiconductor OX820 NAND Controller.
> This is a simple memory mapped NAND controller with single chip select and
> software ECC.
> 
> Signed-off-by: Neil Armstrong <narmstrong at baylibre.com>
> ---
>  .../devicetree/bindings/mtd/oxnas-nand.txt         |  24 ++++
>  drivers/mtd/nand/Kconfig                           |   5 +
>  drivers/mtd/nand/Makefile                          |   1 +
>  drivers/mtd/nand/oxnas_nand.c                      | 144 +++++++++++++++++++++
>  4 files changed, 174 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mtd/oxnas-nand.txt
>  create mode 100644 drivers/mtd/nand/oxnas_nand.c
> 
> diff --git a/Documentation/devicetree/bindings/mtd/oxnas-nand.txt b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
> new file mode 100644
> index 0000000..83b684d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
> @@ -0,0 +1,24 @@
> +* Oxford Semiconductor OXNAS NAND Controller
> +
> +Please refer to nand.txt for generic information regarding MTD NAND bindings.
> +
> +Required properties:
> + - compatible: "oxsemi,ox820-nand"
> + - reg: Base address and length for NAND mapped memory.
> +
> +Optional Properties:
> + - clocks: phandle to the NAND gate clock if needed.
> + - resets: phandle to the NAND reset control if needed.
> +
> +Example:
> +
> +nand: nand at 41000000 {
> +	compatible = "oxsemi,ox820-nand";
> +	reg = <0x41000000 0x100000>;
> +	nand-ecc-mode = "soft";
> +	clocks = <&stdclk CLK_820_NAND>;
> +	resets = <&reset RESET_NAND>;
> +	#address-cells = <1>;
> +	#size-cells = <1>;
> +	status = "disabled";
> +};

Can you switch to new DT representation for NAND controllers, with one
node for the NAND controller and NAND devices connected to this NAND
controller defined as sub-nodes of this NAND controller [1]?

> diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
> index 7b7a887..c023125 100644
> --- a/drivers/mtd/nand/Kconfig
> +++ b/drivers/mtd/nand/Kconfig
> @@ -426,6 +426,11 @@ config MTD_NAND_ORION
>  	  No board specific support is done by this driver, each board
>  	  must advertise a platform_device for the driver to attach.
>  
> +config MTD_NAND_OXNAS
> +	tristate "NAND Flash support for Oxford Semiconductor SoC"
> +	help
> +	  This enables the NAND flash controller on Oxford Semiconductor SoCs.
> +
>  config MTD_NAND_FSL_ELBC
>  	tristate "NAND support for Freescale eLBC controllers"
>  	depends on FSL_SOC
> diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
> index cafde6f..05fc054 100644
> --- a/drivers/mtd/nand/Makefile
> +++ b/drivers/mtd/nand/Makefile
> @@ -35,6 +35,7 @@ obj-$(CONFIG_MTD_NAND_TMIO)		+= tmio_nand.o
>  obj-$(CONFIG_MTD_NAND_PLATFORM)		+= plat_nand.o
>  obj-$(CONFIG_MTD_NAND_PASEMI)		+= pasemi_nand.o
>  obj-$(CONFIG_MTD_NAND_ORION)		+= orion_nand.o
> +obj-$(CONFIG_MTD_NAND_OXNAS)		+= oxnas_nand.o
>  obj-$(CONFIG_MTD_NAND_FSL_ELBC)		+= fsl_elbc_nand.o
>  obj-$(CONFIG_MTD_NAND_FSL_IFC)		+= fsl_ifc_nand.o
>  obj-$(CONFIG_MTD_NAND_FSL_UPM)		+= fsl_upm.o
> diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/oxnas_nand.c
> new file mode 100644
> index 0000000..ee402ab
> --- /dev/null
> +++ b/drivers/mtd/nand/oxnas_nand.c
> @@ -0,0 +1,144 @@
> +/*
> + * Oxford Semiconductor OXNAS NAND driver
> + *
> + * Heavily based on plat_nand.c :
> + * Author: Vitaly Wool <vitalywool at gmail.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/clk.h>
> +#include <linux/reset.h>
> +#include <linux/mtd/mtd.h>
> +#include <linux/mtd/nand.h>
> +#include <linux/mtd/partitions.h>
> +
> +/* nand commands */
> +#define NAND_CMD_ALE		BIT(18)
> +#define NAND_CMD_CLE		BIT(19)
> +#define NAND_CMD_CS		0

I guess this is zero here because you only support connecting a NAND to
CS0.
It's probably something like

OX820_NAND_CS(x)		((x) << CS_FIELD_SHIFT)

> +#define NAND_CMD_RESET		0xff

Why do you have to redefine it? it's already defined here [2].

> +#define NAND_CMD		(NAND_CMD_CS | NAND_CMD_CLE)
> +#define NAND_ADDR		(NAND_CMD_CS | NAND_CMD_ALE)
> +#define NAND_DATA		(NAND_CMD_CS)

Please prefix those macros with OX820, has stated above, this can
conflict with generic definitions.
Also, I'm not sure you should pass the CS information here.

> +
> +struct oxnas_nand_data {
> +	struct nand_chip	chip;
> +	void __iomem		*io_base;
> +	struct clk		*clk;
> +};

Even if your driver does not seem to support connecting several chips
to the same controller, I'd like you to clearly separate the NAND
controller and NAND chip objects:

#define OXNAS_NAND_MAX_CHIPS	1

struct oxnas_nand_controller {
	struct nand_hw_control base;
	void __iomem *io_base;
	struct clk *clk;
	struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS];
}

> +
> +static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
> +				unsigned int ctrl)
> +{
> +	struct nand_chip *this = mtd->priv;
> +	unsigned long nandaddr = (unsigned long) this->IO_ADDR_W;

Please use the ->io_base field directly, and do not use ->IO_ADDR_W/R
(I'd like to get rid of them at some point).

Also, declare the nandaddr as a void __iomem *, and use the '+'
operator instead of '|'.

> +
> +	if (ctrl & NAND_CTRL_CHANGE) {
> +		nandaddr &= ~(NAND_CMD | NAND_ADDR);

This is not needed.

> +		if (ctrl & NAND_CLE)
> +			nandaddr |= NAND_CMD;
> +		else if (ctrl & NAND_ALE)
> +			nandaddr |= NAND_ADDR;
> +		this->IO_ADDR_W = (void __iomem *) nandaddr;

This is not needed, is it?

> +	}
> +
> +	if (cmd != NAND_CMD_NONE)
> +		writeb(cmd, (void __iomem *) nandaddr);
> +}
> +
> +/*
> + * Probe for the NAND device.
> + */
> +static int oxnas_nand_probe(struct platform_device *pdev)
> +{
> +	struct oxnas_nand_data *data;
> +	struct mtd_info *mtd;
> +	struct resource *res;
> +	int err = 0;
> +
> +	/* Allocate memory for the device structure (and zero it) */
> +	data = devm_kzalloc(&pdev->dev, sizeof(struct oxnas_nand_data),
> +			    GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	data->io_base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(data->io_base))
> +		return PTR_ERR(data->io_base);
> +
> +	data->clk = devm_clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(data->clk))
> +		data->clk = NULL;
> +
> +	nand_set_flash_node(&data->chip, pdev->dev.of_node);
> +	mtd = nand_to_mtd(&data->chip);
> +	mtd->dev.parent = &pdev->dev;
> +	mtd->priv = &data->chip;
> +
> +	data->chip.IO_ADDR_R = data->io_base;
> +	data->chip.IO_ADDR_W = data->io_base;

As I said above, don't use these fields.

> +	data->chip.cmd_ctrl = oxnas_nand_cmd_ctrl;
> +	data->chip.chip_delay = 30;
> +	data->chip.ecc.mode = NAND_ECC_SOFT;
> +	data->chip.ecc.algo = NAND_ECC_HAMMING;

Probably a good idea to support soft ECC as well...

> +
> +	platform_set_drvdata(pdev, data);
> +
> +	clk_prepare_enable(data->clk);
> +	device_reset_optional(&pdev->dev);
> +
> +	/* Scan to find existence of the device */
> +	if (nand_scan(mtd, 1)) {

Why not returning nand_scan() error code?

> +		err = -ENXIO;
> +		goto out;

Return directly here.

> +	}
> +
> +	err = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);

Use mtd_device_register() here.

> +	if (!err)
> +		return err;
> +
> +	nand_release(mtd);

Why not

	if (err)
		nand_release(mtd);

> +out:

Drop this label.

> +	return err;
> +}
> +
> +static int oxnas_nand_remove(struct platform_device *pdev)
> +{
> +	struct oxnas_nand_data *data = platform_get_drvdata(pdev);
> +
> +	nand_release(nand_to_mtd(&data->chip));
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id oxnas_nand_match[] = {
> +	{ .compatible = "oxsemi,ox820-nand" },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, oxnas_nand_match);
> +
> +static struct platform_driver oxnas_nand_driver = {
> +	.probe	= oxnas_nand_probe,
> +	.remove	= oxnas_nand_remove,
> +	.driver	= {
> +		.name		= "oxnas_nand",
> +		.of_match_table = oxnas_nand_match,
> +	},
> +};
> +
> +module_platform_driver(oxnas_nand_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Vitaly Wool");
> +MODULE_DESCRIPTION("Oxnas NAND driver");
> +MODULE_ALIAS("platform:oxnas_nand");

Thanks,

Boris

[1]https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/mtd/nand.txt?id=refs/tags/v4.9-rc1#n57
[2]http://lxr.free-electrons.com/source/include/linux/mtd/nand.h#L90


From richard at nod.at  Tue Oct 18 13:18:20 2016
From: richard at nod.at (Richard Weinberger)
Date: Tue, 18 Oct 2016 22:18:20 +0200
Subject: [PATCH 1/1] MAINTAINERS: add a maintainer for the SPI NOR
 subsystem
In-Reply-To: <CAAtXAHfvVqk4zdQezF5jNiTRY2Ufc-nasWN5rwyF=J63hi6Tsw@mail.gmail.com>
References: <0a3eaa21fb0f38743308c9cc9fc5d2373f4877de.1476802288.git.cyrille.pitchen@atmel.com>
 <d4e954c1-0bbb-fc16-4e9a-46c25ec4fb9e@denx.de>
 <CAFLxGvy9okx1cHnRhq2U-u574PzAk=Tampw1Fmvp4KzY8vnDnw@mail.gmail.com>
 <3d45f698-08e9-e672-d405-1ab9bfec1222@atmel.com>
 <cf010a6c-b642-0994-bbfd-c86d5ab24e6e@nod.at>
 <CAAtXAHfvVqk4zdQezF5jNiTRY2Ufc-nasWN5rwyF=J63hi6Tsw@mail.gmail.com>
Message-ID: <c8791e1e-cb96-732f-1a42-eecd2fd6e3de@nod.at>

On 18.10.2016 21:59, Moritz Fischer wrote:
> Hi all,
> 
> On Tue, Oct 18, 2016 at 6:15 PM, Richard Weinberger <richard at nod.at> wrote:
> 
>>> I totally agree with you so if Marek and you volunteer as well, your help
>>> will be precious!
> 
> I had talked to Richard about helping out during ELCE, but tbh I think
> Marek is the better choice ;-)
> He has way more experience in that area.
> Happy to see things moving in the right direction! If you feel you
> need more help one day,
> don't hesitate to ping me.

This does not mean that you can't help.
Please have a look at incoming patches and review them.

Thanks,
//richard


From richard at nod.at  Tue Oct 18 13:46:30 2016
From: richard at nod.at (Richard Weinberger)
Date: Tue, 18 Oct 2016 22:46:30 +0200
Subject: [PATCH] ubifs: Fix xattr_names length in exit paths
Message-ID: <1476823591-6137-1-git-send-email-richard@nod.at>

When the operation fails we also have to undo the changes
we made to ->xattr_names. Otherwise listxattr() will report
wrong lengths.

Cc: stable at vger.kernel.org
Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/ubifs/xattr.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c
index 6c2f4d41ed73..d9f9615bfd71 100644
--- a/fs/ubifs/xattr.c
+++ b/fs/ubifs/xattr.c
@@ -172,6 +172,7 @@ static int create_xattr(struct ubifs_info *c, struct inode *host,
 	host_ui->xattr_cnt -= 1;
 	host_ui->xattr_size -= CALC_DENT_SIZE(nm->len);
 	host_ui->xattr_size -= CALC_XATTR_BYTES(size);
+	host_ui->xattr_names -= nm->len;
 	mutex_unlock(&host_ui->ui_mutex);
 out_free:
 	make_bad_inode(inode);
@@ -478,6 +479,7 @@ static int remove_xattr(struct ubifs_info *c, struct inode *host,
 	host_ui->xattr_cnt += 1;
 	host_ui->xattr_size += CALC_DENT_SIZE(nm->len);
 	host_ui->xattr_size += CALC_XATTR_BYTES(ui->data_len);
+	host_ui->xattr_names += nm->len;
 	mutex_unlock(&host_ui->ui_mutex);
 	ubifs_release_budget(c, &req);
 	make_bad_inode(inode);
-- 
2.7.3



From richard at nod.at  Tue Oct 18 13:46:31 2016
From: richard at nod.at (Richard Weinberger)
Date: Tue, 18 Oct 2016 22:46:31 +0200
Subject: [PATCH] ubifs: Rename ubifs_rename2
In-Reply-To: <1476823591-6137-1-git-send-email-richard@nod.at>
References: <1476823591-6137-1-git-send-email-richard@nod.at>
Message-ID: <1476823591-6137-2-git-send-email-richard@nod.at>

Since ->rename2 is gone, rename ubifs_rename2() to ubifs_rename().

Suggested-by: Linus Torvalds <torvalds at linux-foundation.org>
Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/ubifs/dir.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index c8f60df2733e..668ec3b90ea1 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -1060,9 +1060,9 @@ static void unlock_4_inodes(struct inode *inode1, struct inode *inode2,
 	mutex_unlock(&ubifs_inode(inode1)->ui_mutex);
 }
 
-static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
-			struct inode *new_dir, struct dentry *new_dentry,
-			unsigned int flags)
+static int do_rename(struct inode *old_dir, struct dentry *old_dentry,
+		     struct inode *new_dir, struct dentry *new_dentry,
+		     unsigned int flags)
 {
 	struct ubifs_info *c = old_dir->i_sb->s_fs_info;
 	struct inode *old_inode = d_inode(old_dentry);
@@ -1323,7 +1323,7 @@ static int ubifs_xrename(struct inode *old_dir, struct dentry *old_dentry,
 	return err;
 }
 
-static int ubifs_rename2(struct inode *old_dir, struct dentry *old_dentry,
+static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
 			struct inode *new_dir, struct dentry *new_dentry,
 			unsigned int flags)
 {
@@ -1336,7 +1336,7 @@ static int ubifs_rename2(struct inode *old_dir, struct dentry *old_dentry,
 	if (flags & RENAME_EXCHANGE)
 		return ubifs_xrename(old_dir, old_dentry, new_dir, new_dentry);
 
-	return ubifs_rename(old_dir, old_dentry, new_dir, new_dentry, flags);
+	return do_rename(old_dir, old_dentry, new_dir, new_dentry, flags);
 }
 
 int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
@@ -1387,7 +1387,7 @@ const struct inode_operations ubifs_dir_inode_operations = {
 	.mkdir       = ubifs_mkdir,
 	.rmdir       = ubifs_rmdir,
 	.mknod       = ubifs_mknod,
-	.rename      = ubifs_rename2,
+	.rename      = ubifs_rename,
 	.setattr     = ubifs_setattr,
 	.getattr     = ubifs_getattr,
 	.listxattr   = ubifs_listxattr,
-- 
2.7.3



From david.oberhollenzer at sigma-star.at  Tue Oct 18 14:10:06 2016
From: david.oberhollenzer at sigma-star.at (David Oberhollenzer)
Date: Tue, 18 Oct 2016 23:10:06 +0200
Subject: [PATCH 1/1] MAINTAINERS: add a maintainer for the SPI NOR
 subsystem
In-Reply-To: <20161018211548.08dded8a@bbrezillon>
References: <0a3eaa21fb0f38743308c9cc9fc5d2373f4877de.1476802288.git.cyrille.pitchen@atmel.com>
 <d4e954c1-0bbb-fc16-4e9a-46c25ec4fb9e@denx.de>
 <CAFLxGvy9okx1cHnRhq2U-u574PzAk=Tampw1Fmvp4KzY8vnDnw@mail.gmail.com>
 <3d45f698-08e9-e672-d405-1ab9bfec1222@atmel.com>
 <cf010a6c-b642-0994-bbfd-c86d5ab24e6e@nod.at>
 <20161018184651.GA71760@google.com> <20161018211548.08dded8a@bbrezillon>
Message-ID: <1072e553-202a-70c9-3f3c-815dbdac823d@sigma-star.at>

On 10/18/2016 09:15 PM, Boris Brezillon wrote:
> On Tue, 18 Oct 2016 11:46:51 -0700
> Brian Norris <computersforpeace at gmail.com> wrote:
> 
>> + others
>>
>> On Tue, Oct 18, 2016 at 06:15:23PM +0200, Richard Weinberger wrote:
>>> On 18.10.2016 17:55, Cyrille Pitchen wrote:  
>>>> Le 18/10/2016 ? 17:30, Richard Weinberger a ?crit :  
>>>>> On Tue, Oct 18, 2016 at 5:17 PM, Marek Vasut <marex at denx.de> wrote:  
>>>>>> On 10/18/2016 04:58 PM, Cyrille Pitchen wrote:  
>>>>>>> I would like to volunteer as a maintainer for the SPI NOR part of the MTD
>>>>>>> subsystem.  
>>
>> Awesome!
>>
>>>>>>> Over the last months, a significant number of SPI NOR related patches have
>>>>>>> been submitted, some of them have been reviewed, but very few have finally
>>>>>>> been merged. Hence, the number of pending SPI NOR related patches continues
>>>>>>> to increase over the time.  
>>
>> Agreed, and sorry. But I guess the delays had the side effect of forcing
>> peoples hands, instead of delaying the inevitable.
>>
>>>>>>> Through my work on SPI NOR memories from many manufacturers over the last
>>>>>>> two years, I've gained a solid understanding of this technology.
>>>>>>> I've already helped by reviewing patches from other contributors on the
>>>>>>> mailing list, and would like to help getting those patches integrated by
>>>>>>> volunteering as a maintainer for this specific area.  
>>
>> Agreed.
>>
>>>>>>> Boris Brezillon has already stepped up as a maintainer for the NAND
>>>>>>> sub-subsystem in MTD, and the SPI NOR sub-subsystem could be handled in
>>>>>>> the same way: I would be reviewing patches touching this area, collecting
>>>>>>> them and sending pull requests to Brian Norris.  
>>>>>
>>>>> I'd suggest you send pull requests directly to Linus.
>>>>> Same for NAND.  
>>
>> I could go with either method I suppose, but I don't personally like the
>> idea of splitting out the various bits of MTD into *completely*
>> independent lines of development. As long as someone (not necessarily
>> me) can manage pulling the sub-subsystems together, I think it would
>> make sense to have 1 PR for Linus for non-UBI/FS MTD changes.
>>
>>>>>>> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>  
>>>>>>
>>>>>> Let me know if you need co-maintainer.  
>>>>>
>>>>> +1  
>>
>> +1, I think I've not-so-subtly suggested this to Marek previously.
> 
> Okay, that's all great news!
> You can add my ack after adding Marek as a co-maintainer.
> 
>>
>>>>> While we are here, what about forming a MTD maintainer team?
>>>>> This concept works very well for other subsystems.
>>>>>  
>>>>
>>>> I totally agree with you so if Marek and you volunteer as well, your help
>>>> will be precious!  
>>>
>>> Well, my SPI-NOR fu is not strong. And UBI/UBIFS keeps me busy.
>>> But if Brian likes the idea of having a MTD maintainer team I'll offer my help.  
>>
>> I think a MTD maintainer team would be good to try, and I think it might
>> help to resolve my above complaint; a maintainer team could help to make
>> sure that everything can be coordinated in one tree + pull request,
>> without adding too many extra points of failure (e.g., so we don't have
>> awesome SPI NOR and NAND trees get bogged down by a slow MTD pull).
>>
>> Random thoughts:
>>
>>  Does it make sense to still use infradead.org? We'd need to add a few
>>  users there.
>>
>>  Trust? I have met most of you in person, but not all, and I don't have
>>  signed keys from all of you. I don't know what the best way to get a
>>  group-writeable repo with credentials for all of you that we can trust.
>>  (FWIW, neither Artem nor David met me, but they saw it fit to grant me
>>  infradead.org access ;) )
>>
>>  Coordination: how do we avoid stepping on each other's toes? We'd have
>>  to definitely 100% kill 'git push -f' and 'git rebase'. Also, would
>>  patchwork help or hurt us here? I think Boris and I have been sort of
>>  using it, but it's still got a pretty good backlog (partly real --
>>  i.e., the cause for this thread; and partly artificial, due to
>>  accounting).
> 
> I really think we should keep separate trees for the spi-nor and nand
> sub-subsystems, and then do PRs. The question is, how do we agree that
> a PR should be pulled in the MTD tree.
> 
> I guess we could have a simple rule like, if it's been reviewed by at
> least X person (I guess 2 is acceptable), then we can merge it.
> 
>>
>>  What to do about mtd-utils.git? That's been languishing a bit, and it
>>  has no release schedule. Maybe we want a plan for that too.
> 
> Richard and David had some plans for the mtd-utils repo, and I think
> they already have the permissions to push things to this repo, so the
> best solution is probably to officially promote them maintainers of
> mtd-utils.
I would volunteer to maintain it together with Richard.

As has been previously mentioned, we did a major overhaul and merged lots
of fixes locally. AFAIK Richard already has push permissions for the mtd-utils
tree on infradead.org, so it should be just a matter of making it official?


David



From stefan at agner.ch  Tue Oct 18 14:26:14 2016
From: stefan at agner.ch (Stefan Agner)
Date: Tue, 18 Oct 2016 14:26:14 -0700
Subject: UBI assert failed in wl_tree_add at 168 using v4.9-rc1
In-Reply-To: <CAFLxGvxTgNm3H9NvOGVjA9=0yLTdnMQBW9UUFmsX7kLChCeo2A@mail.gmail.com>
References: <5d8e8bc09c75405a783990312dd1dc41@agner.ch>
 <CAFLxGvxTgNm3H9NvOGVjA9=0yLTdnMQBW9UUFmsX7kLChCeo2A@mail.gmail.com>
Message-ID: <54fa9ba04ec7310bdc520bb8db943de2@agner.ch>

Hi Richard,

On 2016-10-18 13:09, Richard Weinberger wrote:
> Stefan,
> 
> On Tue, Oct 18, 2016 at 9:51 PM, Stefan Agner <stefan at agner.ch> wrote:
>> Hi All,
>>
>> After flashing and 2-3 hard resets (power-cut), I happen to get a lot of
>> the following stack traces:
>>
>> [   33.031951] UBI assert failed in wl_tree_add at 168 (pid 1)
<snip>
>>
>> The system successfully boots in the end (after printing out such traces
>> for a minute or so).
>>
>> This is on a NXP Vybrid using the vf610-nfc driver. The driver is
>> mainline since some releases now, and I haven't seen such a stack trace
>> before.
>>
>> I do use fastmap and a 2015.04 U-Boot to read the kernel/device tree
>> from a separate volume.
>>
>> Anybody else seen this?
> 
> Does this patch help?
> http://lists.infradead.org/pipermail/linux-mtd/2016-October/069702.html
> 
> I'm assuming that the problem first appeared in v4.9-rc1, right?

I've never seen it before, so yes looks like it appeared in v4.9-rc1.

I rebooted and power-cycled a bunch of times with that patch, it looks
stable now! So yes, the patch helps. I will do some more tests and
report in case I see it again.

Thanks!

--
Stefan


From richard at nod.at  Tue Oct 18 14:32:23 2016
From: richard at nod.at (Richard Weinberger)
Date: Tue, 18 Oct 2016 23:32:23 +0200
Subject: [PATCH] ubifs: implement POSIX Access Control Lists (ACLs)
In-Reply-To: <1476046382-19185-1-git-send-email-pascal.eberhard@gmail.com>
References: <1476046382-19185-1-git-send-email-pascal.eberhard@gmail.com>
Message-ID: <443b11a2-729a-32ec-0a6f-5a3276290329@nod.at>

Pascal,

On 09.10.2016 22:53, Pascal Eberhard wrote:
> This patch implements POSIX Access Control Lists (ACLs) in UBIFS.
> It uses posix_acl_(access|default)_xattr_handler ACL generic handlers
> as xattr handlers are now used in UBIFS.

Cool! :)
CC'ing Andreas, maybe he also has comments.

> Signed-off-by: Pascal Eberhard <pascal.eberhard at gmail.com>
> ---
>  fs/ubifs/Kconfig  |  13 +++++
>  fs/ubifs/Makefile |   1 +
>  fs/ubifs/acl.c    | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  fs/ubifs/dir.c    |  22 +++++++++
>  fs/ubifs/file.c   |   9 ++++
>  fs/ubifs/super.c  |  15 ++++++
>  fs/ubifs/ubifs.h  |  18 +++++++
>  fs/ubifs/xattr.c  |  11 +++--
>  8 files changed, 229 insertions(+), 3 deletions(-)
>  create mode 100644 fs/ubifs/acl.c
> 
> diff --git a/fs/ubifs/Kconfig b/fs/ubifs/Kconfig
> index 7ff7712..39119e5 100644
> --- a/fs/ubifs/Kconfig
> +++ b/fs/ubifs/Kconfig
> @@ -50,3 +50,16 @@ config UBIFS_ATIME_SUPPORT
>  	  strictatime is the "heavy", relatime is "lighter", etc.
>  
>  	  If unsure, say 'N'
> +
> +config UBIFS_FS_POSIX_ACL
> +	bool "UBIFS POSIX Access Control Lists"
> +	depends on UBIFS_FS
> +	select FS_POSIX_ACL
> +	help
> +	  POSIX Access Control Lists (ACLs) support permissions for users and
> +	  groups beyond the owner/group/world scheme.
> +
> +	  To learn more about Access Control Lists, visit the POSIX ACLs for
> +	  Linux website <http://acl.bestbits.at/>.
> +
> +	  If you don't know what Access Control Lists are, say N
> diff --git a/fs/ubifs/Makefile b/fs/ubifs/Makefile
> index c54a243..af7a83f 100644
> --- a/fs/ubifs/Makefile
> +++ b/fs/ubifs/Makefile
> @@ -5,3 +5,4 @@ ubifs-y += tnc.o master.o scan.o replay.o log.o commit.o gc.o orphan.o
>  ubifs-y += budget.o find.o tnc_commit.o compress.o lpt.o lprops.o
>  ubifs-y += recovery.o ioctl.o lpt_commit.o tnc_misc.o xattr.o debug.o
>  ubifs-y += misc.o
> +ubifs-$(CONFIG_UBIFS_FS_POSIX_ACL) += acl.o
> \ No newline at end of file
> diff --git a/fs/ubifs/acl.c b/fs/ubifs/acl.c
> new file mode 100644
> index 0000000..a4d4734
> --- /dev/null
> +++ b/fs/ubifs/acl.c
> @@ -0,0 +1,143 @@
> +/*
> + * This file is part of UBIFS.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published by
> + * the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + */
> +
> +#include <linux/fs.h>

ubifs.h includes this already.

> +#include <linux/xattr.h>

Ditto.

> +#include <linux/posix_acl_xattr.h>
> +
> +#include "ubifs.h"
> +
> +struct posix_acl *ubifs_get_acl(struct inode *inode, int type)
> +{
> +	int size;
> +	const char *name;
> +	char *value = NULL;
> +	struct posix_acl *acl;
> +
> +	switch (type) {
> +	case ACL_TYPE_ACCESS:
> +		name = XATTR_NAME_POSIX_ACL_ACCESS;
> +		break;
> +	case ACL_TYPE_DEFAULT:
> +		name = XATTR_NAME_POSIX_ACL_DEFAULT;
> +		break;
> +	default:
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	size = __ubifs_getxattr(inode, name, NULL, 0);
> +	if (size > 0) {
> +		value = kzalloc(size, GFP_KERNEL);
> +		if (!value)
> +			return ERR_PTR(-ENOMEM);
> +		size = __ubifs_getxattr(inode, name, value, size);
> +	}
> +	if (size > 0)
> +		acl = posix_acl_from_xattr(&init_user_ns, value, size);
> +	else if (size == -ERANGE || size == -ENODATA || size == 0)
> +		acl = NULL;
> +	else
> +		acl = ERR_PTR(size);
> +
> +	kfree(value);
> +	if (!IS_ERR(acl))
> +		set_cached_acl(inode, type, acl);
> +
> +	return acl;
> +}
> +
> +int ubifs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
> +{
> +	int ret;
> +	int size = 0;
> +	const char *name;
> +	char *value = NULL;
> +	int flags = 0;
> +
> +	switch (type) {
> +	case ACL_TYPE_ACCESS:
> +		name = XATTR_NAME_POSIX_ACL_ACCESS;
> +		if (acl) {
> +			ret = posix_acl_equiv_mode(acl, &inode->i_mode);
> +			if (ret < 0)
> +				return ret;
> +			if (ret == 0)
> +				acl = NULL;
> +		}
> +		ret = 0;
> +		break;
> +	case ACL_TYPE_DEFAULT:
> +		if (!S_ISDIR(inode->i_mode))
> +			return acl ? -EINVAL : 0;
> +		name = XATTR_NAME_POSIX_ACL_DEFAULT;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	if (acl) {
> +		size = posix_acl_xattr_size(acl->a_count);
> +		value = kmalloc(size, GFP_KERNEL);
> +		if (!value)
> +			return -ENOMEM;
> +
> +		ret = posix_acl_to_xattr(&init_user_ns, acl, value, size);
> +		if (ret < 0)
> +			goto out;
> +	}
> +
> +	if (size == 0)
> +		flags = XATTR_REPLACE;
> +	ret = __ubifs_setxattr(inode, name, value, size, flags);
> +
> +out:
> +	kfree(value);
> +	if (!ret)
> +		set_cached_acl(inode, type, acl);
> +
> +	return ret;
> +}
> +
> +/*
> + * Initialize the ACLs of a new inode.

Please use the Javadoc style we use for all UBIFS functions.
(applies to other functions too in this patch)-

> + */
> +int ubifs_init_acl(struct inode *dir, struct inode *inode)
> +{
> +	struct posix_acl *default_acl, *acl;
> +	int ret = 0;
> +
> +	ret = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
> +	if (ret)
> +		return ret;
> +
> +	if (default_acl) {
> +		inode_lock(inode);
> +		ret = ubifs_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
> +		inode_unlock(inode);
> +		posix_acl_release(default_acl);
> +	}
> +
> +	if (acl) {
> +		if (!ret) {
> +			inode_lock(inode);
> +			ret = ubifs_set_acl(inode, acl, ACL_TYPE_ACCESS);
> +			inode_unlock(inode);
> +		}
> +		posix_acl_release(acl);
> +	}
> +
> +	if (!default_acl && !acl)
> +		cache_no_acl(inode);
> +	return ret;
> +}
> diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
> index ccd9128..a2e5609 100644
> --- a/fs/ubifs/dir.c
> +++ b/fs/ubifs/dir.c
> @@ -270,6 +270,10 @@ static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
>  		goto out_budg;
>  	}
>  
> +	err = ubifs_init_acl(dir, inode);
> +	if (err)
> +		goto out_inode;
> +
>  	err = ubifs_init_security(dir, inode, &dentry->d_name);
>  	if (err)
>  		goto out_inode;
> @@ -341,6 +345,10 @@ static int do_tmpfile(struct inode *dir, struct dentry *dentry,
>  		ubifs_assert(inode->i_op == &ubifs_file_inode_operations);
>  	}
>  
> +	err = ubifs_init_acl(dir, inode);
> +	if (err)
> +		goto out_inode;

Why do we need ACLs for O_TMPFILE?

> +
>  	err = ubifs_init_security(dir, inode, &dentry->d_name);
>  	if (err)
>  		goto out_inode;
> @@ -821,6 +829,10 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
>  		goto out_budg;
>  	}
>  
> +	err = ubifs_init_acl(dir, inode);
> +	if (err)
> +		goto out_inode;
> +
>  	err = ubifs_init_security(dir, inode, &dentry->d_name);
>  	if (err)
>  		goto out_inode;
> @@ -903,6 +915,10 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
>  	ui->data = dev;
>  	ui->data_len = devlen;
>  
> +	err = ubifs_init_acl(dir, inode);
> +	if (err)
> +		goto out_inode;
> +
>  	err = ubifs_init_security(dir, inode, &dentry->d_name);
>  	if (err)
>  		goto out_inode;
> @@ -985,6 +1001,10 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
>  	ui->data_len = len;
>  	inode->i_size = ubifs_inode(inode)->ui_size = len;
>  
> +	err = ubifs_init_acl(dir, inode);
> +	if (err)
> +		goto out_inode;

Do we really need ACLs for symlinks too? I thought permissions for symlinks are irrelevant.

>  	err = ubifs_init_security(dir, inode, &dentry->d_name);
>  	if (err)
>  		goto out_inode;
> @@ -1395,6 +1415,8 @@ const struct inode_operations ubifs_dir_inode_operations = {
>  	.update_time = ubifs_update_time,
>  #endif
>  	.tmpfile     = ubifs_tmpfile,
> +	.get_acl     = ubifs_get_acl,
> +	.set_acl     = ubifs_set_acl,
>  };
>  
>  const struct file_operations ubifs_dir_operations = {
> diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
> index 4ed270b..17f6098 100644
> --- a/fs/ubifs/file.c
> +++ b/fs/ubifs/file.c
> @@ -53,6 +53,7 @@
>  #include <linux/mount.h>
>  #include <linux/slab.h>
>  #include <linux/migrate.h>
> +#include <linux/posix_acl.h>
>  
>  static int read_block(struct inode *inode, void *addr, unsigned int block,
>  		      struct ubifs_data_node *dn)
> @@ -1251,6 +1252,10 @@ static int do_setattr(struct ubifs_info *c, struct inode *inode,
>  		ubifs_release_budget(c, &req);
>  	if (IS_SYNC(inode))
>  		err = inode->i_sb->s_op->write_inode(inode, NULL);
> +
> +	if (!err && (attr->ia_valid & ATTR_MODE))
> +		err = posix_acl_chmod(inode, inode->i_mode);
> +
>  	return err;
>  }
>  
> @@ -1628,6 +1633,8 @@ const struct inode_operations ubifs_file_inode_operations = {
>  #ifdef CONFIG_UBIFS_ATIME_SUPPORT
>  	.update_time = ubifs_update_time,
>  #endif
> +	.get_acl     = ubifs_get_acl,
> +	.set_acl     = ubifs_set_acl,
>  };
>  
>  const struct inode_operations ubifs_symlink_inode_operations = {
> @@ -1642,6 +1649,8 @@ const struct inode_operations ubifs_symlink_inode_operations = {
>  #ifdef CONFIG_UBIFS_ATIME_SUPPORT
>  	.update_time = ubifs_update_time,
>  #endif
> +	.get_acl     = ubifs_get_acl,
> +	.set_acl     = ubifs_set_acl,
>  };
>  
>  const struct file_operations ubifs_file_operations = {
> diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
> index 4ec0510..8239dfd 100644
> --- a/fs/ubifs/super.c
> +++ b/fs/ubifs/super.c
> @@ -444,6 +444,9 @@ static int ubifs_show_options(struct seq_file *s, struct dentry *root)
>  			   ubifs_compr_name(c->mount_opts.compr_type));
>  	}
>  
> +	if (c->vfs_sb->s_flags & MS_POSIXACL)
> +		seq_puts(s, ",acl");
> +
>  	return 0;
>  }
>  
> @@ -929,6 +932,8 @@ enum {
>  	Opt_chk_data_crc,
>  	Opt_no_chk_data_crc,
>  	Opt_override_compr,
> +	Opt_acl,
> +	Opt_noacl,
>  	Opt_err,
>  };
>  
> @@ -940,6 +945,8 @@ static const match_table_t tokens = {
>  	{Opt_chk_data_crc, "chk_data_crc"},
>  	{Opt_no_chk_data_crc, "no_chk_data_crc"},
>  	{Opt_override_compr, "compr=%s"},
> +	{Opt_acl, "acl"},
> +	{Opt_noacl, "noacl"},
>  	{Opt_err, NULL},
>  };
>  
> @@ -1040,6 +1047,14 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options,
>  			c->default_compr = c->mount_opts.compr_type;
>  			break;
>  		}
> +#ifdef CONFIG_UBIFS_FS_POSIX_ACL
> +		case Opt_acl:
> +			c->vfs_sb->s_flags |= MS_POSIXACL;
> +			break;
> +		case Opt_noacl:
> +			c->vfs_sb->s_flags &= ~MS_POSIXACL;
> +			break;
> +#endif
>  		default:
>  		{
>  			unsigned long flag;
> diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
> index 096035e..7935449 100644
> --- a/fs/ubifs/ubifs.h
> +++ b/fs/ubifs/ubifs.h
> @@ -1743,6 +1743,24 @@ extern const struct xattr_handler *ubifs_xattr_handlers[];
>  ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size);
>  int ubifs_init_security(struct inode *dentry, struct inode *inode,
>  			const struct qstr *qstr);
> +ssize_t __ubifs_getxattr(struct inode *host, const char *name,
> +				void *buf, size_t size);
> +int __ubifs_setxattr(struct inode *host, const char *name,
> +			    const void *value, size_t size, int flags);
> +
> +/* acl.c */
> +#ifdef CONFIG_UBIFS_FS_POSIX_ACL
> +int ubifs_init_acl(struct inode *dir, struct inode *inode);
> +int ubifs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
> +struct posix_acl *ubifs_get_acl(struct inode *inode, int type);
> +#else
> +static inline int ubifs_init_acl(struct inode *inode, struct inode *dir)
> +{
> +	return 0;
> +}
> +#define ubifs_get_acl NULL
> +#define ubifs_set_acl NULL
> +#endif
>  
>  /* super.c */
>  struct inode *ubifs_iget(struct super_block *sb, unsigned long inum);
> diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c
> index 6c2f4d4..0a596a1 100644
> --- a/fs/ubifs/xattr.c
> +++ b/fs/ubifs/xattr.c
> @@ -52,13 +52,14 @@
>   * in the VFS inode cache. The xentries are cached in the LNC cache (see
>   * tnc.c).
>   *
> - * ACL support is not implemented.
> + * ACL support is now implemented.

I think we can just drop that line now. :-)

>   */
>  
>  #include "ubifs.h"
>  #include <linux/fs.h>
>  #include <linux/slab.h>
>  #include <linux/xattr.h>
> +#include <linux/posix_acl_xattr.h>

While we are here, these includes should also be cleaned up.

>  /*
>   * Limit the number of extended attributes per inode so that the total size
> @@ -268,7 +269,7 @@ static struct inode *iget_xattr(struct ubifs_info *c, ino_t inum)
>  	return ERR_PTR(-EINVAL);
>  }
>  
> -static int __ubifs_setxattr(struct inode *host, const char *name,
> +int __ubifs_setxattr(struct inode *host, const char *name,
>  			    const void *value, size_t size, int flags)
>  {
>  	struct inode *inode;
> @@ -328,7 +329,7 @@ out_free:
>  	return err;
>  }
>  
> -static ssize_t __ubifs_getxattr(struct inode *host, const char *name,
> +ssize_t __ubifs_getxattr(struct inode *host, const char *name,
>  				void *buf, size_t size)
>  {
>  	struct inode *inode;
> @@ -619,5 +620,9 @@ const struct xattr_handler *ubifs_xattr_handlers[] = {
>  	&ubifs_user_xattr_handler,
>  	&ubifs_trusted_xattr_handler,
>  	&ubifs_security_xattr_handler,
> +#ifdef CONFIG_UBIFS_FS_POSIX_ACL
> +	&posix_acl_access_xattr_handler,
> +	&posix_acl_default_xattr_handler,
> +#endif
>  	NULL
>  };
> 

Overall the patch does not look bad and I'm sure we can add it for v4.10 soon.
I'm a bit confused since most stuff is not really UBIFS specific.
Andreas, is just "normal" for ACL support? I thought most code is generic and already in VFS.

Thanks,
//richard


From marex at denx.de  Tue Oct 18 15:04:14 2016
From: marex at denx.de (Marek Vasut)
Date: Wed, 19 Oct 2016 00:04:14 +0200
Subject: [PATCH 1/1] MAINTAINERS: add a maintainer for the SPI NOR
 subsystem
In-Reply-To: <1072e553-202a-70c9-3f3c-815dbdac823d@sigma-star.at>
References: <0a3eaa21fb0f38743308c9cc9fc5d2373f4877de.1476802288.git.cyrille.pitchen@atmel.com>
 <d4e954c1-0bbb-fc16-4e9a-46c25ec4fb9e@denx.de>
 <CAFLxGvy9okx1cHnRhq2U-u574PzAk=Tampw1Fmvp4KzY8vnDnw@mail.gmail.com>
 <3d45f698-08e9-e672-d405-1ab9bfec1222@atmel.com>
 <cf010a6c-b642-0994-bbfd-c86d5ab24e6e@nod.at>
 <20161018184651.GA71760@google.com> <20161018211548.08dded8a@bbrezillon>
 <1072e553-202a-70c9-3f3c-815dbdac823d@sigma-star.at>
Message-ID: <38160757-92bb-45b9-3ee3-472a9286ec7e@denx.de>

On 10/18/2016 11:10 PM, David Oberhollenzer wrote:
> On 10/18/2016 09:15 PM, Boris Brezillon wrote:
>> On Tue, 18 Oct 2016 11:46:51 -0700
>> Brian Norris <computersforpeace at gmail.com> wrote:
>>
>>> + others
>>>
>>> On Tue, Oct 18, 2016 at 06:15:23PM +0200, Richard Weinberger wrote:
>>>> On 18.10.2016 17:55, Cyrille Pitchen wrote:  
>>>>> Le 18/10/2016 ? 17:30, Richard Weinberger a ?crit :  
>>>>>> On Tue, Oct 18, 2016 at 5:17 PM, Marek Vasut <marex at denx.de> wrote:  
>>>>>>> On 10/18/2016 04:58 PM, Cyrille Pitchen wrote:  
>>>>>>>> I would like to volunteer as a maintainer for the SPI NOR part of the MTD
>>>>>>>> subsystem.  
>>>
>>> Awesome!
>>>
>>>>>>>> Over the last months, a significant number of SPI NOR related patches have
>>>>>>>> been submitted, some of them have been reviewed, but very few have finally
>>>>>>>> been merged. Hence, the number of pending SPI NOR related patches continues
>>>>>>>> to increase over the time.  
>>>
>>> Agreed, and sorry. But I guess the delays had the side effect of forcing
>>> peoples hands, instead of delaying the inevitable.
>>>
>>>>>>>> Through my work on SPI NOR memories from many manufacturers over the last
>>>>>>>> two years, I've gained a solid understanding of this technology.
>>>>>>>> I've already helped by reviewing patches from other contributors on the
>>>>>>>> mailing list, and would like to help getting those patches integrated by
>>>>>>>> volunteering as a maintainer for this specific area.  
>>>
>>> Agreed.
>>>
>>>>>>>> Boris Brezillon has already stepped up as a maintainer for the NAND
>>>>>>>> sub-subsystem in MTD, and the SPI NOR sub-subsystem could be handled in
>>>>>>>> the same way: I would be reviewing patches touching this area, collecting
>>>>>>>> them and sending pull requests to Brian Norris.  
>>>>>>
>>>>>> I'd suggest you send pull requests directly to Linus.
>>>>>> Same for NAND.  
>>>
>>> I could go with either method I suppose, but I don't personally like the
>>> idea of splitting out the various bits of MTD into *completely*
>>> independent lines of development. As long as someone (not necessarily
>>> me) can manage pulling the sub-subsystems together, I think it would
>>> make sense to have 1 PR for Linus for non-UBI/FS MTD changes.
>>>
>>>>>>>> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>  
>>>>>>>
>>>>>>> Let me know if you need co-maintainer.  
>>>>>>
>>>>>> +1  
>>>
>>> +1, I think I've not-so-subtly suggested this to Marek previously.
>>
>> Okay, that's all great news!
>> You can add my ack after adding Marek as a co-maintainer.
>>
>>>
>>>>>> While we are here, what about forming a MTD maintainer team?
>>>>>> This concept works very well for other subsystems.
>>>>>>  
>>>>>
>>>>> I totally agree with you so if Marek and you volunteer as well, your help
>>>>> will be precious!  
>>>>
>>>> Well, my SPI-NOR fu is not strong. And UBI/UBIFS keeps me busy.
>>>> But if Brian likes the idea of having a MTD maintainer team I'll offer my help.  
>>>
>>> I think a MTD maintainer team would be good to try, and I think it might
>>> help to resolve my above complaint; a maintainer team could help to make
>>> sure that everything can be coordinated in one tree + pull request,
>>> without adding too many extra points of failure (e.g., so we don't have
>>> awesome SPI NOR and NAND trees get bogged down by a slow MTD pull).
>>>
>>> Random thoughts:
>>>
>>>  Does it make sense to still use infradead.org? We'd need to add a few
>>>  users there.
>>>
>>>  Trust? I have met most of you in person, but not all, and I don't have
>>>  signed keys from all of you. I don't know what the best way to get a
>>>  group-writeable repo with credentials for all of you that we can trust.
>>>  (FWIW, neither Artem nor David met me, but they saw it fit to grant me
>>>  infradead.org access ;) )
>>>
>>>  Coordination: how do we avoid stepping on each other's toes? We'd have
>>>  to definitely 100% kill 'git push -f' and 'git rebase'. Also, would
>>>  patchwork help or hurt us here? I think Boris and I have been sort of
>>>  using it, but it's still got a pretty good backlog (partly real --
>>>  i.e., the cause for this thread; and partly artificial, due to
>>>  accounting).
>>
>> I really think we should keep separate trees for the spi-nor and nand
>> sub-subsystems, and then do PRs. The question is, how do we agree that
>> a PR should be pulled in the MTD tree.
>>
>> I guess we could have a simple rule like, if it's been reviewed by at
>> least X person (I guess 2 is acceptable), then we can merge it.
>>
>>>
>>>  What to do about mtd-utils.git? That's been languishing a bit, and it
>>>  has no release schedule. Maybe we want a plan for that too.
>>
>> Richard and David had some plans for the mtd-utils repo, and I think
>> they already have the permissions to push things to this repo, so the
>> best solution is probably to officially promote them maintainers of
>> mtd-utils.
> I would volunteer to maintain it together with Richard.
> 
> As has been previously mentioned, we did a major overhaul and merged lots
> of fixes locally. AFAIK Richard already has push permissions for the mtd-utils
> tree on infradead.org, so it should be just a matter of making it official?
> 

Yes please, I saw some of your patches via Richard and they were nice.

-- 
Best regards,
Marek Vasut


From pascal.eberhard at gmail.com  Tue Oct 18 16:54:09 2016
From: pascal.eberhard at gmail.com (Pascal Eberhard)
Date: Wed, 19 Oct 2016 01:54:09 +0200
Subject: [PATCH] ubifs: implement POSIX Access Control Lists (ACLs)
In-Reply-To: <443b11a2-729a-32ec-0a6f-5a3276290329@nod.at>
References: <1476046382-19185-1-git-send-email-pascal.eberhard@gmail.com>
 <443b11a2-729a-32ec-0a6f-5a3276290329@nod.at>
Message-ID: <ac97ae77409865d113ddb5c71420a791@38plumes.fr>

Richard,

Thanks for your review.

On 2016-10-18 23:32, Richard Weinberger wrote:
> Pascal,
> 
> On 09.10.2016 22:53, Pascal Eberhard wrote:
>> This patch implements POSIX Access Control Lists (ACLs) in UBIFS.
>> It uses posix_acl_(access|default)_xattr_handler ACL generic handlers
>> as xattr handlers are now used in UBIFS.
> 
> Cool! :)
> CC'ing Andreas, maybe he also has comments.
> 
>> Signed-off-by: Pascal Eberhard <pascal.eberhard at gmail.com>
>> ---
>>  fs/ubifs/Kconfig  |  13 +++++
>>  fs/ubifs/Makefile |   1 +
>>  fs/ubifs/acl.c    | 143 
>> ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  fs/ubifs/dir.c    |  22 +++++++++
>>  fs/ubifs/file.c   |   9 ++++
>>  fs/ubifs/super.c  |  15 ++++++
>>  fs/ubifs/ubifs.h  |  18 +++++++
>>  fs/ubifs/xattr.c  |  11 +++--
>>  8 files changed, 229 insertions(+), 3 deletions(-)
>>  create mode 100644 fs/ubifs/acl.c
>> 

[...]

>> +#include <linux/fs.h>
> 
> ubifs.h includes this already.
> 

ok

>> +#include <linux/xattr.h>
> 
> Ditto.
> 

ok

[...]

>> +/*
>> + * Initialize the ACLs of a new inode.
> 
> Please use the Javadoc style we use for all UBIFS functions.
> (applies to other functions too in this patch)-

ok

[...]

>> diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
>> index ccd9128..a2e5609 100644
>> --- a/fs/ubifs/dir.c
>> +++ b/fs/ubifs/dir.c
>> @@ -270,6 +270,10 @@ static int ubifs_create(struct inode *dir, struct 
>> dentry *dentry, umode_t mode,
>>  		goto out_budg;
>>  	}
>> 
>> +	err = ubifs_init_acl(dir, inode);
>> +	if (err)
>> +		goto out_inode;
>> +
>>  	err = ubifs_init_security(dir, inode, &dentry->d_name);
>>  	if (err)
>>  		goto out_inode;
>> @@ -341,6 +345,10 @@ static int do_tmpfile(struct inode *dir, struct 
>> dentry *dentry,
>>  		ubifs_assert(inode->i_op == &ubifs_file_inode_operations);
>>  	}
>> 
>> +	err = ubifs_init_acl(dir, inode);
>> +	if (err)
>> +		goto out_inode;
> 
> Why do we need ACLs for O_TMPFILE?

O_TMPFILE files are unnamed... until linkat() is called.
open manpage says that when linkat() is called to a O_TMPFILE file:
"In this case, the open() mode argument determines the file permission 
mode, as with O_CREAT."
And mode with O_CREAT is applied with respect of the default ACLs:
"in the absence of a default ACL, the mode of the created file is (mode 
& ~umask)"

So my interpretation is that default ACLs shall be propagated to 
O_TMPFILE at creation.

O_TMPFILE implementation for btrfs and xfs apply default ACLs as well.

[...]

>> @@ -985,6 +1001,10 @@ static int ubifs_symlink(struct inode *dir, 
>> struct dentry *dentry,
>>  	ui->data_len = len;
>>  	inode->i_size = ubifs_inode(inode)->ui_size = len;
>> 
>> +	err = ubifs_init_acl(dir, inode);
>> +	if (err)
>> +		goto out_inode;
> 
> Do we really need ACLs for symlinks too? I thought permissions for
> symlinks are irrelevant.

Indeed, they are irrelevant. It will be removed.

>> diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c
>> index 6c2f4d4..0a596a1 100644
>> --- a/fs/ubifs/xattr.c
>> +++ b/fs/ubifs/xattr.c
>> @@ -52,13 +52,14 @@
>>   * in the VFS inode cache. The xentries are cached in the LNC cache 
>> (see
>>   * tnc.c).
>>   *
>> - * ACL support is not implemented.
>> + * ACL support is now implemented.
> 
> I think we can just drop that line now. :-)

:-)

> 
>>   */
>> 
>>  #include "ubifs.h"
>>  #include <linux/fs.h>
>>  #include <linux/slab.h>
>>  #include <linux/xattr.h>
>> +#include <linux/posix_acl_xattr.h>
> 
> While we are here, these includes should also be cleaned up.
> 

Ok, and I'll remove the now obsolete enum just below too then:

/*
  * Extended attribute type constants.
  *
  * USER_XATTR: user extended attribute ("user.*")
  * TRUSTED_XATTR: trusted extended attribute ("trusted.*)
  * SECURITY_XATTR: security extended attribute ("security.*")
  */

enum {
         USER_XATTR,
         TRUSTED_XATTR,
         SECURITY_XATTR,
};


> 
> Overall the patch does not look bad and I'm sure we can add it for 
> v4.10 soon.

ok, great!

> I'm a bit confused since most stuff is not really UBIFS specific.
> Andreas, is just "normal" for ACL support? I thought most code is
> generic and already in VFS.
> 
> Thanks,
> //richard
> 
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/


From robh at kernel.org  Tue Oct 18 20:17:16 2016
From: robh at kernel.org (Rob Herring)
Date: Tue, 18 Oct 2016 22:17:16 -0500
Subject: [RFC PATCH] mtd: nand: Add OX820 NAND Support
In-Reply-To: <20161018090927.1990-1-narmstrong@baylibre.com>
References: <20161018090927.1990-1-narmstrong@baylibre.com>
Message-ID: <20161018171149.vhlnuqnyn4axnk2p@rob-hp-laptop>

On Tue, Oct 18, 2016 at 11:09:27AM +0200, Neil Armstrong wrote:
> Add NAND driver to support the Oxford Semiconductor OX820 NAND Controller.
> This is a simple memory mapped NAND controller with single chip select and
> software ECC.
> 
> Signed-off-by: Neil Armstrong <narmstrong at baylibre.com>
> ---
>  .../devicetree/bindings/mtd/oxnas-nand.txt         |  24 ++++

Acked-by: Rob Herring <robh at kernel.org>

>  drivers/mtd/nand/Kconfig                           |   5 +
>  drivers/mtd/nand/Makefile                          |   1 +
>  drivers/mtd/nand/oxnas_nand.c                      | 144 +++++++++++++++++++++
>  4 files changed, 174 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mtd/oxnas-nand.txt
>  create mode 100644 drivers/mtd/nand/oxnas_nand.c


From dedekind1 at gmail.com  Tue Oct 18 23:41:24 2016
From: dedekind1 at gmail.com (Artem Bityutskiy)
Date: Wed, 19 Oct 2016 09:41:24 +0300
Subject: [PATCH 1/1] MAINTAINERS: add a maintainer for the SPI NOR
 subsystem
In-Reply-To: <20161018184651.GA71760@google.com>
References: <0a3eaa21fb0f38743308c9cc9fc5d2373f4877de.1476802288.git.cyrille.pitchen@atmel.com>
 <d4e954c1-0bbb-fc16-4e9a-46c25ec4fb9e@denx.de>
 <CAFLxGvy9okx1cHnRhq2U-u574PzAk=Tampw1Fmvp4KzY8vnDnw@mail.gmail.com>
 <3d45f698-08e9-e672-d405-1ab9bfec1222@atmel.com>
 <cf010a6c-b642-0994-bbfd-c86d5ab24e6e@nod.at>
 <20161018184651.GA71760@google.com>
Message-ID: <1476859284.18750.115.camel@gmail.com>

On Tue, 2016-10-18 at 11:46 -0700, Brian Norris wrote:
> I could go with either method I suppose, but I don't personally like
> the
> idea of splitting out the various bits of MTD into *completely*
> independent lines of development. As long as someone (not necessarily
> me) can manage pulling the sub-subsystems together, I think it would
> make sense to have 1 PR for Linus for non-UBI/FS MTD changes.

I think this is a good point. MTD is pretty much a "don't care"
subsystem for Linus, an I do not think he'll appreciate 2 or more micro
MTD pull requests. It makes a lot more sense to consolidate all this
under a single tree MTD tree and make a single pull request.


From geert at linux-m68k.org  Tue Oct 18 23:57:27 2016
From: geert at linux-m68k.org (Geert Uytterhoeven)
Date: Wed, 19 Oct 2016 08:57:27 +0200
Subject: [PATCH 2/2] fsl-quadspi: introduce per-bus spi-bus-width property
In-Reply-To: <20161018220334.6452fc5b.albert.aribaud@3adev.fr>
References: <20160927055957.427-1-albert.aribaud@3adev.fr>
 <20160927055957.427-2-albert.aribaud@3adev.fr>
 <20161003185143.GA27634@rob-hp-laptop>
 <CAMuHMdW6WJBj3TiXU0mmwKJmcwp28HEVUSD17-7RH7-UXFtX1g@mail.gmail.com>
 <20161018220334.6452fc5b.albert.aribaud@3adev.fr>
Message-ID: <CAMuHMdW-L=Wc7mcs6s_N+joEZ8hX7DLHoY_YU0wuvnM=3DN8ug@mail.gmail.com>

On Tue, Oct 18, 2016 at 10:03 PM, Albert ARIBAUD
<albert.aribaud at 3adev.fr> wrote:
> Le Mon, 3 Oct 2016 21:57:58 +0200, Geert Uytterhoeven
> <geert at linux-m68k.org> a ?crit :
>
>> On Mon, Oct 3, 2016 at 8:51 PM, Rob Herring <robh at kernel.org> wrote:
>> > On Tue, Sep 27, 2016 at 07:59:57AM +0200, Albert ARIBAUD (3ADEV) wrote:
>> >> Introduce spi-bus-width property for bus subnodes, to
>> >> specify per-bus capability to use NORMAL, FAST, DUAL,
>> >> and/or QUAD reads.
>> >>
>> >> Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud at 3adev.fr>
>> >> ---
>> >>  Documentation/devicetree/bindings/mtd/fsl-quadspi.txt | 18 ++++++++++++++++++
>> >>  1 file changed, 18 insertions(+)
>> >
>> > Make this a common property.
>
> @Rob: do you mean common to all slaves, i.e. described
> in ./Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt?
>
>> They already exist:
>>
>> Documentation/devicetree/bindings/spi/spi-bus.txt:
>> - spi-tx-bus-width - (optional) The bus width (number of data wires)
>> that is used for MOSI. Defaults to 1 if not present.
>> - spi-rx-bus-width - (optional) The bus width (number of data wires)
>> that is used for MISO. Defaults to 1 if not present.
>>
>> The above are for normal/dual/quad.
>>
>> "Fast" is not a property of the bus, but of the SPI slave, right? Cfr.
>>
>> Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt:
>> - m25p,fast-read : Use the "fast read" opcode to read data from the
>> chip instead of the usual "read" opcode. This opcode is not supported
>> by all chips and support for it can not be detected at runtime.
>>                    Refer to your chips' datasheet to check if this is
>> supported by your chip.
>>
>> Gr{oetje,eeting}s,
>
> @Geert: the problem here is that on the board for which I wrote this
> patch, only one of the two NOR slaves can do quad SPI; the other one
> can do dual at best. Setting a bus property would prevent the
> quad-capable device from doing actual quad reads.
>
> The fsl-quadspi driver already supports per-NOR read and erase commands
> to support heterogeneous NOR setups. A per-NOR bus width property would
> make sense in this light.

spi-[tx]x-bus-width is already a property for the SPI slave, not for
the whole bus.
So you can use 4 for the quad-capable device, and 1 or 2 for the other.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds


From narmstrong at baylibre.com  Wed Oct 19 02:29:59 2016
From: narmstrong at baylibre.com (Neil Armstrong)
Date: Wed, 19 Oct 2016 11:29:59 +0200
Subject: [RFC PATCH] mtd: nand: Add OX820 NAND Support
In-Reply-To: <20161018221744.5e574e82@bbrezillon>
References: <20161018090927.1990-1-narmstrong@baylibre.com>
 <20161018221744.5e574e82@bbrezillon>
Message-ID: <37a5b543-e564-a496-d5cf-c215e798839f@baylibre.com>

Hi Boris,

On 10/18/2016 10:17 PM, Boris Brezillon wrote:
> Hi Neil,
> 
> On Tue, 18 Oct 2016 11:09:27 +0200
> Neil Armstrong <narmstrong at baylibre.com> wrote:
> 
>> Add NAND driver to support the Oxford Semiconductor OX820 NAND Controller.
>> This is a simple memory mapped NAND controller with single chip select and
>> software ECC.
>>
>> Signed-off-by: Neil Armstrong <narmstrong at baylibre.com>
>> ---
>>  .../devicetree/bindings/mtd/oxnas-nand.txt         |  24 ++++
>>  drivers/mtd/nand/Kconfig                           |   5 +
>>  drivers/mtd/nand/Makefile                          |   1 +
>>  drivers/mtd/nand/oxnas_nand.c                      | 144 +++++++++++++++++++++
>>  4 files changed, 174 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/mtd/oxnas-nand.txt
>>  create mode 100644 drivers/mtd/nand/oxnas_nand.c
>>
>> diff --git a/Documentation/devicetree/bindings/mtd/oxnas-nand.txt b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
>> new file mode 100644
>> index 0000000..83b684d
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
>> @@ -0,0 +1,24 @@
>> +* Oxford Semiconductor OXNAS NAND Controller
>> +
>> +Please refer to nand.txt for generic information regarding MTD NAND bindings.
>> +
>> +Required properties:
>> + - compatible: "oxsemi,ox820-nand"
>> + - reg: Base address and length for NAND mapped memory.
>> +
>> +Optional Properties:
>> + - clocks: phandle to the NAND gate clock if needed.
>> + - resets: phandle to the NAND reset control if needed.
>> +
>> +Example:
>> +
>> +nand: nand at 41000000 {
>> +	compatible = "oxsemi,ox820-nand";
>> +	reg = <0x41000000 0x100000>;
>> +	nand-ecc-mode = "soft";
>> +	clocks = <&stdclk CLK_820_NAND>;
>> +	resets = <&reset RESET_NAND>;
>> +	#address-cells = <1>;
>> +	#size-cells = <1>;
>> +	status = "disabled";
>> +};
> 
> Can you switch to new DT representation for NAND controllers, with one
> node for the NAND controller and NAND devices connected to this NAND
> controller defined as sub-nodes of this NAND controller [1]?

Yes, I was wondering if this existed... my bad, next time I will search further.

> 
>> diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
>> index 7b7a887..c023125 100644
>> --- a/drivers/mtd/nand/Kconfig
>> +++ b/drivers/mtd/nand/Kconfig
>> @@ -426,6 +426,11 @@ config MTD_NAND_ORION
>>  	  No board specific support is done by this driver, each board
>>  	  must advertise a platform_device for the driver to attach.
>>  
>> +config MTD_NAND_OXNAS
>> +	tristate "NAND Flash support for Oxford Semiconductor SoC"
>> +	help
>> +	  This enables the NAND flash controller on Oxford Semiconductor SoCs.
>> +
>>  config MTD_NAND_FSL_ELBC
>>  	tristate "NAND support for Freescale eLBC controllers"
>>  	depends on FSL_SOC
>> diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
>> index cafde6f..05fc054 100644
>> --- a/drivers/mtd/nand/Makefile
>> +++ b/drivers/mtd/nand/Makefile
>> @@ -35,6 +35,7 @@ obj-$(CONFIG_MTD_NAND_TMIO)		+= tmio_nand.o
>>  obj-$(CONFIG_MTD_NAND_PLATFORM)		+= plat_nand.o
>>  obj-$(CONFIG_MTD_NAND_PASEMI)		+= pasemi_nand.o
>>  obj-$(CONFIG_MTD_NAND_ORION)		+= orion_nand.o
>> +obj-$(CONFIG_MTD_NAND_OXNAS)		+= oxnas_nand.o
>>  obj-$(CONFIG_MTD_NAND_FSL_ELBC)		+= fsl_elbc_nand.o
>>  obj-$(CONFIG_MTD_NAND_FSL_IFC)		+= fsl_ifc_nand.o
>>  obj-$(CONFIG_MTD_NAND_FSL_UPM)		+= fsl_upm.o
>> diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/oxnas_nand.c
>> new file mode 100644
>> index 0000000..ee402ab
>> --- /dev/null
>> +++ b/drivers/mtd/nand/oxnas_nand.c
>> @@ -0,0 +1,144 @@
>> +/*
>> + * Oxford Semiconductor OXNAS NAND driver
>> + *
>> + * Heavily based on plat_nand.c :
>> + * Author: Vitaly Wool <vitalywool at gmail.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + */
>> +
>> +#include <linux/err.h>
>> +#include <linux/io.h>
>> +#include <linux/module.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/slab.h>
>> +#include <linux/clk.h>
>> +#include <linux/reset.h>
>> +#include <linux/mtd/mtd.h>
>> +#include <linux/mtd/nand.h>
>> +#include <linux/mtd/partitions.h>
>> +
>> +/* nand commands */
>> +#define NAND_CMD_ALE		BIT(18)
>> +#define NAND_CMD_CLE		BIT(19)
>> +#define NAND_CMD_CS		0
> 
> I guess this is zero here because you only support connecting a NAND to
> CS0.
> It's probably something like
> 
> OX820_NAND_CS(x)		((x) << CS_FIELD_SHIFT)

The hardware seems to be able to drive multiple chip selects, but no implementation does this.
We will stick to CS0 only here for test reasons.

> 
>> +#define NAND_CMD_RESET		0xff
> 
> Why do you have to redefine it? it's already defined here [2].
> 
>> +#define NAND_CMD		(NAND_CMD_CS | NAND_CMD_CLE)
>> +#define NAND_ADDR		(NAND_CMD_CS | NAND_CMD_ALE)
>> +#define NAND_DATA		(NAND_CMD_CS)
> 
> Please prefix those macros with OX820, has stated above, this can
> conflict with generic definitions.
> Also, I'm not sure you should pass the CS information here.
> 
>> +
>> +struct oxnas_nand_data {
>> +	struct nand_chip	chip;
>> +	void __iomem		*io_base;
>> +	struct clk		*clk;
>> +};
> 
> Even if your driver does not seem to support connecting several chips
> to the same controller, I'd like you to clearly separate the NAND
> controller and NAND chip objects:
> 
> #define OXNAS_NAND_MAX_CHIPS	1
> 
> struct oxnas_nand_controller {
> 	struct nand_hw_control base;
> 	void __iomem *io_base;
> 	struct clk *clk;
> 	struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS];
> }

Ok.

> 
>> +
>> +static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
>> +				unsigned int ctrl)
>> +{
>> +	struct nand_chip *this = mtd->priv;
>> +	unsigned long nandaddr = (unsigned long) this->IO_ADDR_W;
> 
> Please use the ->io_base field directly, and do not use ->IO_ADDR_W/R
> (I'd like to get rid of them at some point).

Yes, it seems cleaner.

> 
> Also, declare the nandaddr as a void __iomem *, and use the '+'
> operator instead of '|'.
> 
>> +
>> +	if (ctrl & NAND_CTRL_CHANGE) {
>> +		nandaddr &= ~(NAND_CMD | NAND_ADDR);
> 
> This is not needed.
> 
>> +		if (ctrl & NAND_CLE)
>> +			nandaddr |= NAND_CMD;
>> +		else if (ctrl & NAND_ALE)
>> +			nandaddr |= NAND_ADDR;
>> +		this->IO_ADDR_W = (void __iomem *) nandaddr;
> 
> This is not needed, is it?

No more if we stick to ->io_base

> 
>> +	}
>> +
>> +	if (cmd != NAND_CMD_NONE)
>> +		writeb(cmd, (void __iomem *) nandaddr);
>> +}
>> +
>> +/*
>> + * Probe for the NAND device.
>> + */
>> +static int oxnas_nand_probe(struct platform_device *pdev)
>> +{
>> +	struct oxnas_nand_data *data;
>> +	struct mtd_info *mtd;
>> +	struct resource *res;
>> +	int err = 0;
>> +
>> +	/* Allocate memory for the device structure (and zero it) */
>> +	data = devm_kzalloc(&pdev->dev, sizeof(struct oxnas_nand_data),
>> +			    GFP_KERNEL);
>> +	if (!data)
>> +		return -ENOMEM;
>> +
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	data->io_base = devm_ioremap_resource(&pdev->dev, res);
>> +	if (IS_ERR(data->io_base))
>> +		return PTR_ERR(data->io_base);
>> +
>> +	data->clk = devm_clk_get(&pdev->dev, NULL);
>> +	if (IS_ERR(data->clk))
>> +		data->clk = NULL;
>> +
>> +	nand_set_flash_node(&data->chip, pdev->dev.of_node);
>> +	mtd = nand_to_mtd(&data->chip);
>> +	mtd->dev.parent = &pdev->dev;
>> +	mtd->priv = &data->chip;
>> +
>> +	data->chip.IO_ADDR_R = data->io_base;
>> +	data->chip.IO_ADDR_W = data->io_base;
> 
> As I said above, don't use these fields.
> 
>> +	data->chip.cmd_ctrl = oxnas_nand_cmd_ctrl;
>> +	data->chip.chip_delay = 30;
>> +	data->chip.ecc.mode = NAND_ECC_SOFT;
>> +	data->chip.ecc.algo = NAND_ECC_HAMMING;
> 
> Probably a good idea to support soft ECC as well...

This was taken from plat_nand.c, I was not sure if it was necessary, will remove this and rely on DT attributes.

> 
>> +
>> +	platform_set_drvdata(pdev, data);
>> +
>> +	clk_prepare_enable(data->clk);
>> +	device_reset_optional(&pdev->dev);
>> +
>> +	/* Scan to find existence of the device */
>> +	if (nand_scan(mtd, 1)) {
> 
> Why not returning nand_scan() error code?

Same, bad plat_nand.c copy/paste.

> 
>> +		err = -ENXIO;
>> +		goto out;
> 
> Return directly here.
> 
>> +	}
>> +
>> +	err = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
> 
> Use mtd_device_register() here.
> 
>> +	if (!err)
>> +		return err;
>> +
>> +	nand_release(mtd);
> 
> Why not
> 
> 	if (err)
> 		nand_release(mtd);
> 
>> +out:
> 
> Drop this label.

Will refactor this error management.

> 
>> +	return err;
>> +}
>> +
>> +static int oxnas_nand_remove(struct platform_device *pdev)
>> +{
>> +	struct oxnas_nand_data *data = platform_get_drvdata(pdev);
>> +
>> +	nand_release(nand_to_mtd(&data->chip));
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct of_device_id oxnas_nand_match[] = {
>> +	{ .compatible = "oxsemi,ox820-nand" },
>> +	{},
>> +};
>> +MODULE_DEVICE_TABLE(of, oxnas_nand_match);
>> +
>> +static struct platform_driver oxnas_nand_driver = {
>> +	.probe	= oxnas_nand_probe,
>> +	.remove	= oxnas_nand_remove,
>> +	.driver	= {
>> +		.name		= "oxnas_nand",
>> +		.of_match_table = oxnas_nand_match,
>> +	},
>> +};
>> +
>> +module_platform_driver(oxnas_nand_driver);
>> +
>> +MODULE_LICENSE("GPL");
>> +MODULE_AUTHOR("Vitaly Wool");
>> +MODULE_DESCRIPTION("Oxnas NAND driver");
>> +MODULE_ALIAS("platform:oxnas_nand");
> 
> Thanks,
> 
> Boris

Thanks,
Neil

> 
> [1]https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/mtd/nand.txt?id=refs/tags/v4.9-rc1#n57
> [2]http://lxr.free-electrons.com/source/include/linux/mtd/nand.h#L90
> 



From richard at nod.at  Wed Oct 19 03:58:35 2016
From: richard at nod.at (Richard Weinberger)
Date: Wed, 19 Oct 2016 12:58:35 +0200
Subject: [PATCH] ubifs: Abort readdir upon error
Message-ID: <1476874715-7127-1-git-send-email-richard@nod.at>

If UBIFS is facing an error while walking a directory, it reports this
error and ubifs_readdir() returns the error code. But the VFS readdir
logic does not make the getdents system call fail in all cases. When the
readdir cursor indicates that more entries are present, the system call
will just return and the libc wrapper will try again since it also
knows that more entries are present.
This causes the libc wrapper to busy loop for ever when a directory is
corrupted on UBIFS.
A common approach do deal with corrupted directory entries is
skipping them by setting the cursor to the next entry. On UBIFS this
approach is not possible since we cannot compute the next directory
entry cursor position without reading the current entry. So all we can
do is setting the cursor to the "no more entries" position and make
getdents exit.

Cc: stable at vger.kernel.org
Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/ubifs/dir.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index 668ec3b90ea1..bd4a5e8ce441 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -439,7 +439,7 @@ static unsigned int vfs_dent_type(uint8_t type)
  */
 static int ubifs_readdir(struct file *file, struct dir_context *ctx)
 {
-	int err;
+	int err = 0;
 	struct qstr nm;
 	union ubifs_key key;
 	struct ubifs_dent_node *dent;
@@ -541,14 +541,12 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
 	kfree(file->private_data);
 	file->private_data = NULL;
 
-	if (err != -ENOENT) {
+	if (err != -ENOENT)
 		ubifs_err(c, "cannot find next direntry, error %d", err);
-		return err;
-	}
 
 	/* 2 is a special value indicating that there are no more direntries */
 	ctx->pos = 2;
-	return 0;
+	return err;
 }
 
 /* Free saved readdir() state when the directory is closed */
-- 
2.7.3



From boris.brezillon at free-electrons.com  Wed Oct 19 04:13:01 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Wed, 19 Oct 2016 13:13:01 +0200
Subject: [RFC PATCH] mtd: nand: Add OX820 NAND Support
In-Reply-To: <37a5b543-e564-a496-d5cf-c215e798839f@baylibre.com>
References: <20161018090927.1990-1-narmstrong@baylibre.com>
 <20161018221744.5e574e82@bbrezillon>
 <37a5b543-e564-a496-d5cf-c215e798839f@baylibre.com>
Message-ID: <20161019131301.19c7a64d@bbrezillon>

On Wed, 19 Oct 2016 11:29:59 +0200
Neil Armstrong <narmstrong at baylibre.com> wrote:

> Hi Boris,
> 
> On 10/18/2016 10:17 PM, Boris Brezillon wrote:
> > Hi Neil,
> > 
> > On Tue, 18 Oct 2016 11:09:27 +0200
> > Neil Armstrong <narmstrong at baylibre.com> wrote:
> >   
> >> Add NAND driver to support the Oxford Semiconductor OX820 NAND Controller.
> >> This is a simple memory mapped NAND controller with single chip select and
> >> software ECC.
> >>
> >> Signed-off-by: Neil Armstrong <narmstrong at baylibre.com>
> >> ---
> >>  .../devicetree/bindings/mtd/oxnas-nand.txt         |  24 ++++
> >>  drivers/mtd/nand/Kconfig                           |   5 +
> >>  drivers/mtd/nand/Makefile                          |   1 +
> >>  drivers/mtd/nand/oxnas_nand.c                      | 144 +++++++++++++++++++++
> >>  4 files changed, 174 insertions(+)
> >>  create mode 100644 Documentation/devicetree/bindings/mtd/oxnas-nand.txt
> >>  create mode 100644 drivers/mtd/nand/oxnas_nand.c
> >>
> >> diff --git a/Documentation/devicetree/bindings/mtd/oxnas-nand.txt b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
> >> new file mode 100644
> >> index 0000000..83b684d
> >> --- /dev/null
> >> +++ b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
> >> @@ -0,0 +1,24 @@
> >> +* Oxford Semiconductor OXNAS NAND Controller
> >> +
> >> +Please refer to nand.txt for generic information regarding MTD NAND bindings.
> >> +
> >> +Required properties:
> >> + - compatible: "oxsemi,ox820-nand"
> >> + - reg: Base address and length for NAND mapped memory.
> >> +
> >> +Optional Properties:
> >> + - clocks: phandle to the NAND gate clock if needed.
> >> + - resets: phandle to the NAND reset control if needed.
> >> +
> >> +Example:
> >> +
> >> +nand: nand at 41000000 {
> >> +	compatible = "oxsemi,ox820-nand";
> >> +	reg = <0x41000000 0x100000>;
> >> +	nand-ecc-mode = "soft";
> >> +	clocks = <&stdclk CLK_820_NAND>;
> >> +	resets = <&reset RESET_NAND>;
> >> +	#address-cells = <1>;
> >> +	#size-cells = <1>;
> >> +	status = "disabled";
> >> +};  
> > 
> > Can you switch to new DT representation for NAND controllers, with one
> > node for the NAND controller and NAND devices connected to this NAND
> > controller defined as sub-nodes of this NAND controller [1]?  
> 
> Yes, I was wondering if this existed... my bad, next time I will search further.

No problem. That's what reviews are here for ;-).

[...]
> >> diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/oxnas_nand.c

[...]

> >> +
> >> +/* nand commands */
> >> +#define NAND_CMD_ALE		BIT(18)
> >> +#define NAND_CMD_CLE		BIT(19)
> >> +#define NAND_CMD_CS		0  
> > 
> > I guess this is zero here because you only support connecting a NAND to
> > CS0.
> > It's probably something like
> > 
> > OX820_NAND_CS(x)		((x) << CS_FIELD_SHIFT)  
> 
> The hardware seems to be able to drive multiple chip selects, but no implementation does this.
> We will stick to CS0 only here for test reasons.

Then no need to define this _CS flag.

[...]

> >> +	data->chip.cmd_ctrl = oxnas_nand_cmd_ctrl;
> >> +	data->chip.chip_delay = 30;
> >> +	data->chip.ecc.mode = NAND_ECC_SOFT;
> >> +	data->chip.ecc.algo = NAND_ECC_HAMMING;  
> > 
> > Probably a good idea to support soft ECC as well...  

I meant BCH, not soft :-).

> 
> This was taken from plat_nand.c, I was not sure if it was necessary, will remove this and rely on DT attributes.

Yes, that's probably the best solution.

Regards,

Boris


From agruenba at redhat.com  Wed Oct 19 07:34:30 2016
From: agruenba at redhat.com (Andreas Gruenbacher)
Date: Wed, 19 Oct 2016 16:34:30 +0200
Subject: [PATCH] ubifs: implement POSIX Access Control Lists (ACLs)
In-Reply-To: <443b11a2-729a-32ec-0a6f-5a3276290329@nod.at>
References: <1476046382-19185-1-git-send-email-pascal.eberhard@gmail.com>
 <443b11a2-729a-32ec-0a6f-5a3276290329@nod.at>
Message-ID: <CAHc6FU7Sh3cX2NAs6bu1jBWQwwpQK0OLsLMAEZMpzocb7L5teg@mail.gmail.com>

Pascal,

On Tue, Oct 18, 2016 at 11:32 PM, Richard Weinberger <richard at nod.at> wrote:
> Pascal,
>
> On 09.10.2016 22:53, Pascal Eberhard wrote:
>> This patch implements POSIX Access Control Lists (ACLs) in UBIFS.
>> It uses posix_acl_(access|default)_xattr_handler ACL generic handlers
>> as xattr handlers are now used in UBIFS.
>
> Cool! :)
> CC'ing Andreas, maybe he also has comments.

please run this through xfstests as well. Note the following fixes /
improvements I've made in the course of reviewing this; they've
obviously not been merged, yet:

  https://github.com/andreas-gruenbacher/xfsprogs-dev/commits/io
  https://github.com/andreas-gruenbacher/xfstests/commits/tmpfile

>> Signed-off-by: Pascal Eberhard <pascal.eberhard at gmail.com>
>> ---
>>  fs/ubifs/Kconfig  |  13 +++++
>>  fs/ubifs/Makefile |   1 +
>>  fs/ubifs/acl.c    | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  fs/ubifs/dir.c    |  22 +++++++++
>>  fs/ubifs/file.c   |   9 ++++
>>  fs/ubifs/super.c  |  15 ++++++
>>  fs/ubifs/ubifs.h  |  18 +++++++
>>  fs/ubifs/xattr.c  |  11 +++--
>>  8 files changed, 229 insertions(+), 3 deletions(-)
>>  create mode 100644 fs/ubifs/acl.c
>>
>> diff --git a/fs/ubifs/Kconfig b/fs/ubifs/Kconfig
>> index 7ff7712..39119e5 100644
>> --- a/fs/ubifs/Kconfig
>> +++ b/fs/ubifs/Kconfig
>> @@ -50,3 +50,16 @@ config UBIFS_ATIME_SUPPORT
>>         strictatime is the "heavy", relatime is "lighter", etc.
>>
>>         If unsure, say 'N'
>> +
>> +config UBIFS_FS_POSIX_ACL
>> +     bool "UBIFS POSIX Access Control Lists"
>> +     depends on UBIFS_FS
>> +     select FS_POSIX_ACL
>> +     help
>> +       POSIX Access Control Lists (ACLs) support permissions for users and
>> +       groups beyond the owner/group/world scheme.
>> +
>> +       To learn more about Access Control Lists, visit the POSIX ACLs for
>> +       Linux website <http://acl.bestbits.at/>.
>> +
>> +       If you don't know what Access Control Lists are, say N
>> diff --git a/fs/ubifs/Makefile b/fs/ubifs/Makefile
>> index c54a243..af7a83f 100644
>> --- a/fs/ubifs/Makefile
>> +++ b/fs/ubifs/Makefile
>> @@ -5,3 +5,4 @@ ubifs-y += tnc.o master.o scan.o replay.o log.o commit.o gc.o orphan.o
>>  ubifs-y += budget.o find.o tnc_commit.o compress.o lpt.o lprops.o
>>  ubifs-y += recovery.o ioctl.o lpt_commit.o tnc_misc.o xattr.o debug.o
>>  ubifs-y += misc.o
>> +ubifs-$(CONFIG_UBIFS_FS_POSIX_ACL) += acl.o
>> \ No newline at end of file
>> diff --git a/fs/ubifs/acl.c b/fs/ubifs/acl.c
>> new file mode 100644
>> index 0000000..a4d4734
>> --- /dev/null
>> +++ b/fs/ubifs/acl.c
>> @@ -0,0 +1,143 @@
>> +/*
>> + * This file is part of UBIFS.
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2 as published by
>> + * the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful, but WITHOUT
>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
>> + * more details.
>> + *
>> + */
>> +
>> +#include <linux/fs.h>
>
> ubifs.h includes this already.
>
>> +#include <linux/xattr.h>
>
> Ditto.
>
>> +#include <linux/posix_acl_xattr.h>
>> +
>> +#include "ubifs.h"
>> +
>> +struct posix_acl *ubifs_get_acl(struct inode *inode, int type)
>> +{
>> +     int size;
>> +     const char *name;
>> +     char *value = NULL;
>> +     struct posix_acl *acl;
>> +
>> +     switch (type) {
>> +     case ACL_TYPE_ACCESS:
>> +             name = XATTR_NAME_POSIX_ACL_ACCESS;
>> +             break;
>> +     case ACL_TYPE_DEFAULT:
>> +             name = XATTR_NAME_POSIX_ACL_DEFAULT;
>> +             break;
>> +     default:
>> +             return ERR_PTR(-EINVAL);
>> +     }
>> +
>> +     size = __ubifs_getxattr(inode, name, NULL, 0);
>> +     if (size > 0) {
>> +             value = kzalloc(size, GFP_KERNEL);
>> +             if (!value)
>> +                     return ERR_PTR(-ENOMEM);
>> +             size = __ubifs_getxattr(inode, name, value, size);
>> +     }
>> +     if (size > 0)
>> +             acl = posix_acl_from_xattr(&init_user_ns, value, size);
>> +     else if (size == -ERANGE || size == -ENODATA || size == 0)
>> +             acl = NULL;
>> +     else
>> +             acl = ERR_PTR(size);
>> +
>> +     kfree(value);
>> +     if (!IS_ERR(acl))
>> +             set_cached_acl(inode, type, acl);

The get_acl inode operation should no longer call set_cached_acl; the
cached ACL is updated automatically. (It's correct to use
set_cached_acl in the set_acl inode operation though.)

>> +
>> +     return acl;
>> +}
>> +
>> +int ubifs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
>> +{
>> +     int ret;
>> +     int size = 0;
>> +     const char *name;
>> +     char *value = NULL;
>> +     int flags = 0;
>> +
>> +     switch (type) {
>> +     case ACL_TYPE_ACCESS:
>> +             name = XATTR_NAME_POSIX_ACL_ACCESS;
>> +             if (acl) {
>> +                     ret = posix_acl_equiv_mode(acl, &inode->i_mode);
>> +                     if (ret < 0)
>> +                             return ret;
>> +                     if (ret == 0)
>> +                             acl = NULL;
>> +             }
>> +             ret = 0;
>> +             break;
>> +     case ACL_TYPE_DEFAULT:
>> +             if (!S_ISDIR(inode->i_mode))
>> +                     return acl ? -EINVAL : 0;
>> +             name = XATTR_NAME_POSIX_ACL_DEFAULT;
>> +             break;
>> +     default:
>> +             return -EINVAL;
>> +     }
>> +
>> +     if (acl) {
>> +             size = posix_acl_xattr_size(acl->a_count);
>> +             value = kmalloc(size, GFP_KERNEL);
>> +             if (!value)
>> +                     return -ENOMEM;
>> +
>> +             ret = posix_acl_to_xattr(&init_user_ns, acl, value, size);
>> +             if (ret < 0)
>> +                     goto out;
>> +     }
>> +
>> +     if (size == 0)
>> +             flags = XATTR_REPLACE;
>> +     ret = __ubifs_setxattr(inode, name, value, size, flags);
>> +
>> +out:
>> +     kfree(value);
>> +     if (!ret)
>> +             set_cached_acl(inode, type, acl);
>> +
>> +     return ret;
>> +}
>> +
>> +/*
>> + * Initialize the ACLs of a new inode.
>
> Please use the Javadoc style we use for all UBIFS functions.
> (applies to other functions too in this patch)-
>
>> + */
>> +int ubifs_init_acl(struct inode *dir, struct inode *inode)
>> +{
>> +     struct posix_acl *default_acl, *acl;
>> +     int ret = 0;
>> +
>> +     ret = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
>> +     if (ret)
>> +             return ret;
>> +
>> +     if (default_acl) {
>> +             inode_lock(inode);

Why the inode locking here?

>> +             ret = ubifs_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
>> +             inode_unlock(inode);
>> +             posix_acl_release(default_acl);
>> +     }
>> +
>> +     if (acl) {
>> +             if (!ret) {
>> +                     inode_lock(inode);

Same here.

>> +                     ret = ubifs_set_acl(inode, acl, ACL_TYPE_ACCESS);
>> +                     inode_unlock(inode);
>> +             }
>> +             posix_acl_release(acl);
>> +     }
>> +
>> +     if (!default_acl && !acl)
>> +             cache_no_acl(inode);

This call to cache_no_acl doesn't make sense; please check. It may be
wrong in btrfs as well; copying Josef for that.

>> +     return ret;
>> +}
>> diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
>> index ccd9128..a2e5609 100644
>> --- a/fs/ubifs/dir.c
>> +++ b/fs/ubifs/dir.c
>> @@ -270,6 +270,10 @@ static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
>>               goto out_budg;
>>       }
>>
>> +     err = ubifs_init_acl(dir, inode);
>> +     if (err)
>> +             goto out_inode;
>> +

The pattern ubifs_budget_space / ubifs_new_inode / ubifs_init_acl /
ubifs_init_security repeats a number of times in the code, so it
should probably be put in a function.

>>       err = ubifs_init_security(dir, inode, &dentry->d_name);
>>       if (err)
>>               goto out_inode;
>> @@ -341,6 +345,10 @@ static int do_tmpfile(struct inode *dir, struct dentry *dentry,
>>               ubifs_assert(inode->i_op == &ubifs_file_inode_operations);
>>       }
>>
>> +     err = ubifs_init_acl(dir, inode);
>> +     if (err)
>> +             goto out_inode;
>
> Why do we need ACLs for O_TMPFILE?
>
>> +
>>       err = ubifs_init_security(dir, inode, &dentry->d_name);
>>       if (err)
>>               goto out_inode;
>> @@ -821,6 +829,10 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
>>               goto out_budg;
>>       }
>>
>> +     err = ubifs_init_acl(dir, inode);
>> +     if (err)
>> +             goto out_inode;
>> +
>>       err = ubifs_init_security(dir, inode, &dentry->d_name);
>>       if (err)
>>               goto out_inode;
>> @@ -903,6 +915,10 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
>>       ui->data = dev;
>>       ui->data_len = devlen;
>>
>> +     err = ubifs_init_acl(dir, inode);
>> +     if (err)
>> +             goto out_inode;
>> +
>>       err = ubifs_init_security(dir, inode, &dentry->d_name);
>>       if (err)
>>               goto out_inode;
>> @@ -985,6 +1001,10 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
>>       ui->data_len = len;
>>       inode->i_size = ubifs_inode(inode)->ui_size = len;
>>
>> +     err = ubifs_init_acl(dir, inode);
>> +     if (err)
>> +             goto out_inode;
>
> Do we really need ACLs for symlinks too? I thought permissions for symlinks are irrelevant.
>
>>       err = ubifs_init_security(dir, inode, &dentry->d_name);
>>       if (err)
>>               goto out_inode;
>> @@ -1395,6 +1415,8 @@ const struct inode_operations ubifs_dir_inode_operations = {
>>       .update_time = ubifs_update_time,
>>  #endif
>>       .tmpfile     = ubifs_tmpfile,
>> +     .get_acl     = ubifs_get_acl,
>> +     .set_acl     = ubifs_set_acl,
>>  };
>>
>>  const struct file_operations ubifs_dir_operations = {
>> diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
>> index 4ed270b..17f6098 100644
>> --- a/fs/ubifs/file.c
>> +++ b/fs/ubifs/file.c
>> @@ -53,6 +53,7 @@
>>  #include <linux/mount.h>
>>  #include <linux/slab.h>
>>  #include <linux/migrate.h>
>> +#include <linux/posix_acl.h>
>>
>>  static int read_block(struct inode *inode, void *addr, unsigned int block,
>>                     struct ubifs_data_node *dn)
>> @@ -1251,6 +1252,10 @@ static int do_setattr(struct ubifs_info *c, struct inode *inode,
>>               ubifs_release_budget(c, &req);
>>       if (IS_SYNC(inode))
>>               err = inode->i_sb->s_op->write_inode(inode, NULL);
>> +
>> +     if (!err && (attr->ia_valid & ATTR_MODE))
>> +             err = posix_acl_chmod(inode, inode->i_mode);
>> +
>>       return err;
>>  }
>>
>> @@ -1628,6 +1633,8 @@ const struct inode_operations ubifs_file_inode_operations = {
>>  #ifdef CONFIG_UBIFS_ATIME_SUPPORT
>>       .update_time = ubifs_update_time,
>>  #endif
>> +     .get_acl     = ubifs_get_acl,
>> +     .set_acl     = ubifs_set_acl,
>>  };
>>
>>  const struct inode_operations ubifs_symlink_inode_operations = {
>> @@ -1642,6 +1649,8 @@ const struct inode_operations ubifs_symlink_inode_operations = {
>>  #ifdef CONFIG_UBIFS_ATIME_SUPPORT
>>       .update_time = ubifs_update_time,
>>  #endif
>> +     .get_acl     = ubifs_get_acl,
>> +     .set_acl     = ubifs_set_acl,
>>  };
>>
>>  const struct file_operations ubifs_file_operations = {
>> diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
>> index 4ec0510..8239dfd 100644
>> --- a/fs/ubifs/super.c
>> +++ b/fs/ubifs/super.c
>> @@ -444,6 +444,9 @@ static int ubifs_show_options(struct seq_file *s, struct dentry *root)
>>                          ubifs_compr_name(c->mount_opts.compr_type));
>>       }
>>
>> +     if (c->vfs_sb->s_flags & MS_POSIXACL)
>> +             seq_puts(s, ",acl");
>> +
>>       return 0;
>>  }
>>
>> @@ -929,6 +932,8 @@ enum {
>>       Opt_chk_data_crc,
>>       Opt_no_chk_data_crc,
>>       Opt_override_compr,
>> +     Opt_acl,
>> +     Opt_noacl,
>>       Opt_err,
>>  };
>>
>> @@ -940,6 +945,8 @@ static const match_table_t tokens = {
>>       {Opt_chk_data_crc, "chk_data_crc"},
>>       {Opt_no_chk_data_crc, "no_chk_data_crc"},
>>       {Opt_override_compr, "compr=%s"},
>> +     {Opt_acl, "acl"},
>> +     {Opt_noacl, "noacl"},
>>       {Opt_err, NULL},
>>  };
>>
>> @@ -1040,6 +1047,14 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options,
>>                       c->default_compr = c->mount_opts.compr_type;
>>                       break;
>>               }
>> +#ifdef CONFIG_UBIFS_FS_POSIX_ACL
>> +             case Opt_acl:
>> +                     c->vfs_sb->s_flags |= MS_POSIXACL;
>> +                     break;
>> +             case Opt_noacl:
>> +                     c->vfs_sb->s_flags &= ~MS_POSIXACL;
>> +                     break;
>> +#endif
>>               default:
>>               {
>>                       unsigned long flag;
>> diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
>> index 096035e..7935449 100644
>> --- a/fs/ubifs/ubifs.h
>> +++ b/fs/ubifs/ubifs.h
>> @@ -1743,6 +1743,24 @@ extern const struct xattr_handler *ubifs_xattr_handlers[];
>>  ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size);
>>  int ubifs_init_security(struct inode *dentry, struct inode *inode,
>>                       const struct qstr *qstr);
>> +ssize_t __ubifs_getxattr(struct inode *host, const char *name,
>> +                             void *buf, size_t size);
>> +int __ubifs_setxattr(struct inode *host, const char *name,
>> +                         const void *value, size_t size, int flags);
>> +
>> +/* acl.c */
>> +#ifdef CONFIG_UBIFS_FS_POSIX_ACL
>> +int ubifs_init_acl(struct inode *dir, struct inode *inode);
>> +int ubifs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
>> +struct posix_acl *ubifs_get_acl(struct inode *inode, int type);
>> +#else
>> +static inline int ubifs_init_acl(struct inode *inode, struct inode *dir)
>> +{
>> +     return 0;
>> +}
>> +#define ubifs_get_acl NULL
>> +#define ubifs_set_acl NULL
>> +#endif
>>
>>  /* super.c */
>>  struct inode *ubifs_iget(struct super_block *sb, unsigned long inum);
>> diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c
>> index 6c2f4d4..0a596a1 100644
>> --- a/fs/ubifs/xattr.c
>> +++ b/fs/ubifs/xattr.c
>> @@ -52,13 +52,14 @@
>>   * in the VFS inode cache. The xentries are cached in the LNC cache (see
>>   * tnc.c).
>>   *
>> - * ACL support is not implemented.
>> + * ACL support is now implemented.
>
> I think we can just drop that line now. :-)
>
>>   */
>>
>>  #include "ubifs.h"
>>  #include <linux/fs.h>
>>  #include <linux/slab.h>
>>  #include <linux/xattr.h>
>> +#include <linux/posix_acl_xattr.h>
>
> While we are here, these includes should also be cleaned up.
>
>>  /*
>>   * Limit the number of extended attributes per inode so that the total size
>> @@ -268,7 +269,7 @@ static struct inode *iget_xattr(struct ubifs_info *c, ino_t inum)
>>       return ERR_PTR(-EINVAL);
>>  }
>>
>> -static int __ubifs_setxattr(struct inode *host, const char *name,
>> +int __ubifs_setxattr(struct inode *host, const char *name,
>>                           const void *value, size_t size, int flags)
>>  {
>>       struct inode *inode;
>> @@ -328,7 +329,7 @@ out_free:
>>       return err;
>>  }
>>
>> -static ssize_t __ubifs_getxattr(struct inode *host, const char *name,
>> +ssize_t __ubifs_getxattr(struct inode *host, const char *name,
>>                               void *buf, size_t size)
>>  {
>>       struct inode *inode;
>> @@ -619,5 +620,9 @@ const struct xattr_handler *ubifs_xattr_handlers[] = {
>>       &ubifs_user_xattr_handler,
>>       &ubifs_trusted_xattr_handler,
>>       &ubifs_security_xattr_handler,
>> +#ifdef CONFIG_UBIFS_FS_POSIX_ACL
>> +     &posix_acl_access_xattr_handler,
>> +     &posix_acl_default_xattr_handler,
>> +#endif
>>       NULL
>>  };
>>
>
> Overall the patch does not look bad and I'm sure we can add it for v4.10 soon.
> I'm a bit confused since most stuff is not really UBIFS specific.
> Andreas, is just "normal" for ACL support? I thought most code is generic and already in VFS.

There are several filesystems like ubifs that use the xattr
representation as the on-disk format, so ubifs_get_acl and
ubifs_set_acl could be abstracted and shared across those filesystems.
The rest looks good.

Thanks,
Andreas


From agruenba at redhat.com  Wed Oct 19 07:37:15 2016
From: agruenba at redhat.com (Andreas Gruenbacher)
Date: Wed, 19 Oct 2016 16:37:15 +0200
Subject: [PATCH] ubifs: implement POSIX Access Control Lists (ACLs)
In-Reply-To: <CAHc6FU7Sh3cX2NAs6bu1jBWQwwpQK0OLsLMAEZMpzocb7L5teg@mail.gmail.com>
References: <1476046382-19185-1-git-send-email-pascal.eberhard@gmail.com>
 <443b11a2-729a-32ec-0a6f-5a3276290329@nod.at>
 <CAHc6FU7Sh3cX2NAs6bu1jBWQwwpQK0OLsLMAEZMpzocb7L5teg@mail.gmail.com>
Message-ID: <CAHc6FU5pei6eLT2msMO3NV-me5SoCWf7_6y5utuCvfZHYjyiZw@mail.gmail.com>

On Wed, Oct 19, 2016 at 4:34 PM, Andreas Gruenbacher
<agruenba at redhat.com> wrote:
> Pascal,
>
> On Tue, Oct 18, 2016 at 11:32 PM, Richard Weinberger <richard at nod.at> wrote:
>> Pascal,
>>
>> On 09.10.2016 22:53, Pascal Eberhard wrote:
>>> This patch implements POSIX Access Control Lists (ACLs) in UBIFS.
>>> It uses posix_acl_(access|default)_xattr_handler ACL generic handlers
>>> as xattr handlers are now used in UBIFS.
>>
>> Cool! :)
>> CC'ing Andreas, maybe he also has comments.
>
> please run this through xfstests as well. Note the following fixes /
> improvements I've made in the course of reviewing this; they've
> obviously not been merged, yet:
>
>   https://github.com/andreas-gruenbacher/xfsprogs-dev/commits/io
>   https://github.com/andreas-gruenbacher/xfstests/commits/tmpfile
>
>>> Signed-off-by: Pascal Eberhard <pascal.eberhard at gmail.com>
>>> ---
>>>  fs/ubifs/Kconfig  |  13 +++++
>>>  fs/ubifs/Makefile |   1 +
>>>  fs/ubifs/acl.c    | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>  fs/ubifs/dir.c    |  22 +++++++++
>>>  fs/ubifs/file.c   |   9 ++++
>>>  fs/ubifs/super.c  |  15 ++++++
>>>  fs/ubifs/ubifs.h  |  18 +++++++
>>>  fs/ubifs/xattr.c  |  11 +++--
>>>  8 files changed, 229 insertions(+), 3 deletions(-)
>>>  create mode 100644 fs/ubifs/acl.c
>>>
>>> diff --git a/fs/ubifs/Kconfig b/fs/ubifs/Kconfig
>>> index 7ff7712..39119e5 100644
>>> --- a/fs/ubifs/Kconfig
>>> +++ b/fs/ubifs/Kconfig
>>> @@ -50,3 +50,16 @@ config UBIFS_ATIME_SUPPORT
>>>         strictatime is the "heavy", relatime is "lighter", etc.
>>>
>>>         If unsure, say 'N'
>>> +
>>> +config UBIFS_FS_POSIX_ACL
>>> +     bool "UBIFS POSIX Access Control Lists"
>>> +     depends on UBIFS_FS
>>> +     select FS_POSIX_ACL
>>> +     help
>>> +       POSIX Access Control Lists (ACLs) support permissions for users and
>>> +       groups beyond the owner/group/world scheme.
>>> +
>>> +       To learn more about Access Control Lists, visit the POSIX ACLs for
>>> +       Linux website <http://acl.bestbits.at/>.
>>> +
>>> +       If you don't know what Access Control Lists are, say N
>>> diff --git a/fs/ubifs/Makefile b/fs/ubifs/Makefile
>>> index c54a243..af7a83f 100644
>>> --- a/fs/ubifs/Makefile
>>> +++ b/fs/ubifs/Makefile
>>> @@ -5,3 +5,4 @@ ubifs-y += tnc.o master.o scan.o replay.o log.o commit.o gc.o orphan.o
>>>  ubifs-y += budget.o find.o tnc_commit.o compress.o lpt.o lprops.o
>>>  ubifs-y += recovery.o ioctl.o lpt_commit.o tnc_misc.o xattr.o debug.o
>>>  ubifs-y += misc.o
>>> +ubifs-$(CONFIG_UBIFS_FS_POSIX_ACL) += acl.o
>>> \ No newline at end of file
>>> diff --git a/fs/ubifs/acl.c b/fs/ubifs/acl.c
>>> new file mode 100644
>>> index 0000000..a4d4734
>>> --- /dev/null
>>> +++ b/fs/ubifs/acl.c
>>> @@ -0,0 +1,143 @@
>>> +/*
>>> + * This file is part of UBIFS.
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify it
>>> + * under the terms of the GNU General Public License version 2 as published by
>>> + * the Free Software Foundation.
>>> + *
>>> + * This program is distributed in the hope that it will be useful, but WITHOUT
>>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
>>> + * more details.
>>> + *
>>> + */
>>> +
>>> +#include <linux/fs.h>
>>
>> ubifs.h includes this already.
>>
>>> +#include <linux/xattr.h>
>>
>> Ditto.
>>
>>> +#include <linux/posix_acl_xattr.h>
>>> +
>>> +#include "ubifs.h"
>>> +
>>> +struct posix_acl *ubifs_get_acl(struct inode *inode, int type)
>>> +{
>>> +     int size;
>>> +     const char *name;
>>> +     char *value = NULL;
>>> +     struct posix_acl *acl;
>>> +
>>> +     switch (type) {
>>> +     case ACL_TYPE_ACCESS:
>>> +             name = XATTR_NAME_POSIX_ACL_ACCESS;
>>> +             break;
>>> +     case ACL_TYPE_DEFAULT:
>>> +             name = XATTR_NAME_POSIX_ACL_DEFAULT;
>>> +             break;
>>> +     default:
>>> +             return ERR_PTR(-EINVAL);
>>> +     }
>>> +
>>> +     size = __ubifs_getxattr(inode, name, NULL, 0);
>>> +     if (size > 0) {
>>> +             value = kzalloc(size, GFP_KERNEL);
>>> +             if (!value)
>>> +                     return ERR_PTR(-ENOMEM);
>>> +             size = __ubifs_getxattr(inode, name, value, size);
>>> +     }
>>> +     if (size > 0)
>>> +             acl = posix_acl_from_xattr(&init_user_ns, value, size);
>>> +     else if (size == -ERANGE || size == -ENODATA || size == 0)
>>> +             acl = NULL;
>>> +     else
>>> +             acl = ERR_PTR(size);
>>> +
>>> +     kfree(value);
>>> +     if (!IS_ERR(acl))
>>> +             set_cached_acl(inode, type, acl);
>
> The get_acl inode operation should no longer call set_cached_acl; the
> cached ACL is updated automatically. (It's correct to use
> set_cached_acl in the set_acl inode operation though.)
>
>>> +
>>> +     return acl;
>>> +}
>>> +
>>> +int ubifs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
>>> +{
>>> +     int ret;
>>> +     int size = 0;
>>> +     const char *name;
>>> +     char *value = NULL;
>>> +     int flags = 0;
>>> +
>>> +     switch (type) {
>>> +     case ACL_TYPE_ACCESS:
>>> +             name = XATTR_NAME_POSIX_ACL_ACCESS;
>>> +             if (acl) {
>>> +                     ret = posix_acl_equiv_mode(acl, &inode->i_mode);
>>> +                     if (ret < 0)
>>> +                             return ret;
>>> +                     if (ret == 0)
>>> +                             acl = NULL;
>>> +             }
>>> +             ret = 0;
>>> +             break;
>>> +     case ACL_TYPE_DEFAULT:
>>> +             if (!S_ISDIR(inode->i_mode))
>>> +                     return acl ? -EINVAL : 0;
>>> +             name = XATTR_NAME_POSIX_ACL_DEFAULT;
>>> +             break;
>>> +     default:
>>> +             return -EINVAL;
>>> +     }
>>> +
>>> +     if (acl) {
>>> +             size = posix_acl_xattr_size(acl->a_count);
>>> +             value = kmalloc(size, GFP_KERNEL);
>>> +             if (!value)
>>> +                     return -ENOMEM;
>>> +
>>> +             ret = posix_acl_to_xattr(&init_user_ns, acl, value, size);
>>> +             if (ret < 0)
>>> +                     goto out;
>>> +     }
>>> +
>>> +     if (size == 0)
>>> +             flags = XATTR_REPLACE;
>>> +     ret = __ubifs_setxattr(inode, name, value, size, flags);
>>> +
>>> +out:
>>> +     kfree(value);
>>> +     if (!ret)
>>> +             set_cached_acl(inode, type, acl);
>>> +
>>> +     return ret;
>>> +}
>>> +
>>> +/*
>>> + * Initialize the ACLs of a new inode.
>>
>> Please use the Javadoc style we use for all UBIFS functions.
>> (applies to other functions too in this patch)-
>>
>>> + */
>>> +int ubifs_init_acl(struct inode *dir, struct inode *inode)
>>> +{
>>> +     struct posix_acl *default_acl, *acl;
>>> +     int ret = 0;
>>> +
>>> +     ret = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
>>> +     if (ret)
>>> +             return ret;
>>> +
>>> +     if (default_acl) {
>>> +             inode_lock(inode);
>
> Why the inode locking here?
>
>>> +             ret = ubifs_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
>>> +             inode_unlock(inode);
>>> +             posix_acl_release(default_acl);
>>> +     }
>>> +
>>> +     if (acl) {
>>> +             if (!ret) {
>>> +                     inode_lock(inode);
>
> Same here.
>
>>> +                     ret = ubifs_set_acl(inode, acl, ACL_TYPE_ACCESS);
>>> +                     inode_unlock(inode);
>>> +             }
>>> +             posix_acl_release(acl);
>>> +     }
>>> +
>>> +     if (!default_acl && !acl)
>>> +             cache_no_acl(inode);
>
> This call to cache_no_acl doesn't make sense; please check. It may be
> wrong in btrfs as well; copying Josef for that.

Now with Josef's current email address, hopefully.

>>> +     return ret;
>>> +}
>>> diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
>>> index ccd9128..a2e5609 100644
>>> --- a/fs/ubifs/dir.c
>>> +++ b/fs/ubifs/dir.c
>>> @@ -270,6 +270,10 @@ static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
>>>               goto out_budg;
>>>       }
>>>
>>> +     err = ubifs_init_acl(dir, inode);
>>> +     if (err)
>>> +             goto out_inode;
>>> +
>
> The pattern ubifs_budget_space / ubifs_new_inode / ubifs_init_acl /
> ubifs_init_security repeats a number of times in the code, so it
> should probably be put in a function.
>
>>>       err = ubifs_init_security(dir, inode, &dentry->d_name);
>>>       if (err)
>>>               goto out_inode;
>>> @@ -341,6 +345,10 @@ static int do_tmpfile(struct inode *dir, struct dentry *dentry,
>>>               ubifs_assert(inode->i_op == &ubifs_file_inode_operations);
>>>       }
>>>
>>> +     err = ubifs_init_acl(dir, inode);
>>> +     if (err)
>>> +             goto out_inode;
>>
>> Why do we need ACLs for O_TMPFILE?
>>
>>> +
>>>       err = ubifs_init_security(dir, inode, &dentry->d_name);
>>>       if (err)
>>>               goto out_inode;
>>> @@ -821,6 +829,10 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
>>>               goto out_budg;
>>>       }
>>>
>>> +     err = ubifs_init_acl(dir, inode);
>>> +     if (err)
>>> +             goto out_inode;
>>> +
>>>       err = ubifs_init_security(dir, inode, &dentry->d_name);
>>>       if (err)
>>>               goto out_inode;
>>> @@ -903,6 +915,10 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
>>>       ui->data = dev;
>>>       ui->data_len = devlen;
>>>
>>> +     err = ubifs_init_acl(dir, inode);
>>> +     if (err)
>>> +             goto out_inode;
>>> +
>>>       err = ubifs_init_security(dir, inode, &dentry->d_name);
>>>       if (err)
>>>               goto out_inode;
>>> @@ -985,6 +1001,10 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
>>>       ui->data_len = len;
>>>       inode->i_size = ubifs_inode(inode)->ui_size = len;
>>>
>>> +     err = ubifs_init_acl(dir, inode);
>>> +     if (err)
>>> +             goto out_inode;
>>
>> Do we really need ACLs for symlinks too? I thought permissions for symlinks are irrelevant.
>>
>>>       err = ubifs_init_security(dir, inode, &dentry->d_name);
>>>       if (err)
>>>               goto out_inode;
>>> @@ -1395,6 +1415,8 @@ const struct inode_operations ubifs_dir_inode_operations = {
>>>       .update_time = ubifs_update_time,
>>>  #endif
>>>       .tmpfile     = ubifs_tmpfile,
>>> +     .get_acl     = ubifs_get_acl,
>>> +     .set_acl     = ubifs_set_acl,
>>>  };
>>>
>>>  const struct file_operations ubifs_dir_operations = {
>>> diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
>>> index 4ed270b..17f6098 100644
>>> --- a/fs/ubifs/file.c
>>> +++ b/fs/ubifs/file.c
>>> @@ -53,6 +53,7 @@
>>>  #include <linux/mount.h>
>>>  #include <linux/slab.h>
>>>  #include <linux/migrate.h>
>>> +#include <linux/posix_acl.h>
>>>
>>>  static int read_block(struct inode *inode, void *addr, unsigned int block,
>>>                     struct ubifs_data_node *dn)
>>> @@ -1251,6 +1252,10 @@ static int do_setattr(struct ubifs_info *c, struct inode *inode,
>>>               ubifs_release_budget(c, &req);
>>>       if (IS_SYNC(inode))
>>>               err = inode->i_sb->s_op->write_inode(inode, NULL);
>>> +
>>> +     if (!err && (attr->ia_valid & ATTR_MODE))
>>> +             err = posix_acl_chmod(inode, inode->i_mode);
>>> +
>>>       return err;
>>>  }
>>>
>>> @@ -1628,6 +1633,8 @@ const struct inode_operations ubifs_file_inode_operations = {
>>>  #ifdef CONFIG_UBIFS_ATIME_SUPPORT
>>>       .update_time = ubifs_update_time,
>>>  #endif
>>> +     .get_acl     = ubifs_get_acl,
>>> +     .set_acl     = ubifs_set_acl,
>>>  };
>>>
>>>  const struct inode_operations ubifs_symlink_inode_operations = {
>>> @@ -1642,6 +1649,8 @@ const struct inode_operations ubifs_symlink_inode_operations = {
>>>  #ifdef CONFIG_UBIFS_ATIME_SUPPORT
>>>       .update_time = ubifs_update_time,
>>>  #endif
>>> +     .get_acl     = ubifs_get_acl,
>>> +     .set_acl     = ubifs_set_acl,
>>>  };
>>>
>>>  const struct file_operations ubifs_file_operations = {
>>> diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
>>> index 4ec0510..8239dfd 100644
>>> --- a/fs/ubifs/super.c
>>> +++ b/fs/ubifs/super.c
>>> @@ -444,6 +444,9 @@ static int ubifs_show_options(struct seq_file *s, struct dentry *root)
>>>                          ubifs_compr_name(c->mount_opts.compr_type));
>>>       }
>>>
>>> +     if (c->vfs_sb->s_flags & MS_POSIXACL)
>>> +             seq_puts(s, ",acl");
>>> +
>>>       return 0;
>>>  }
>>>
>>> @@ -929,6 +932,8 @@ enum {
>>>       Opt_chk_data_crc,
>>>       Opt_no_chk_data_crc,
>>>       Opt_override_compr,
>>> +     Opt_acl,
>>> +     Opt_noacl,
>>>       Opt_err,
>>>  };
>>>
>>> @@ -940,6 +945,8 @@ static const match_table_t tokens = {
>>>       {Opt_chk_data_crc, "chk_data_crc"},
>>>       {Opt_no_chk_data_crc, "no_chk_data_crc"},
>>>       {Opt_override_compr, "compr=%s"},
>>> +     {Opt_acl, "acl"},
>>> +     {Opt_noacl, "noacl"},
>>>       {Opt_err, NULL},
>>>  };
>>>
>>> @@ -1040,6 +1047,14 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options,
>>>                       c->default_compr = c->mount_opts.compr_type;
>>>                       break;
>>>               }
>>> +#ifdef CONFIG_UBIFS_FS_POSIX_ACL
>>> +             case Opt_acl:
>>> +                     c->vfs_sb->s_flags |= MS_POSIXACL;
>>> +                     break;
>>> +             case Opt_noacl:
>>> +                     c->vfs_sb->s_flags &= ~MS_POSIXACL;
>>> +                     break;
>>> +#endif
>>>               default:
>>>               {
>>>                       unsigned long flag;
>>> diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
>>> index 096035e..7935449 100644
>>> --- a/fs/ubifs/ubifs.h
>>> +++ b/fs/ubifs/ubifs.h
>>> @@ -1743,6 +1743,24 @@ extern const struct xattr_handler *ubifs_xattr_handlers[];
>>>  ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size);
>>>  int ubifs_init_security(struct inode *dentry, struct inode *inode,
>>>                       const struct qstr *qstr);
>>> +ssize_t __ubifs_getxattr(struct inode *host, const char *name,
>>> +                             void *buf, size_t size);
>>> +int __ubifs_setxattr(struct inode *host, const char *name,
>>> +                         const void *value, size_t size, int flags);
>>> +
>>> +/* acl.c */
>>> +#ifdef CONFIG_UBIFS_FS_POSIX_ACL
>>> +int ubifs_init_acl(struct inode *dir, struct inode *inode);
>>> +int ubifs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
>>> +struct posix_acl *ubifs_get_acl(struct inode *inode, int type);
>>> +#else
>>> +static inline int ubifs_init_acl(struct inode *inode, struct inode *dir)
>>> +{
>>> +     return 0;
>>> +}
>>> +#define ubifs_get_acl NULL
>>> +#define ubifs_set_acl NULL
>>> +#endif
>>>
>>>  /* super.c */
>>>  struct inode *ubifs_iget(struct super_block *sb, unsigned long inum);
>>> diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c
>>> index 6c2f4d4..0a596a1 100644
>>> --- a/fs/ubifs/xattr.c
>>> +++ b/fs/ubifs/xattr.c
>>> @@ -52,13 +52,14 @@
>>>   * in the VFS inode cache. The xentries are cached in the LNC cache (see
>>>   * tnc.c).
>>>   *
>>> - * ACL support is not implemented.
>>> + * ACL support is now implemented.
>>
>> I think we can just drop that line now. :-)
>>
>>>   */
>>>
>>>  #include "ubifs.h"
>>>  #include <linux/fs.h>
>>>  #include <linux/slab.h>
>>>  #include <linux/xattr.h>
>>> +#include <linux/posix_acl_xattr.h>
>>
>> While we are here, these includes should also be cleaned up.
>>
>>>  /*
>>>   * Limit the number of extended attributes per inode so that the total size
>>> @@ -268,7 +269,7 @@ static struct inode *iget_xattr(struct ubifs_info *c, ino_t inum)
>>>       return ERR_PTR(-EINVAL);
>>>  }
>>>
>>> -static int __ubifs_setxattr(struct inode *host, const char *name,
>>> +int __ubifs_setxattr(struct inode *host, const char *name,
>>>                           const void *value, size_t size, int flags)
>>>  {
>>>       struct inode *inode;
>>> @@ -328,7 +329,7 @@ out_free:
>>>       return err;
>>>  }
>>>
>>> -static ssize_t __ubifs_getxattr(struct inode *host, const char *name,
>>> +ssize_t __ubifs_getxattr(struct inode *host, const char *name,
>>>                               void *buf, size_t size)
>>>  {
>>>       struct inode *inode;
>>> @@ -619,5 +620,9 @@ const struct xattr_handler *ubifs_xattr_handlers[] = {
>>>       &ubifs_user_xattr_handler,
>>>       &ubifs_trusted_xattr_handler,
>>>       &ubifs_security_xattr_handler,
>>> +#ifdef CONFIG_UBIFS_FS_POSIX_ACL
>>> +     &posix_acl_access_xattr_handler,
>>> +     &posix_acl_default_xattr_handler,
>>> +#endif
>>>       NULL
>>>  };
>>>
>>
>> Overall the patch does not look bad and I'm sure we can add it for v4.10 soon.
>> I'm a bit confused since most stuff is not really UBIFS specific.
>> Andreas, is just "normal" for ACL support? I thought most code is generic and already in VFS.
>
> There are several filesystems like ubifs that use the xattr
> representation as the on-disk format, so ubifs_get_acl and
> ubifs_set_acl could be abstracted and shared across those filesystems.
> The rest looks good.
>
> Thanks,
> Andreas


From jbacik at fb.com  Wed Oct 19 07:51:02 2016
From: jbacik at fb.com (Josef Bacik)
Date: Wed, 19 Oct 2016 10:51:02 -0400
Subject: [PATCH] ubifs: implement POSIX Access Control Lists (ACLs)
In-Reply-To: <CAHc6FU5pei6eLT2msMO3NV-me5SoCWf7_6y5utuCvfZHYjyiZw@mail.gmail.com>
References: <1476046382-19185-1-git-send-email-pascal.eberhard@gmail.com>
 <443b11a2-729a-32ec-0a6f-5a3276290329@nod.at>
 <CAHc6FU7Sh3cX2NAs6bu1jBWQwwpQK0OLsLMAEZMpzocb7L5teg@mail.gmail.com>
 <CAHc6FU5pei6eLT2msMO3NV-me5SoCWf7_6y5utuCvfZHYjyiZw@mail.gmail.com>
Message-ID: <8970b7a5-eea0-921b-16ff-6cf53df52f85@fb.com>

On 10/19/2016 10:37 AM, Andreas Gruenbacher wrote:
> On Wed, Oct 19, 2016 at 4:34 PM, Andreas Gruenbacher
> <agruenba at redhat.com> wrote:
>> Pascal,
>>
>> On Tue, Oct 18, 2016 at 11:32 PM, Richard Weinberger <richard at nod.at> wrote:
>>> Pascal,
>>>
>>> On 09.10.2016 22:53, Pascal Eberhard wrote:
>>>> This patch implements POSIX Access Control Lists (ACLs) in UBIFS.
>>>> It uses posix_acl_(access|default)_xattr_handler ACL generic handlers
>>>> as xattr handlers are now used in UBIFS.
>>>
>>> Cool! :)
>>> CC'ing Andreas, maybe he also has comments.
>>
>> please run this through xfstests as well. Note the following fixes /
>> improvements I've made in the course of reviewing this; they've
>> obviously not been merged, yet:
>>
>>   https://github.com/andreas-gruenbacher/xfsprogs-dev/commits/io
>>   https://github.com/andreas-gruenbacher/xfstests/commits/tmpfile
>>
>>>> Signed-off-by: Pascal Eberhard <pascal.eberhard at gmail.com>
>>>> ---
>>>>  fs/ubifs/Kconfig  |  13 +++++
>>>>  fs/ubifs/Makefile |   1 +
>>>>  fs/ubifs/acl.c    | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>>  fs/ubifs/dir.c    |  22 +++++++++
>>>>  fs/ubifs/file.c   |   9 ++++
>>>>  fs/ubifs/super.c  |  15 ++++++
>>>>  fs/ubifs/ubifs.h  |  18 +++++++
>>>>  fs/ubifs/xattr.c  |  11 +++--
>>>>  8 files changed, 229 insertions(+), 3 deletions(-)
>>>>  create mode 100644 fs/ubifs/acl.c
>>>>
>>>> diff --git a/fs/ubifs/Kconfig b/fs/ubifs/Kconfig
>>>> index 7ff7712..39119e5 100644
>>>> --- a/fs/ubifs/Kconfig
>>>> +++ b/fs/ubifs/Kconfig
>>>> @@ -50,3 +50,16 @@ config UBIFS_ATIME_SUPPORT
>>>>         strictatime is the "heavy", relatime is "lighter", etc.
>>>>
>>>>         If unsure, say 'N'
>>>> +
>>>> +config UBIFS_FS_POSIX_ACL
>>>> +     bool "UBIFS POSIX Access Control Lists"
>>>> +     depends on UBIFS_FS
>>>> +     select FS_POSIX_ACL
>>>> +     help
>>>> +       POSIX Access Control Lists (ACLs) support permissions for users and
>>>> +       groups beyond the owner/group/world scheme.
>>>> +
>>>> +       To learn more about Access Control Lists, visit the POSIX ACLs for
>>>> +       Linux website <https://urldefense.proofpoint.com/v2/url?u=http-3A__acl.bestbits.at_&d=DQIBaQ&c=5VD0RTtNlTh3ycd41b3MUw&r=sDzg6MvHymKOUgI8SFIm4Q&m=kMcqxODxmAbECYcLW6bRou3Q-jJYfAL4HPw5ErTumUU&s=De0Qb4gRiGITbgivfS5NKW92fL7-HKCGNvCnAMU6CwM&e= >.
>>>> +
>>>> +       If you don't know what Access Control Lists are, say N
>>>> diff --git a/fs/ubifs/Makefile b/fs/ubifs/Makefile
>>>> index c54a243..af7a83f 100644
>>>> --- a/fs/ubifs/Makefile
>>>> +++ b/fs/ubifs/Makefile
>>>> @@ -5,3 +5,4 @@ ubifs-y += tnc.o master.o scan.o replay.o log.o commit.o gc.o orphan.o
>>>>  ubifs-y += budget.o find.o tnc_commit.o compress.o lpt.o lprops.o
>>>>  ubifs-y += recovery.o ioctl.o lpt_commit.o tnc_misc.o xattr.o debug.o
>>>>  ubifs-y += misc.o
>>>> +ubifs-$(CONFIG_UBIFS_FS_POSIX_ACL) += acl.o
>>>> \ No newline at end of file
>>>> diff --git a/fs/ubifs/acl.c b/fs/ubifs/acl.c
>>>> new file mode 100644
>>>> index 0000000..a4d4734
>>>> --- /dev/null
>>>> +++ b/fs/ubifs/acl.c
>>>> @@ -0,0 +1,143 @@
>>>> +/*
>>>> + * This file is part of UBIFS.
>>>> + *
>>>> + * This program is free software; you can redistribute it and/or modify it
>>>> + * under the terms of the GNU General Public License version 2 as published by
>>>> + * the Free Software Foundation.
>>>> + *
>>>> + * This program is distributed in the hope that it will be useful, but WITHOUT
>>>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>>>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
>>>> + * more details.
>>>> + *
>>>> + */
>>>> +
>>>> +#include <linux/fs.h>
>>>
>>> ubifs.h includes this already.
>>>
>>>> +#include <linux/xattr.h>
>>>
>>> Ditto.
>>>
>>>> +#include <linux/posix_acl_xattr.h>
>>>> +
>>>> +#include "ubifs.h"
>>>> +
>>>> +struct posix_acl *ubifs_get_acl(struct inode *inode, int type)
>>>> +{
>>>> +     int size;
>>>> +     const char *name;
>>>> +     char *value = NULL;
>>>> +     struct posix_acl *acl;
>>>> +
>>>> +     switch (type) {
>>>> +     case ACL_TYPE_ACCESS:
>>>> +             name = XATTR_NAME_POSIX_ACL_ACCESS;
>>>> +             break;
>>>> +     case ACL_TYPE_DEFAULT:
>>>> +             name = XATTR_NAME_POSIX_ACL_DEFAULT;
>>>> +             break;
>>>> +     default:
>>>> +             return ERR_PTR(-EINVAL);
>>>> +     }
>>>> +
>>>> +     size = __ubifs_getxattr(inode, name, NULL, 0);
>>>> +     if (size > 0) {
>>>> +             value = kzalloc(size, GFP_KERNEL);
>>>> +             if (!value)
>>>> +                     return ERR_PTR(-ENOMEM);
>>>> +             size = __ubifs_getxattr(inode, name, value, size);
>>>> +     }
>>>> +     if (size > 0)
>>>> +             acl = posix_acl_from_xattr(&init_user_ns, value, size);
>>>> +     else if (size == -ERANGE || size == -ENODATA || size == 0)
>>>> +             acl = NULL;
>>>> +     else
>>>> +             acl = ERR_PTR(size);
>>>> +
>>>> +     kfree(value);
>>>> +     if (!IS_ERR(acl))
>>>> +             set_cached_acl(inode, type, acl);
>>
>> The get_acl inode operation should no longer call set_cached_acl; the
>> cached ACL is updated automatically. (It's correct to use
>> set_cached_acl in the set_acl inode operation though.)
>>
>>>> +
>>>> +     return acl;
>>>> +}
>>>> +
>>>> +int ubifs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
>>>> +{
>>>> +     int ret;
>>>> +     int size = 0;
>>>> +     const char *name;
>>>> +     char *value = NULL;
>>>> +     int flags = 0;
>>>> +
>>>> +     switch (type) {
>>>> +     case ACL_TYPE_ACCESS:
>>>> +             name = XATTR_NAME_POSIX_ACL_ACCESS;
>>>> +             if (acl) {
>>>> +                     ret = posix_acl_equiv_mode(acl, &inode->i_mode);
>>>> +                     if (ret < 0)
>>>> +                             return ret;
>>>> +                     if (ret == 0)
>>>> +                             acl = NULL;
>>>> +             }
>>>> +             ret = 0;
>>>> +             break;
>>>> +     case ACL_TYPE_DEFAULT:
>>>> +             if (!S_ISDIR(inode->i_mode))
>>>> +                     return acl ? -EINVAL : 0;
>>>> +             name = XATTR_NAME_POSIX_ACL_DEFAULT;
>>>> +             break;
>>>> +     default:
>>>> +             return -EINVAL;
>>>> +     }
>>>> +
>>>> +     if (acl) {
>>>> +             size = posix_acl_xattr_size(acl->a_count);
>>>> +             value = kmalloc(size, GFP_KERNEL);
>>>> +             if (!value)
>>>> +                     return -ENOMEM;
>>>> +
>>>> +             ret = posix_acl_to_xattr(&init_user_ns, acl, value, size);
>>>> +             if (ret < 0)
>>>> +                     goto out;
>>>> +     }
>>>> +
>>>> +     if (size == 0)
>>>> +             flags = XATTR_REPLACE;
>>>> +     ret = __ubifs_setxattr(inode, name, value, size, flags);
>>>> +
>>>> +out:
>>>> +     kfree(value);
>>>> +     if (!ret)
>>>> +             set_cached_acl(inode, type, acl);
>>>> +
>>>> +     return ret;
>>>> +}
>>>> +
>>>> +/*
>>>> + * Initialize the ACLs of a new inode.
>>>
>>> Please use the Javadoc style we use for all UBIFS functions.
>>> (applies to other functions too in this patch)-
>>>
>>>> + */
>>>> +int ubifs_init_acl(struct inode *dir, struct inode *inode)
>>>> +{
>>>> +     struct posix_acl *default_acl, *acl;
>>>> +     int ret = 0;
>>>> +
>>>> +     ret = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
>>>> +     if (ret)
>>>> +             return ret;
>>>> +
>>>> +     if (default_acl) {
>>>> +             inode_lock(inode);
>>
>> Why the inode locking here?
>>
>>>> +             ret = ubifs_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
>>>> +             inode_unlock(inode);
>>>> +             posix_acl_release(default_acl);
>>>> +     }
>>>> +
>>>> +     if (acl) {
>>>> +             if (!ret) {
>>>> +                     inode_lock(inode);
>>
>> Same here.
>>
>>>> +                     ret = ubifs_set_acl(inode, acl, ACL_TYPE_ACCESS);
>>>> +                     inode_unlock(inode);
>>>> +             }
>>>> +             posix_acl_release(acl);
>>>> +     }
>>>> +
>>>> +     if (!default_acl && !acl)
>>>> +             cache_no_acl(inode);
>>
>> This call to cache_no_acl doesn't make sense; please check. It may be
>> wrong in btrfs as well; copying Josef for that.
>
> Now with Josef's current email address, hopefully.
>

Looks right to me, we call this during inode creation, so if there is no ACL to 
set then we cache no acl so we don't waste the lookup later.  Thanks,

Josef



From narmstrong at baylibre.com  Wed Oct 19 07:55:23 2016
From: narmstrong at baylibre.com (Neil Armstrong)
Date: Wed, 19 Oct 2016 16:55:23 +0200
Subject: [PATCH] mtd: nand: Add OX820 NAND Support
Message-ID: <20161019145523.6763-1-narmstrong@baylibre.com>

Add NAND driver to support the Oxford Semiconductor OX820 NAND Controller.
This is a simple memory mapped NAND controller with single chip select and
software ECC.

Signed-off-by: Neil Armstrong <narmstrong at baylibre.com>
---
 .../devicetree/bindings/mtd/oxnas-nand.txt         |  24 +++
 drivers/mtd/nand/Kconfig                           |   5 +
 drivers/mtd/nand/Makefile                          |   1 +
 drivers/mtd/nand/oxnas_nand.c                      | 204 +++++++++++++++++++++
 4 files changed, 234 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/oxnas-nand.txt
 create mode 100644 drivers/mtd/nand/oxnas_nand.c

Changes since RFC http://lkml.kernel.org/r/20161018090927.1990-1-narmstrong at baylibre.com :
 - Avoid using chip->IO_ADDR*
 - Use new DT structure
 - Assign a chip for the subnode
 - Use the nand_hw_control structure
 - Cleanup probe
 - Cleanup cmd_ctrl by using a context ctrl offset used in write_bytes

diff --git a/Documentation/devicetree/bindings/mtd/oxnas-nand.txt b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
new file mode 100644
index 0000000..83b684d
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
@@ -0,0 +1,24 @@
+* Oxford Semiconductor OXNAS NAND Controller
+
+Please refer to nand.txt for generic information regarding MTD NAND bindings.
+
+Required properties:
+ - compatible: "oxsemi,ox820-nand"
+ - reg: Base address and length for NAND mapped memory.
+
+Optional Properties:
+ - clocks: phandle to the NAND gate clock if needed.
+ - resets: phandle to the NAND reset control if needed.
+
+Example:
+
+nand: nand at 41000000 {
+	compatible = "oxsemi,ox820-nand";
+	reg = <0x41000000 0x100000>;
+	nand-ecc-mode = "soft";
+	clocks = <&stdclk CLK_820_NAND>;
+	resets = <&reset RESET_NAND>;
+	#address-cells = <1>;
+	#size-cells = <1>;
+	status = "disabled";
+};
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 7b7a887..c023125 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -426,6 +426,11 @@ config MTD_NAND_ORION
 	  No board specific support is done by this driver, each board
 	  must advertise a platform_device for the driver to attach.
 
+config MTD_NAND_OXNAS
+	tristate "NAND Flash support for Oxford Semiconductor SoC"
+	help
+	  This enables the NAND flash controller on Oxford Semiconductor SoCs.
+
 config MTD_NAND_FSL_ELBC
 	tristate "NAND support for Freescale eLBC controllers"
 	depends on FSL_SOC
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index cafde6f..05fc054 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_MTD_NAND_TMIO)		+= tmio_nand.o
 obj-$(CONFIG_MTD_NAND_PLATFORM)		+= plat_nand.o
 obj-$(CONFIG_MTD_NAND_PASEMI)		+= pasemi_nand.o
 obj-$(CONFIG_MTD_NAND_ORION)		+= orion_nand.o
+obj-$(CONFIG_MTD_NAND_OXNAS)		+= oxnas_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_ELBC)		+= fsl_elbc_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_IFC)		+= fsl_ifc_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_UPM)		+= fsl_upm.o
diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/oxnas_nand.c
new file mode 100644
index 0000000..a9fe1ac
--- /dev/null
+++ b/drivers/mtd/nand/oxnas_nand.c
@@ -0,0 +1,204 @@
+/*
+ * Oxford Semiconductor OXNAS NAND driver
+
+ * Copyright (C) 2016 Neil Armstrong <narmstrong at baylibre.com>
+ * Heavily based on plat_nand.c :
+ * Author: Vitaly Wool <vitalywool at gmail.com>
+ * Copyright (C) 2013 Ma Haijun <mahaijuns at gmail.com>
+ * Copyright (C) 2012 John Crispin <blogic at openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/reset.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of.h>
+
+/* Nand commands */
+#define OXNAS_NAND_CMD_ALE		BIT(18)
+#define OXNAS_NAND_CMD_CLE		BIT(19)
+
+#define OXNAS_NAND_MAX_CHIPS	1
+
+struct oxnas_nand {
+	struct nand_hw_control base;
+	void __iomem *io_base;
+	struct clk *clk;
+	struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS];
+	unsigned long ctrl;
+};
+
+static uint8_t oxnas_nand_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct oxnas_nand *oxnas = nand_get_controller_data(chip);
+
+	return readb(oxnas->io_base);
+}
+
+static void oxnas_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct oxnas_nand *oxnas = nand_get_controller_data(chip);
+
+	ioread8_rep(oxnas->io_base, buf, len);
+}
+
+static void oxnas_nand_write_buf(struct mtd_info *mtd,
+				 const uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct oxnas_nand *oxnas = nand_get_controller_data(chip);
+
+	iowrite8_rep(oxnas->io_base + oxnas->ctrl, buf, len);
+}
+
+/* Single CS command control */
+static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+				unsigned int ctrl)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct oxnas_nand *oxnas = nand_get_controller_data(chip);
+
+	if (ctrl & NAND_CTRL_CHANGE) {
+		if (ctrl & NAND_CLE)
+			oxnas->ctrl = OXNAS_NAND_CMD_CLE;
+		else if (ctrl & NAND_ALE)
+			oxnas->ctrl = OXNAS_NAND_CMD_ALE;
+		else
+			oxnas->ctrl = 0;
+	}
+
+	if (cmd != NAND_CMD_NONE)
+		writeb(cmd, oxnas->io_base + oxnas->ctrl);
+}
+
+/*
+ * Probe for the NAND device.
+ */
+static int oxnas_nand_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *nand_np;
+	struct oxnas_nand *oxnas;
+	struct nand_chip *chip;
+	struct mtd_info *mtd;
+	struct resource *res;
+	int nchips = 0;
+	int count = 0;
+	int err = 0;
+
+	/* Allocate memory for the device structure (and zero it) */
+	oxnas = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip),
+			    GFP_KERNEL);
+	if (!oxnas)
+		return -ENOMEM;
+
+	nand_hw_control_init(&oxnas->base);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	oxnas->io_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(oxnas->io_base))
+		return PTR_ERR(oxnas->io_base);
+
+	oxnas->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(oxnas->clk))
+		oxnas->clk = NULL;
+
+	/* Only a single chip node is supported */
+	count = of_get_child_count(np);
+	if (count > 1)
+		return -EINVAL;
+
+	clk_prepare_enable(oxnas->clk);
+	device_reset_optional(&pdev->dev);
+
+	for_each_child_of_node(np, nand_np) {
+		chip = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip),
+				    GFP_KERNEL);
+		if (!chip)
+			return -ENOMEM;
+
+		chip->controller = &oxnas->base;
+
+		nand_set_flash_node(chip, nand_np);
+		nand_set_controller_data(chip, oxnas);
+
+		mtd = nand_to_mtd(chip);
+		mtd->dev.parent = &pdev->dev;
+		mtd->priv = chip;
+
+		chip->cmd_ctrl = oxnas_nand_cmd_ctrl;
+		chip->read_buf = oxnas_nand_read_buf;
+		chip->read_byte = oxnas_nand_read_byte;
+		chip->write_buf = oxnas_nand_write_buf;
+		chip->chip_delay = 30;
+
+		/* Scan to find existence of the device */
+		err = nand_scan(mtd, 1);
+		if (err)
+			return err;
+
+		err = mtd_device_register(mtd, NULL, 0);
+		if (err) {
+			nand_release(mtd);
+			return err;
+		}
+
+		oxnas->chips[nchips] = chip;
+		++nchips;
+	}
+
+	/* Exit if no chips found */
+	if (!nchips)
+		return -ENODEV;
+
+	platform_set_drvdata(pdev, oxnas);
+
+	return 0;
+}
+
+static int oxnas_nand_remove(struct platform_device *pdev)
+{
+	struct oxnas_nand *oxnas = platform_get_drvdata(pdev);
+
+	if (oxnas->chips[0])
+		nand_release(nand_to_mtd(oxnas->chips[0]));
+
+	clk_disable_unprepare(oxnas->clk);
+
+	return 0;
+}
+
+static const struct of_device_id oxnas_nand_match[] = {
+	{ .compatible = "oxsemi,ox820-nand" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, oxnas_nand_match);
+
+static struct platform_driver oxnas_nand_driver = {
+	.probe	= oxnas_nand_probe,
+	.remove	= oxnas_nand_remove,
+	.driver	= {
+		.name		= "oxnas_nand",
+		.of_match_table = oxnas_nand_match,
+	},
+};
+
+module_platform_driver(oxnas_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Neil Armstrong <narmstrong at baylibre.com>");
+MODULE_DESCRIPTION("Oxnas NAND driver");
+MODULE_ALIAS("platform:oxnas_nand");
-- 
2.7.0



From agruenba at redhat.com  Wed Oct 19 08:05:19 2016
From: agruenba at redhat.com (Andreas Gruenbacher)
Date: Wed, 19 Oct 2016 17:05:19 +0200
Subject: [PATCH] ubifs: implement POSIX Access Control Lists (ACLs)
In-Reply-To: <8970b7a5-eea0-921b-16ff-6cf53df52f85@fb.com>
References: <1476046382-19185-1-git-send-email-pascal.eberhard@gmail.com>
 <443b11a2-729a-32ec-0a6f-5a3276290329@nod.at>
 <CAHc6FU7Sh3cX2NAs6bu1jBWQwwpQK0OLsLMAEZMpzocb7L5teg@mail.gmail.com>
 <CAHc6FU5pei6eLT2msMO3NV-me5SoCWf7_6y5utuCvfZHYjyiZw@mail.gmail.com>
 <8970b7a5-eea0-921b-16ff-6cf53df52f85@fb.com>
Message-ID: <CAHc6FU7qGhpNPNncav+R-zxim5wyPAtK72uEtTU65-hVcNxEhw@mail.gmail.com>

On Wed, Oct 19, 2016 at 4:51 PM, Josef Bacik <jbacik at fb.com> wrote:
> Looks right to me, we call this during inode creation, so if there is no ACL
> to set then we cache no acl so we don't waste the lookup later.

This is when we create an new inode, so neither i_acl nor
i_default_acl should be ACL_NOT_CACHED when this function succeeds. So
either we should make sure that i_acl and i_default_acl are already
not set to ACL_NOT_CACHED anymore when entering this function, or
cache_no_acl should be called unconditionally before setting the
actual ACLs.

Thanks,
Andreas


From narmstrong at baylibre.com  Wed Oct 19 08:30:38 2016
From: narmstrong at baylibre.com (Neil Armstrong)
Date: Wed, 19 Oct 2016 17:30:38 +0200
Subject: [PATCH] mtd: nand: Add OX820 NAND Support
In-Reply-To: <20161019145523.6763-1-narmstrong@baylibre.com>
References: <20161019145523.6763-1-narmstrong@baylibre.com>
Message-ID: <12212beb-d152-9b49-3c06-227956e84207@baylibre.com>

On 10/19/2016 04:55 PM, Neil Armstrong wrote:
> Add NAND driver to support the Oxford Semiconductor OX820 NAND Controller.
> This is a simple memory mapped NAND controller with single chip select and
> software ECC.
> 
> Signed-off-by: Neil Armstrong <narmstrong at baylibre.com>

Forgot
Acked-by: Rob Herring <robh at kernel.org>

Will add in v2 if a respin is needed.

> ---
>  .../devicetree/bindings/mtd/oxnas-nand.txt         |  24 +++
>  drivers/mtd/nand/Kconfig                           |   5 +
>  drivers/mtd/nand/Makefile                          |   1 +
>  drivers/mtd/nand/oxnas_nand.c                      | 204 +++++++++++++++++++++
>  4 files changed, 234 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mtd/oxnas-nand.txt
>  create mode 100644 drivers/mtd/nand/oxnas_nand.c
> 
> Changes since RFC http://lkml.kernel.org/r/20161018090927.1990-1-narmstrong at baylibre.com :
>  - Avoid using chip->IO_ADDR*
>  - Use new DT structure
>  - Assign a chip for the subnode
>  - Use the nand_hw_control structure
>  - Cleanup probe
>  - Cleanup cmd_ctrl by using a context ctrl offset used in write_bytes
> 
> diff --git a/Documentation/devicetree/bindings/mtd/oxnas-nand.txt b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
> new file mode 100644
> index 0000000..83b684d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
> @@ -0,0 +1,24 @@
> +* Oxford Semiconductor OXNAS NAND Controller
> +
> +Please refer to nand.txt for generic information regarding MTD NAND bindings.
> +
> +Required properties:
> + - compatible: "oxsemi,ox820-nand"
> + - reg: Base address and length for NAND mapped memory.
> +
> +Optional Properties:
> + - clocks: phandle to the NAND gate clock if needed.
> + - resets: phandle to the NAND reset control if needed.
> +
> +Example:
> +
> +nand: nand at 41000000 {
> +	compatible = "oxsemi,ox820-nand";
> +	reg = <0x41000000 0x100000>;
> +	nand-ecc-mode = "soft";
> +	clocks = <&stdclk CLK_820_NAND>;
> +	resets = <&reset RESET_NAND>;
> +	#address-cells = <1>;
> +	#size-cells = <1>;
> +	status = "disabled";
> +};
> diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
> index 7b7a887..c023125 100644
> --- a/drivers/mtd/nand/Kconfig
> +++ b/drivers/mtd/nand/Kconfig
> @@ -426,6 +426,11 @@ config MTD_NAND_ORION
>  	  No board specific support is done by this driver, each board
>  	  must advertise a platform_device for the driver to attach.
>  
> +config MTD_NAND_OXNAS
> +	tristate "NAND Flash support for Oxford Semiconductor SoC"
> +	help
> +	  This enables the NAND flash controller on Oxford Semiconductor SoCs.
> +
>  config MTD_NAND_FSL_ELBC
>  	tristate "NAND support for Freescale eLBC controllers"
>  	depends on FSL_SOC
> diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
> index cafde6f..05fc054 100644
> --- a/drivers/mtd/nand/Makefile
> +++ b/drivers/mtd/nand/Makefile
> @@ -35,6 +35,7 @@ obj-$(CONFIG_MTD_NAND_TMIO)		+= tmio_nand.o
>  obj-$(CONFIG_MTD_NAND_PLATFORM)		+= plat_nand.o
>  obj-$(CONFIG_MTD_NAND_PASEMI)		+= pasemi_nand.o
>  obj-$(CONFIG_MTD_NAND_ORION)		+= orion_nand.o
> +obj-$(CONFIG_MTD_NAND_OXNAS)		+= oxnas_nand.o
>  obj-$(CONFIG_MTD_NAND_FSL_ELBC)		+= fsl_elbc_nand.o
>  obj-$(CONFIG_MTD_NAND_FSL_IFC)		+= fsl_ifc_nand.o
>  obj-$(CONFIG_MTD_NAND_FSL_UPM)		+= fsl_upm.o
> diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/oxnas_nand.c
> new file mode 100644
> index 0000000..a9fe1ac
> --- /dev/null
> +++ b/drivers/mtd/nand/oxnas_nand.c
> @@ -0,0 +1,204 @@
> +/*
> + * Oxford Semiconductor OXNAS NAND driver
> +
> + * Copyright (C) 2016 Neil Armstrong <narmstrong at baylibre.com>
> + * Heavily based on plat_nand.c :
> + * Author: Vitaly Wool <vitalywool at gmail.com>
> + * Copyright (C) 2013 Ma Haijun <mahaijuns at gmail.com>
> + * Copyright (C) 2012 John Crispin <blogic at openwrt.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/clk.h>
> +#include <linux/reset.h>
> +#include <linux/mtd/mtd.h>
> +#include <linux/mtd/nand.h>
> +#include <linux/mtd/partitions.h>
> +#include <linux/of.h>
> +
> +/* Nand commands */
> +#define OXNAS_NAND_CMD_ALE		BIT(18)
> +#define OXNAS_NAND_CMD_CLE		BIT(19)
> +
> +#define OXNAS_NAND_MAX_CHIPS	1
> +
> +struct oxnas_nand {
> +	struct nand_hw_control base;
> +	void __iomem *io_base;
> +	struct clk *clk;
> +	struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS];
> +	unsigned long ctrl;
> +};
> +
> +static uint8_t oxnas_nand_read_byte(struct mtd_info *mtd)
> +{
> +	struct nand_chip *chip = mtd_to_nand(mtd);
> +	struct oxnas_nand *oxnas = nand_get_controller_data(chip);
> +
> +	return readb(oxnas->io_base);
> +}
> +
> +static void oxnas_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
> +{
> +	struct nand_chip *chip = mtd_to_nand(mtd);
> +	struct oxnas_nand *oxnas = nand_get_controller_data(chip);
> +
> +	ioread8_rep(oxnas->io_base, buf, len);
> +}
> +
> +static void oxnas_nand_write_buf(struct mtd_info *mtd,
> +				 const uint8_t *buf, int len)
> +{
> +	struct nand_chip *chip = mtd_to_nand(mtd);
> +	struct oxnas_nand *oxnas = nand_get_controller_data(chip);
> +
> +	iowrite8_rep(oxnas->io_base + oxnas->ctrl, buf, len);
> +}
> +
> +/* Single CS command control */
> +static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
> +				unsigned int ctrl)
> +{
> +	struct nand_chip *chip = mtd_to_nand(mtd);
> +	struct oxnas_nand *oxnas = nand_get_controller_data(chip);
> +
> +	if (ctrl & NAND_CTRL_CHANGE) {
> +		if (ctrl & NAND_CLE)
> +			oxnas->ctrl = OXNAS_NAND_CMD_CLE;
> +		else if (ctrl & NAND_ALE)
> +			oxnas->ctrl = OXNAS_NAND_CMD_ALE;
> +		else
> +			oxnas->ctrl = 0;
> +	}
> +
> +	if (cmd != NAND_CMD_NONE)
> +		writeb(cmd, oxnas->io_base + oxnas->ctrl);
> +}
> +
> +/*
> + * Probe for the NAND device.
> + */
> +static int oxnas_nand_probe(struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	struct device_node *nand_np;
> +	struct oxnas_nand *oxnas;
> +	struct nand_chip *chip;
> +	struct mtd_info *mtd;
> +	struct resource *res;
> +	int nchips = 0;
> +	int count = 0;
> +	int err = 0;
> +
> +	/* Allocate memory for the device structure (and zero it) */
> +	oxnas = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip),
> +			    GFP_KERNEL);
> +	if (!oxnas)
> +		return -ENOMEM;
> +
> +	nand_hw_control_init(&oxnas->base);
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	oxnas->io_base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(oxnas->io_base))
> +		return PTR_ERR(oxnas->io_base);
> +
> +	oxnas->clk = devm_clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(oxnas->clk))
> +		oxnas->clk = NULL;
> +
> +	/* Only a single chip node is supported */
> +	count = of_get_child_count(np);
> +	if (count > 1)
> +		return -EINVAL;
> +
> +	clk_prepare_enable(oxnas->clk);
> +	device_reset_optional(&pdev->dev);
> +
> +	for_each_child_of_node(np, nand_np) {
> +		chip = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip),
> +				    GFP_KERNEL);
> +		if (!chip)
> +			return -ENOMEM;
> +
> +		chip->controller = &oxnas->base;
> +
> +		nand_set_flash_node(chip, nand_np);
> +		nand_set_controller_data(chip, oxnas);
> +
> +		mtd = nand_to_mtd(chip);
> +		mtd->dev.parent = &pdev->dev;
> +		mtd->priv = chip;
> +
> +		chip->cmd_ctrl = oxnas_nand_cmd_ctrl;
> +		chip->read_buf = oxnas_nand_read_buf;
> +		chip->read_byte = oxnas_nand_read_byte;
> +		chip->write_buf = oxnas_nand_write_buf;
> +		chip->chip_delay = 30;
> +
> +		/* Scan to find existence of the device */
> +		err = nand_scan(mtd, 1);
> +		if (err)
> +			return err;
> +
> +		err = mtd_device_register(mtd, NULL, 0);
> +		if (err) {
> +			nand_release(mtd);
> +			return err;
> +		}
> +
> +		oxnas->chips[nchips] = chip;
> +		++nchips;
> +	}
> +
> +	/* Exit if no chips found */
> +	if (!nchips)
> +		return -ENODEV;
> +
> +	platform_set_drvdata(pdev, oxnas);
> +
> +	return 0;
> +}
> +
> +static int oxnas_nand_remove(struct platform_device *pdev)
> +{
> +	struct oxnas_nand *oxnas = platform_get_drvdata(pdev);
> +
> +	if (oxnas->chips[0])
> +		nand_release(nand_to_mtd(oxnas->chips[0]));
> +
> +	clk_disable_unprepare(oxnas->clk);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id oxnas_nand_match[] = {
> +	{ .compatible = "oxsemi,ox820-nand" },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, oxnas_nand_match);
> +
> +static struct platform_driver oxnas_nand_driver = {
> +	.probe	= oxnas_nand_probe,
> +	.remove	= oxnas_nand_remove,
> +	.driver	= {
> +		.name		= "oxnas_nand",
> +		.of_match_table = oxnas_nand_match,
> +	},
> +};
> +
> +module_platform_driver(oxnas_nand_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Neil Armstrong <narmstrong at baylibre.com>");
> +MODULE_DESCRIPTION("Oxnas NAND driver");
> +MODULE_ALIAS("platform:oxnas_nand");
> 



From cyrille.pitchen at atmel.com  Wed Oct 19 08:34:49 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Wed, 19 Oct 2016 17:34:49 +0200
Subject: [PATCH v2 1/1] MAINTAINERS: add a maintainer for the SPI NOR subsystem
Message-ID: <aad52b708dcf6754edab87d2e0afe4f0ee6831f9.1476891131.git.cyrille.pitchen@atmel.com>

I would like to volunteer as a maintainer for the SPI NOR part of the MTD
subsystem.

Over the last months, a significant number of SPI NOR related patches have
been submitted, some of them have been reviewed, but very few have finally
been merged. Hence, the number of pending SPI NOR related patches continues
to increase over the time.

Through my work on SPI NOR memories from many manufacturers over the last
two years, I've gained a solid understanding of this technology.
I've already helped by reviewing patches from other contributors on the
mailing list, and would like to help getting those patches integrated by
volunteering as a maintainer for this specific area.

Boris Brezillon has already stepped up as a maintainer for the NAND
sub-subsystem in MTD, and the SPI NOR sub-subsystem could be handled in
the same way: I would be reviewing patches touching this area, collecting
them and sending pull requests to Brian Norris.

Also both Marek Vasut and Richard Weinberger have volunteered as well as
maintainers for the SPI NOR subsystem.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
Acked-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
ChangeLog:

v1 -> v2:
- add Marek and Richard as maintainers.
- add Acked-by from Boris Brezillon.


 MAINTAINERS | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 757f9c4b388d..7e63b2015072 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11390,6 +11390,18 @@ W:	http://www.st.com/spear
 S:	Maintained
 F:	drivers/clk/spear/
 
+SPI NOR SUBSYSTEM
+M:	Cyrille Pitchen <cyrille.pitchen at atmel.com>
+M:	Marek Vasut <marek.vasut at gmail.com>
+M:	Richard Weinberger <richard at nod.at>
+L:	linux-mtd at lists.infradead.org
+W:	http://www.linux-mtd.infradead.org/
+Q:	http://patchwork.ozlabs.org/project/linux-mtd/list/
+T:	git git://github.com/spi-nor/linux.git
+S:	Maintained
+F:	drivers/mtd/spi-nor/
+F:	include/linux/mtd/spi-nor.h
+
 SPI SUBSYSTEM
 M:	Mark Brown <broonie at kernel.org>
 L:	linux-spi at vger.kernel.org
-- 
2.7.4



From boris.brezillon at free-electrons.com  Wed Oct 19 08:37:04 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Wed, 19 Oct 2016 17:37:04 +0200
Subject: [PATCH] mtd: nand: Add OX820 NAND Support
In-Reply-To: <20161019145523.6763-1-narmstrong@baylibre.com>
References: <20161019145523.6763-1-narmstrong@baylibre.com>
Message-ID: <20161019173704.75592f52@bbrezillon>

On Wed, 19 Oct 2016 16:55:23 +0200
Neil Armstrong <narmstrong at baylibre.com> wrote:

> Add NAND driver to support the Oxford Semiconductor OX820 NAND Controller.
> This is a simple memory mapped NAND controller with single chip select and
> software ECC.
> 
> Signed-off-by: Neil Armstrong <narmstrong at baylibre.com>

It looks pretty good already (I like those dummy controllers :-)). Just
a few comments below.

> ---
>  .../devicetree/bindings/mtd/oxnas-nand.txt         |  24 +++
>  drivers/mtd/nand/Kconfig                           |   5 +
>  drivers/mtd/nand/Makefile                          |   1 +
>  drivers/mtd/nand/oxnas_nand.c                      | 204 +++++++++++++++++++++
>  4 files changed, 234 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mtd/oxnas-nand.txt
>  create mode 100644 drivers/mtd/nand/oxnas_nand.c
> 
> Changes since RFC http://lkml.kernel.org/r/20161018090927.1990-1-narmstrong at baylibre.com :
>  - Avoid using chip->IO_ADDR*
>  - Use new DT structure
>  - Assign a chip for the subnode
>  - Use the nand_hw_control structure
>  - Cleanup probe
>  - Cleanup cmd_ctrl by using a context ctrl offset used in write_bytes
> 
> diff --git a/Documentation/devicetree/bindings/mtd/oxnas-nand.txt b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
> new file mode 100644
> index 0000000..83b684d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
> @@ -0,0 +1,24 @@
> +* Oxford Semiconductor OXNAS NAND Controller
> +
> +Please refer to nand.txt for generic information regarding MTD NAND bindings.
> +
> +Required properties:
> + - compatible: "oxsemi,ox820-nand"
> + - reg: Base address and length for NAND mapped memory.
> +
> +Optional Properties:
> + - clocks: phandle to the NAND gate clock if needed.
> + - resets: phandle to the NAND reset control if needed.
> +
> +Example:
> +
> +nand: nand at 41000000 {

nandc: nand-controller at 41000000 {

> +	compatible = "oxsemi,ox820-nand";
> +	reg = <0x41000000 0x100000>;
> +	nand-ecc-mode = "soft";
> +	clocks = <&stdclk CLK_820_NAND>;
> +	resets = <&reset RESET_NAND>;
> +	#address-cells = <1>;
> +	#size-cells = <1>;
> +	status = "disabled";
> +};

You should probably provide an example where the NAND controller is
enabled and at least one nand chip is connected to the NAND bus.

> diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
> index 7b7a887..c023125 100644
> --- a/drivers/mtd/nand/Kconfig
> +++ b/drivers/mtd/nand/Kconfig
> @@ -426,6 +426,11 @@ config MTD_NAND_ORION
>  	  No board specific support is done by this driver, each board
>  	  must advertise a platform_device for the driver to attach.
>  
> +config MTD_NAND_OXNAS
> +	tristate "NAND Flash support for Oxford Semiconductor SoC"
> +	help
> +	  This enables the NAND flash controller on Oxford Semiconductor SoCs.
> +
>  config MTD_NAND_FSL_ELBC
>  	tristate "NAND support for Freescale eLBC controllers"
>  	depends on FSL_SOC
> diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
> index cafde6f..05fc054 100644
> --- a/drivers/mtd/nand/Makefile
> +++ b/drivers/mtd/nand/Makefile
> @@ -35,6 +35,7 @@ obj-$(CONFIG_MTD_NAND_TMIO)		+= tmio_nand.o
>  obj-$(CONFIG_MTD_NAND_PLATFORM)		+= plat_nand.o
>  obj-$(CONFIG_MTD_NAND_PASEMI)		+= pasemi_nand.o
>  obj-$(CONFIG_MTD_NAND_ORION)		+= orion_nand.o
> +obj-$(CONFIG_MTD_NAND_OXNAS)		+= oxnas_nand.o
>  obj-$(CONFIG_MTD_NAND_FSL_ELBC)		+= fsl_elbc_nand.o
>  obj-$(CONFIG_MTD_NAND_FSL_IFC)		+= fsl_ifc_nand.o
>  obj-$(CONFIG_MTD_NAND_FSL_UPM)		+= fsl_upm.o
> diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/oxnas_nand.c
> new file mode 100644
> index 0000000..a9fe1ac
> --- /dev/null
> +++ b/drivers/mtd/nand/oxnas_nand.c
> @@ -0,0 +1,204 @@
> +/*
> + * Oxford Semiconductor OXNAS NAND driver
> +
> + * Copyright (C) 2016 Neil Armstrong <narmstrong at baylibre.com>
> + * Heavily based on plat_nand.c :
> + * Author: Vitaly Wool <vitalywool at gmail.com>
> + * Copyright (C) 2013 Ma Haijun <mahaijuns at gmail.com>
> + * Copyright (C) 2012 John Crispin <blogic at openwrt.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/clk.h>
> +#include <linux/reset.h>
> +#include <linux/mtd/mtd.h>
> +#include <linux/mtd/nand.h>
> +#include <linux/mtd/partitions.h>
> +#include <linux/of.h>
> +
> +/* Nand commands */
> +#define OXNAS_NAND_CMD_ALE		BIT(18)
> +#define OXNAS_NAND_CMD_CLE		BIT(19)
> +
> +#define OXNAS_NAND_MAX_CHIPS	1
> +
> +struct oxnas_nand {
> +	struct nand_hw_control base;
> +	void __iomem *io_base;
> +	struct clk *clk;
> +	struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS];
> +	unsigned long ctrl;
> +};
> +
> +static uint8_t oxnas_nand_read_byte(struct mtd_info *mtd)
> +{
> +	struct nand_chip *chip = mtd_to_nand(mtd);
> +	struct oxnas_nand *oxnas = nand_get_controller_data(chip);
> +
> +	return readb(oxnas->io_base);
> +}
> +
> +static void oxnas_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
> +{
> +	struct nand_chip *chip = mtd_to_nand(mtd);
> +	struct oxnas_nand *oxnas = nand_get_controller_data(chip);
> +
> +	ioread8_rep(oxnas->io_base, buf, len);
> +}
> +
> +static void oxnas_nand_write_buf(struct mtd_info *mtd,
> +				 const uint8_t *buf, int len)
> +{
> +	struct nand_chip *chip = mtd_to_nand(mtd);
> +	struct oxnas_nand *oxnas = nand_get_controller_data(chip);
> +
> +	iowrite8_rep(oxnas->io_base + oxnas->ctrl, buf, len);
> +}
> +
> +/* Single CS command control */
> +static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
> +				unsigned int ctrl)
> +{
> +	struct nand_chip *chip = mtd_to_nand(mtd);
> +	struct oxnas_nand *oxnas = nand_get_controller_data(chip);
> +
> +	if (ctrl & NAND_CTRL_CHANGE) {
> +		if (ctrl & NAND_CLE)
> +			oxnas->ctrl = OXNAS_NAND_CMD_CLE;
> +		else if (ctrl & NAND_ALE)
> +			oxnas->ctrl = OXNAS_NAND_CMD_ALE;
> +		else
> +			oxnas->ctrl = 0;
> +	}
> +
> +	if (cmd != NAND_CMD_NONE)
> +		writeb(cmd, oxnas->io_base + oxnas->ctrl);

There's no need to test the NAND_CTRL_CHANGE here, and I don't think
the CLE or ALE flag is ever set when cmd == CMD_NONE. So, you can kill
the ->ctrl field and simply do:

	if (ctrl & NAND_CLE)
		writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_CLE);
	else if (ctrl & NAND_ALE)
		writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_ALE);

> +}


From narmstrong at baylibre.com  Wed Oct 19 08:46:01 2016
From: narmstrong at baylibre.com (Neil Armstrong)
Date: Wed, 19 Oct 2016 17:46:01 +0200
Subject: [PATCH] mtd: nand: Add OX820 NAND Support
In-Reply-To: <20161019173704.75592f52@bbrezillon>
References: <20161019145523.6763-1-narmstrong@baylibre.com>
 <20161019173704.75592f52@bbrezillon>
Message-ID: <0f5398bb-52f1-d5bb-834c-dead4f708fd3@baylibre.com>

On 10/19/2016 05:37 PM, Boris Brezillon wrote:
> On Wed, 19 Oct 2016 16:55:23 +0200
> Neil Armstrong <narmstrong at baylibre.com> wrote:

[...]

>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
>> @@ -0,0 +1,24 @@
>> +* Oxford Semiconductor OXNAS NAND Controller
>> +
>> +Please refer to nand.txt for generic information regarding MTD NAND bindings.
>> +
>> +Required properties:
>> + - compatible: "oxsemi,ox820-nand"
>> + - reg: Base address and length for NAND mapped memory.
>> +
>> +Optional Properties:
>> + - clocks: phandle to the NAND gate clock if needed.
>> + - resets: phandle to the NAND reset control if needed.
>> +
>> +Example:
>> +
>> +nand: nand at 41000000 {
> 
> nandc: nand-controller at 41000000 {
> 
>> +	compatible = "oxsemi,ox820-nand";
>> +	reg = <0x41000000 0x100000>;
>> +	nand-ecc-mode = "soft";
>> +	clocks = <&stdclk CLK_820_NAND>;
>> +	resets = <&reset RESET_NAND>;
>> +	#address-cells = <1>;
>> +	#size-cells = <1>;
>> +	status = "disabled";
>> +};
> 
> You should probably provide an example where the NAND controller is
> enabled and at least one nand chip is connected to the NAND bus.

Indeed, I forgot that.

[...]

>> +
>> +static uint8_t oxnas_nand_read_byte(struct mtd_info *mtd)
>> +{
>> +	struct nand_chip *chip = mtd_to_nand(mtd);
>> +	struct oxnas_nand *oxnas = nand_get_controller_data(chip);
>> +
>> +	return readb(oxnas->io_base);
>> +}
>> +
>> +static void oxnas_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
>> +{
>> +	struct nand_chip *chip = mtd_to_nand(mtd);
>> +	struct oxnas_nand *oxnas = nand_get_controller_data(chip);
>> +
>> +	ioread8_rep(oxnas->io_base, buf, len);
>> +}
>> +
>> +static void oxnas_nand_write_buf(struct mtd_info *mtd,
>> +				 const uint8_t *buf, int len)
>> +{
>> +	struct nand_chip *chip = mtd_to_nand(mtd);
>> +	struct oxnas_nand *oxnas = nand_get_controller_data(chip);
>> +
>> +	iowrite8_rep(oxnas->io_base + oxnas->ctrl, buf, len);
>> +}
>> +
>> +/* Single CS command control */
>> +static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
>> +				unsigned int ctrl)
>> +{
>> +	struct nand_chip *chip = mtd_to_nand(mtd);
>> +	struct oxnas_nand *oxnas = nand_get_controller_data(chip);
>> +
>> +	if (ctrl & NAND_CTRL_CHANGE) {
>> +		if (ctrl & NAND_CLE)
>> +			oxnas->ctrl = OXNAS_NAND_CMD_CLE;
>> +		else if (ctrl & NAND_ALE)
>> +			oxnas->ctrl = OXNAS_NAND_CMD_ALE;
>> +		else
>> +			oxnas->ctrl = 0;
>> +	}
>> +
>> +	if (cmd != NAND_CMD_NONE)
>> +		writeb(cmd, oxnas->io_base + oxnas->ctrl);
> 
> There's no need to test the NAND_CTRL_CHANGE here, and I don't think
> the CLE or ALE flag is ever set when cmd == CMD_NONE. So, you can kill
> the ->ctrl field and simply do:
> 
> 	if (ctrl & NAND_CLE)
> 		writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_CLE);
> 	else if (ctrl & NAND_ALE)
> 		writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_ALE);
> 
>> +}

Hmm, except it's needed back in the oxnas_nand_write_buf() call (don't ask me why)
so I don't see how to simplify more this function.


From boris.brezillon at free-electrons.com  Wed Oct 19 08:54:28 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Wed, 19 Oct 2016 17:54:28 +0200
Subject: [PATCH] mtd: nand: Add OX820 NAND Support
In-Reply-To: <0f5398bb-52f1-d5bb-834c-dead4f708fd3@baylibre.com>
References: <20161019145523.6763-1-narmstrong@baylibre.com>
 <20161019173704.75592f52@bbrezillon>
 <0f5398bb-52f1-d5bb-834c-dead4f708fd3@baylibre.com>
Message-ID: <20161019175428.6ea3998d@bbrezillon>

On Wed, 19 Oct 2016 17:46:01 +0200
Neil Armstrong <narmstrong at baylibre.com> wrote:

> >> +/* Single CS command control */
> >> +static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
> >> +				unsigned int ctrl)
> >> +{
> >> +	struct nand_chip *chip = mtd_to_nand(mtd);
> >> +	struct oxnas_nand *oxnas = nand_get_controller_data(chip);
> >> +
> >> +	if (ctrl & NAND_CTRL_CHANGE) {
> >> +		if (ctrl & NAND_CLE)
> >> +			oxnas->ctrl = OXNAS_NAND_CMD_CLE;
> >> +		else if (ctrl & NAND_ALE)
> >> +			oxnas->ctrl = OXNAS_NAND_CMD_ALE;
> >> +		else
> >> +			oxnas->ctrl = 0;
> >> +	}
> >> +
> >> +	if (cmd != NAND_CMD_NONE)
> >> +		writeb(cmd, oxnas->io_base + oxnas->ctrl);  
> > 
> > There's no need to test the NAND_CTRL_CHANGE here, and I don't think
> > the CLE or ALE flag is ever set when cmd == CMD_NONE. So, you can kill
> > the ->ctrl field and simply do:
> > 
> > 	if (ctrl & NAND_CLE)
> > 		writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_CLE);
> > 	else if (ctrl & NAND_ALE)
> > 		writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_ALE);
> >   
> >> +}  
> 
> Hmm, except it's needed back in the oxnas_nand_write_buf() call (don't ask me why)
> so I don't see how to simplify more this function.

Are you sure? Can you add a WARN(oxnas->ctrl) in oxnas_nand_write_buf()
to check if it's ever the case? I'm almost sure there is a call to
->cmd_ctrl() with none of the CLE and ALE flags set before the
->write_buf() call.


From boris.brezillon at free-electrons.com  Wed Oct 19 09:21:05 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Wed, 19 Oct 2016 18:21:05 +0200
Subject: [PATCH] mtd: nand: Add OX820 NAND Support
In-Reply-To: <20161019145523.6763-1-narmstrong@baylibre.com>
References: <20161019145523.6763-1-narmstrong@baylibre.com>
Message-ID: <20161019182105.23c31ed9@bbrezillon>

On Wed, 19 Oct 2016 16:55:23 +0200
Neil Armstrong <narmstrong at baylibre.com> wrote:

> Add NAND driver to support the Oxford Semiconductor OX820 NAND Controller.
> This is a simple memory mapped NAND controller with single chip select and
> software ECC.
> 
> Signed-off-by: Neil Armstrong <narmstrong at baylibre.com>
> ---
>  .../devicetree/bindings/mtd/oxnas-nand.txt         |  24 +++
>  drivers/mtd/nand/Kconfig                           |   5 +
>  drivers/mtd/nand/Makefile                          |   1 +
>  drivers/mtd/nand/oxnas_nand.c                      | 204 +++++++++++++++++++++
>  4 files changed, 234 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mtd/oxnas-nand.txt
>  create mode 100644 drivers/mtd/nand/oxnas_nand.c
> 
> Changes since RFC http://lkml.kernel.org/r/20161018090927.1990-1-narmstrong at baylibre.com :
>  - Avoid using chip->IO_ADDR*
>  - Use new DT structure
>  - Assign a chip for the subnode
>  - Use the nand_hw_control structure
>  - Cleanup probe
>  - Cleanup cmd_ctrl by using a context ctrl offset used in write_bytes
> 
> diff --git a/Documentation/devicetree/bindings/mtd/oxnas-nand.txt b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
> new file mode 100644
> index 0000000..83b684d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
> @@ -0,0 +1,24 @@
> +* Oxford Semiconductor OXNAS NAND Controller
> +
> +Please refer to nand.txt for generic information regarding MTD NAND bindings.
> +
> +Required properties:
> + - compatible: "oxsemi,ox820-nand"
> + - reg: Base address and length for NAND mapped memory.
> +
> +Optional Properties:
> + - clocks: phandle to the NAND gate clock if needed.
> + - resets: phandle to the NAND reset control if needed.
> +
> +Example:
> +
> +nand: nand at 41000000 {
> +	compatible = "oxsemi,ox820-nand";
> +	reg = <0x41000000 0x100000>;
> +	nand-ecc-mode = "soft";
> +	clocks = <&stdclk CLK_820_NAND>;
> +	resets = <&reset RESET_NAND>;
> +	#address-cells = <1>;
> +	#size-cells = <1>;
> +	status = "disabled";
> +};
> diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
> index 7b7a887..c023125 100644
> --- a/drivers/mtd/nand/Kconfig
> +++ b/drivers/mtd/nand/Kconfig
> @@ -426,6 +426,11 @@ config MTD_NAND_ORION
>  	  No board specific support is done by this driver, each board
>  	  must advertise a platform_device for the driver to attach.
>  
> +config MTD_NAND_OXNAS
> +	tristate "NAND Flash support for Oxford Semiconductor SoC"
> +	help
> +	  This enables the NAND flash controller on Oxford Semiconductor SoCs.
> +
>  config MTD_NAND_FSL_ELBC
>  	tristate "NAND support for Freescale eLBC controllers"
>  	depends on FSL_SOC
> diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
> index cafde6f..05fc054 100644
> --- a/drivers/mtd/nand/Makefile
> +++ b/drivers/mtd/nand/Makefile
> @@ -35,6 +35,7 @@ obj-$(CONFIG_MTD_NAND_TMIO)		+= tmio_nand.o
>  obj-$(CONFIG_MTD_NAND_PLATFORM)		+= plat_nand.o
>  obj-$(CONFIG_MTD_NAND_PASEMI)		+= pasemi_nand.o
>  obj-$(CONFIG_MTD_NAND_ORION)		+= orion_nand.o
> +obj-$(CONFIG_MTD_NAND_OXNAS)		+= oxnas_nand.o
>  obj-$(CONFIG_MTD_NAND_FSL_ELBC)		+= fsl_elbc_nand.o
>  obj-$(CONFIG_MTD_NAND_FSL_IFC)		+= fsl_ifc_nand.o
>  obj-$(CONFIG_MTD_NAND_FSL_UPM)		+= fsl_upm.o
> diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/oxnas_nand.c
> new file mode 100644
> index 0000000..a9fe1ac
> --- /dev/null
> +++ b/drivers/mtd/nand/oxnas_nand.c
> @@ -0,0 +1,204 @@
> +/*
> + * Oxford Semiconductor OXNAS NAND driver
> +
> + * Copyright (C) 2016 Neil Armstrong <narmstrong at baylibre.com>
> + * Heavily based on plat_nand.c :
> + * Author: Vitaly Wool <vitalywool at gmail.com>
> + * Copyright (C) 2013 Ma Haijun <mahaijuns at gmail.com>
> + * Copyright (C) 2012 John Crispin <blogic at openwrt.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/clk.h>
> +#include <linux/reset.h>
> +#include <linux/mtd/mtd.h>
> +#include <linux/mtd/nand.h>
> +#include <linux/mtd/partitions.h>
> +#include <linux/of.h>
> +
> +/* Nand commands */
> +#define OXNAS_NAND_CMD_ALE		BIT(18)
> +#define OXNAS_NAND_CMD_CLE		BIT(19)
> +
> +#define OXNAS_NAND_MAX_CHIPS	1
> +
> +struct oxnas_nand {

One last thing, please rename the struct: oxnas_nandc, oxnas_nand_ctrl
or oxnas_nand_controller. Pick the one you prefer or choose another
one, I don't care, as long as the name clearly shows that this is a NAND
controller and not the NAND chip.

> +	struct nand_hw_control base;
> +	void __iomem *io_base;
> +	struct clk *clk;
> +	struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS];
> +	unsigned long ctrl;
> +};


From cyrille.pitchen at atmel.com  Wed Oct 19 09:42:36 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Wed, 19 Oct 2016 18:42:36 +0200
Subject: [PATCH 1/2] fsl-quadspi: fix QUAD read, add NORMAL, DUAL and FAST
 reads
In-Reply-To: <20160927055957.427-1-albert.aribaud@3adev.fr>
References: <20160927055957.427-1-albert.aribaud@3adev.fr>
Message-ID: <69a5b0d7-6b89-7edc-738d-c9e25802ba31@atmel.com>

Hi Albert,

+Yunhui

Le 27/09/2016 ? 07:59, Albert ARIBAUD (3ADEV) a ?crit :
> Fix QUAD read LUT sequence missing JMP_ON_CS which caused
> read corruptions with non-1K-size reads on BK4R1 machine.
> 
> Add NORMAL, DUAL and FAST read sequences.
> 
> Introduce spi-bus-width property for bus subnodes, to
> specify per-bus capability to use NORMAL, FAST, DUAL,
> and/or QUAD reads.
> 
> Also:
> 
> Simplify ioremap/memcpy usage.
> 
> Make controller clock frequency equal to the lowest of
> subnode max frequencies instead of the last one.
> 
> Limit Vybrid to use only half its RX fifo, using more will
> cause corrupt reads.
> 
> Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud at 3adev.fr>
> ---
>  drivers/mtd/spi-nor/fsl-quadspi.c | 204 ++++++++++++++++++++++++++++----------
>  1 file changed, 152 insertions(+), 52 deletions(-)
> 
> diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c
> index 5c82e4e..9811cf2 100644
> --- a/drivers/mtd/spi-nor/fsl-quadspi.c
> +++ b/drivers/mtd/spi-nor/fsl-quadspi.c
> @@ -41,6 +41,8 @@
>  #define QUADSPI_QUIRK_TKT253890		(1 << 2)
>  /* Controller cannot wake up from wait mode, TKT245618 */
>  #define QUADSPI_QUIRK_TKT245618         (1 << 3)
> +/* Controller can only read half a rx fifo through AHB */
> +#define QUADSPI_QUIRK_AHB_READ_HALF_FIFO  (1 << 4)
>  
>  /* The registers */
>  #define QUADSPI_MCR			0x00
> @@ -117,6 +119,10 @@
>  #define QUADSPI_FR			0x160
>  #define QUADSPI_FR_TFF_MASK		0x1
>  
> +#define QUADSPI_SPTRCLR			0x15c
> +#define QUADSPI_SPTRCLR_BFPTRC_SHIFT		0
> +#define QUADSPI_SPTRCLR_BFPTRC_MASK		(0x1 << QUADSPI_SPTRCLR_BFPTRC_SHIFT)
> +
>  #define QUADSPI_SFA1AD			0x180
>  #define QUADSPI_SFA2AD			0x184
>  #define QUADSPI_SFB1AD			0x188
> @@ -193,7 +199,7 @@
>  #define QUADSPI_LUT_NUM		64
>  
>  /* SEQID -- we can have 16 seqids at most. */
> -#define SEQID_QUAD_READ		0
> +#define SEQID_READ		0
>  #define SEQID_WREN		1
>  #define SEQID_WRDI		2
>  #define SEQID_RDSR		3
> @@ -205,6 +211,9 @@
>  #define SEQID_RDCR		9
>  #define SEQID_EN4B		10
>  #define SEQID_BRWR		11
> +#define SEQID_FAST_READ		12
> +#define SEQID_DUAL_READ		13
> +#define SEQID_QUAD_READ		14
>  
>  #define QUADSPI_MIN_IOMAP SZ_4M
>  
> @@ -229,7 +238,8 @@ static struct fsl_qspi_devtype_data vybrid_data = {
>  	.rxfifo = 128,
>  	.txfifo = 64,
>  	.ahb_buf_size = 1024,
> -	.driver_data = QUADSPI_QUIRK_SWAP_ENDIAN,
> +	.driver_data = QUADSPI_QUIRK_SWAP_ENDIAN
> +		       | QUADSPI_QUIRK_AHB_READ_HALF_FIFO,
>  };
>  
>  static struct fsl_qspi_devtype_data imx6sx_data = {
> @@ -309,6 +319,11 @@ static inline int needs_wakeup_wait_mode(struct fsl_qspi *q)
>  	return q->devtype_data->driver_data & QUADSPI_QUIRK_TKT245618;
>  }
>  
> +static inline int needs_half_fifo(struct fsl_qspi *q)
> +{
> +	return q->devtype_data->driver_data & QUADSPI_QUIRK_AHB_READ_HALF_FIFO;
> +}
> +
>  /*
>   * R/W functions for big- or little-endian registers:
>   * The qSPI controller's endian is independent of the CPU core's endian.
> @@ -373,8 +388,20 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
>  	void __iomem *base = q->iobase;
>  	int rxfifo = q->devtype_data->rxfifo;
>  	u32 lut_base;
> -	u8 cmd, addrlen, dummy;
> +	u8 cmd, addrlen;
>  	int i;
> +	/* use 8 dummy cycles for all fast operations */
> +	const int dummy = 8;
> +
> +	/* use only half fifo if controller needs that */
> +	if (needs_half_fifo(q))
> +		rxfifo /= 2;
> +
> +    /* use 24-bit addresses for up to 16MB, 32-bit above 16MB */
> +	if (q->nor_size <= SZ_16M)
> +		addrlen = ADDR24BIT;
> +	else
> +		addrlen = ADDR32BIT;
>  
>  	fsl_qspi_unlock_lut(q);
>  
> @@ -382,24 +409,12 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
>  	for (i = 0; i < QUADSPI_LUT_NUM; i++)
>  		qspi_writel(q, 0, base + QUADSPI_LUT_BASE + i * 4);
>  
> -	/* Quad Read */
> -	lut_base = SEQID_QUAD_READ * 4;
> -
> -	if (q->nor_size <= SZ_16M) {
> -		cmd = SPINOR_OP_READ_1_1_4;
> -		addrlen = ADDR24BIT;
> -		dummy = 8;
> -	} else {
> -		/* use the 4-byte address */
> -		cmd = SPINOR_OP_READ_1_1_4;
> -		addrlen = ADDR32BIT;
> -		dummy = 8;
> -	}
> -
> -	qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
> -			base + QUADSPI_LUT(lut_base));
> -	qspi_writel(q, LUT0(DUMMY, PAD1, dummy) | LUT1(FSL_READ, PAD4, rxfifo),
> -			base + QUADSPI_LUT(lut_base + 1));
> +	/* Read */
> +	lut_base = SEQID_READ * 4;
> +	qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_READ) | LUT1(ADDR, PAD1, addrlen),
> +		base + QUADSPI_LUT(lut_base));
> +	qspi_writel(q, LUT0(FSL_READ, PAD1, rxfifo) | LUT1(JMP_ON_CS, PAD1, SEQID_READ * 8),
> +		base + QUADSPI_LUT(lut_base + 1));

It seems that both Yunhui and you work on the same topic, maybe you can
synchronize?
https://patchwork.ozlabs.org/patch/660356/

>  
>  	/* Write enable */
>  	lut_base = SEQID_WREN * 4;
> @@ -409,16 +424,7 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
>  	/* Page Program */
>  	lut_base = SEQID_PP * 4;
>  
> -	if (q->nor_size <= SZ_16M) {
> -		cmd = SPINOR_OP_PP;
> -		addrlen = ADDR24BIT;
> -	} else {
> -		/* use the 4-byte address */
> -		cmd = SPINOR_OP_PP;
> -		addrlen = ADDR32BIT;
> -	}
> -
> -	qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
> +	qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_PP) | LUT1(ADDR, PAD1, addrlen),
>  			base + QUADSPI_LUT(lut_base));
>  	qspi_writel(q, LUT0(FSL_WRITE, PAD1, 0),
>  			base + QUADSPI_LUT(lut_base + 1));
> @@ -431,7 +437,6 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
>  
>  	/* Erase a sector */
>  	lut_base = SEQID_SE * 4;
> -
>  	cmd = q->nor[0].erase_opcode;
>  	addrlen = q->nor_size <= SZ_16M ? ADDR24BIT : ADDR32BIT;
>  
> @@ -476,6 +481,33 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
>  	qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_BRWR),
>  			base + QUADSPI_LUT(lut_base));
>  
> +	/* Fast Read */
> +	lut_base = SEQID_FAST_READ * 4;
> +	qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_READ_FAST) | LUT1(ADDR, PAD1, addrlen),
> +		base + QUADSPI_LUT(lut_base));
> +	qspi_writel(q, LUT0(DUMMY, PAD1, dummy) | LUT1(FSL_READ, PAD1, rxfifo),
> +		base + QUADSPI_LUT(lut_base + 1));
> +	qspi_writel(q, LUT0(JMP_ON_CS, PAD1, SEQID_FAST_READ * 8),
> +		base + QUADSPI_LUT(lut_base + 2));
> +
> +	/* Dual Read */
> +	lut_base = SEQID_DUAL_READ * 4;
> +	qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_READ_1_1_2) | LUT1(ADDR, PAD1, addrlen),
> +		base + QUADSPI_LUT(lut_base));
> +	qspi_writel(q, LUT0(DUMMY, PAD1, dummy) | LUT1(FSL_READ, PAD2, rxfifo),
> +		base + QUADSPI_LUT(lut_base + 1));
> +	qspi_writel(q, LUT0(JMP_ON_CS, PAD1, SEQID_DUAL_READ * 8),
> +		base + QUADSPI_LUT(lut_base + 2));
> +
> +	/* Quad Read */
> +	lut_base = SEQID_QUAD_READ * 4;
> +	qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_READ_1_1_4) | LUT1(ADDR, PAD1, addrlen),
> +		base + QUADSPI_LUT(lut_base));
> +	qspi_writel(q, LUT0(DUMMY, PAD1, dummy) | LUT1(FSL_READ, PAD4, rxfifo),
> +		base + QUADSPI_LUT(lut_base + 1));
> +	qspi_writel(q, LUT0(JMP_ON_CS, PAD1, SEQID_QUAD_READ * 8),
> +		base + QUADSPI_LUT(lut_base + 2));
> +
>  	fsl_qspi_lock_lut(q);
>  }
>  
> @@ -483,8 +515,8 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
>  static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd)
>  {
>  	switch (cmd) {
> -	case SPINOR_OP_READ_1_1_4:
> -		return SEQID_QUAD_READ;
> +	case SPINOR_OP_READ:
> +		return SEQID_READ;
>  	case SPINOR_OP_WREN:
>  		return SEQID_WREN;
>  	case SPINOR_OP_WRDI:
> @@ -507,6 +539,12 @@ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd)
>  		return SEQID_EN4B;
>  	case SPINOR_OP_BRWR:
>  		return SEQID_BRWR;
> +	case SPINOR_OP_READ_FAST:
> +		return SEQID_FAST_READ;
> +	case SPINOR_OP_READ_1_1_2:
> +		return SEQID_DUAL_READ;
> +	case SPINOR_OP_READ_1_1_4:
> +		return SEQID_QUAD_READ;

I don't think it is a good thing to select the relevant "READ" LUT entry
according to the command op code. What if spi-nor.c introduces new op codes?

Maybe you could index the LUT entries by functions:
- READ_REG: the LUT op code would be dynamically updated by your
            .read_reg(nor, opcode, ...) implementation according to opcode.
- WRITE_REG: the same as above with the .write_reg(nor, opcode, ...) hook.
- READ_SLAVE1: read memory from the first SPI-NOR memory.
- WRITE_SLAVE1: write into the first SPI-NOR memory.
- READ_SLAVE2: read memory form the 2nd SPI-NOR memory.
...
- WRITE_SLAVEN: write into the N-th SPI-NOR memory.

Also be aware even for the .read() hook the nor->read_opcode might changes
between calls!

I don't know whether those comments fit your actual needs and the Freescale SPI
controller hardware constraints but I'm always worried about the ease to maintain
SPI-NOR controller drivers when they are not "op code agnostic".

Best regards,

Cyrille

>  	default:
>  		if (cmd == q->nor[0].erase_opcode)
>  			return SEQID_SE;
> @@ -676,11 +714,16 @@ static void fsl_qspi_set_map_addr(struct fsl_qspi *q)
>   * the memcpy to read the data directly. A "missed" access to the buffer
>   * causes the controller to clear the buffer, and use the sequence pointed
>   * by the QUADSPI_BFGENCR[SEQID] to initiate a read from the flash.
> + *
> + * When using two ports, the SEQID to use for one port might differ from
> + * the one to use for the other (e.g., if one port can do 4-pad reads but
> + * the other cannot). So we set up a basic mode here (SEQID_READ) and we
> + * will set up the proper SEQID for the port right before doing the AHB
> + * access(es).
>   */
>  static void fsl_qspi_init_abh_read(struct fsl_qspi *q)
>  {
>  	void __iomem *base = q->iobase;
> -	int seqid;
>  
>  	/* AHB configuration for access buffer 0/1/2 .*/
>  	qspi_writel(q, QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF0CR);
> @@ -688,11 +731,13 @@ static void fsl_qspi_init_abh_read(struct fsl_qspi *q)
>  	qspi_writel(q, QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF2CR);
>  	/*
>  	 * Set ADATSZ with the maximum AHB buffer size to improve the
> -	 * read performance.
> +	 * read performance, except when the controller should not use
> +	 * more than half its RX fifo in AHB reads, in which case read
> +	 * size is given in the LUT FSL_READ instructions.
>  	 */
>  	qspi_writel(q, QUADSPI_BUF3CR_ALLMST_MASK |
> -			((q->devtype_data->ahb_buf_size / 8)
> -			<< QUADSPI_BUF3CR_ADATSZ_SHIFT),
> +			(needs_half_fifo(q)? 0 : q->devtype_data->ahb_buf_size / 8)
> +	        << QUADSPI_BUF3CR_ADATSZ_SHIFT,
>  			base + QUADSPI_BUF3CR);
>  
>  	/* We only use the buffer3 */
> @@ -700,9 +745,8 @@ static void fsl_qspi_init_abh_read(struct fsl_qspi *q)
>  	qspi_writel(q, 0, base + QUADSPI_BUF1IND);
>  	qspi_writel(q, 0, base + QUADSPI_BUF2IND);
>  
> -	/* Set the default lut sequence for AHB Read. */
> -	seqid = fsl_qspi_get_seqid(q, q->nor[0].read_opcode);
> -	qspi_writel(q, seqid << QUADSPI_BFGENCR_SEQID_SHIFT,
> +	/* Set the default lut sequence for AHB Read to READ. */
> +	qspi_writel(q, SEQID_READ << QUADSPI_BFGENCR_SEQID_SHIFT,
>  		q->iobase + QUADSPI_BFGENCR);
>  }
>  
> @@ -841,6 +885,7 @@ static int fsl_qspi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
>  		return ret;
>  
>  	fsl_qspi_read_data(q, len, buf);
> +
>  	return 0;
>  }
>  
> @@ -887,11 +932,27 @@ static ssize_t fsl_qspi_read(struct spi_nor *nor, loff_t from,
>  {
>  	struct fsl_qspi *q = nor->priv;
>  	u8 cmd = nor->read_opcode;
> +	uint32_t seqid;
> +	size_t qlen = q->nor_size * 4;
> +	int nor_idx = nor - q->nor;
> +	size_t nor_ofs = q->nor_size * nor_idx;
> +
> +	/* Set the actual lut sequence for AHB Read from the considered nor. */
> +	seqid = fsl_qspi_get_seqid(q, nor->read_opcode);
> +	qspi_writel(q, seqid << QUADSPI_BFGENCR_SEQID_SHIFT,
> +		q->iobase + QUADSPI_BFGENCR);
> +	/* Reset the AHB sequence pointer */
> +	qspi_writel(q, QUADSPI_SPTRCLR_BFPTRC_MASK, q->iobase + QUADSPI_SPTRCLR);
> +    /* make sure the Rx buffer is read through AHB, not IP */
> +	qspi_writel(q, QUADSPI_RBCT_WMRK_MASK, q->iobase + QUADSPI_RBCT);
> +
> +	/* set the chip address for READID */
> +	fsl_qspi_set_base_addr(q, q->nor);
>  
>  	/* if necessary,ioremap buffer before AHB read, */
>  	if (!q->ahb_addr) {
> -		q->memmap_offs = q->chip_base_addr + from;
> -		q->memmap_len = len > QUADSPI_MIN_IOMAP ? len : QUADSPI_MIN_IOMAP;
> +		q->memmap_offs = q->chip_base_addr;
> +		q->memmap_len = qlen > QUADSPI_MIN_IOMAP ? qlen : QUADSPI_MIN_IOMAP;
>  
>  		q->ahb_addr = ioremap_nocache(
>  				q->memmap_phy + q->memmap_offs,
> @@ -906,8 +967,8 @@ static ssize_t fsl_qspi_read(struct spi_nor *nor, loff_t from,
>  			q->memmap_offs + q->memmap_len) {
>  		iounmap(q->ahb_addr);
>  
> -		q->memmap_offs = q->chip_base_addr + from;
> -		q->memmap_len = len > QUADSPI_MIN_IOMAP ? len : QUADSPI_MIN_IOMAP;
> +		q->memmap_offs = q->chip_base_addr;
> +		q->memmap_len = qlen > QUADSPI_MIN_IOMAP ? qlen : QUADSPI_MIN_IOMAP;
>  		q->ahb_addr = ioremap_nocache(
>  				q->memmap_phy + q->memmap_offs,
>  				q->memmap_len);
> @@ -917,13 +978,11 @@ static ssize_t fsl_qspi_read(struct spi_nor *nor, loff_t from,
>  		}
>  	}
>  
> -	dev_dbg(q->dev, "cmd [%x],read from %p, len:%zd\n",
> -		cmd, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs,
> -		len);
> +	dev_dbg(q->dev, "cmd [%x], read from %p, len:%zd\n",
> +		cmd, q->ahb_addr + nor_ofs + from, len);
>  
>  	/* Read out the data directly from the AHB buffer.*/
> -	memcpy(buf, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs,
> -		len);
> +	memcpy(buf, q->ahb_addr + nor_ofs + from, len);
>  
>  	return len;
>  }
> @@ -980,6 +1039,11 @@ static int fsl_qspi_probe(struct platform_device *pdev)
>  	struct spi_nor *nor;
>  	struct mtd_info *mtd;
>  	int ret, i = 0;
> +	const struct of_device_id *of_id =
> +			of_match_device(fsl_qspi_dt_ids, &pdev->dev);
> +	enum read_mode readmode;
> +	unsigned int buswidth;
> +	u32 qspimaxfreq, spimaxfreq;
>  
>  	q = devm_kzalloc(dev, sizeof(*q), GFP_KERNEL);
>  	if (!q)
> @@ -1050,6 +1114,9 @@ static int fsl_qspi_probe(struct platform_device *pdev)
>  
>  	mutex_init(&q->lock);
>  
> +	/* Running MIN of all "spi-max-frequency' values present in subnodes */
> +	qspimaxfreq = INT_MAX;
> +
>  	/* iterate the subnodes. */
>  	for_each_available_child_of_node(dev->of_node, np) {
>  		/* skip the holes */
> @@ -1073,15 +1140,44 @@ static int fsl_qspi_probe(struct platform_device *pdev)
>  		nor->prepare = fsl_qspi_prep;
>  		nor->unprepare = fsl_qspi_unprep;
>  
> +		/* Update running MIN of subnode max frequencies */
>  		ret = of_property_read_u32(np, "spi-max-frequency",
> -				&q->clk_rate);
> +				&spimaxfreq);
>  		if (ret < 0)
>  			goto mutex_failed;
> +		qspimaxfreq = (qspimaxfreq > spimaxfreq) ? spimaxfreq: qspimaxfreq;
>  
>  		/* set the chip address for READID */
>  		fsl_qspi_set_base_addr(q, nor);
>  
> -		ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
> +		/* scan using the proper read mode for this subnode */
> +		if (of_property_read_u32(np, "spi-bus-width", &buswidth)<0) {
> +			nor->read_opcode = SPINOR_OP_READ;
> +			readmode = SPI_NOR_NORMAL;
> +		} else {
> +			switch (buswidth) {
> +			case 4:
> +				nor->read_opcode = SPINOR_OP_READ_1_1_4;
> +				readmode = SPI_NOR_QUAD;
> +				break;
> +			case 2:
> +				nor->read_opcode = SPINOR_OP_READ_1_1_2;
> +				readmode = SPI_NOR_DUAL;
> +				break;
> +			case 1:
> +				nor->read_opcode = SPINOR_OP_READ_FAST;
> +				readmode = SPI_NOR_FAST;
> +				break;
> +			default:
> +				dev_warn(q->dev,
> +					"ignoring spi-bus-width=%d (should be 1, 2 or 4)",
> +					buswidth);
> +				nor->read_opcode = SPINOR_OP_READ;
> +				readmode = SPI_NOR_NORMAL;
> +			}
> +		}
> +
> +		ret = spi_nor_scan(nor, NULL, readmode);
>  		if (ret)
>  			goto mutex_failed;
>  
> @@ -1112,6 +1208,10 @@ static int fsl_qspi_probe(struct platform_device *pdev)
>  		i++;
>  	}
>  
> +	/* If we know the lowest subnode frequency, override driver default. */
> +	if (qspimaxfreq<INT_MAX)
> +		q->clk_rate = qspimaxfreq;
> +
>  	/* finish the rest init. */
>  	ret = fsl_qspi_nor_setup_last(q);
>  	if (ret)
> 



From cyrille.pitchen at atmel.com  Wed Oct 19 10:06:21 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Wed, 19 Oct 2016 19:06:21 +0200
Subject: [PATCH] mtd/spi-nor: Add SPI memory controllers for Aspeed SoCs
In-Reply-To: <1476723427-13243-1-git-send-email-clg@kaod.org>
References: <1476723427-13243-1-git-send-email-clg@kaod.org>
Message-ID: <6964c1fd-3ac1-a28f-7b73-8113f0837e75@atmel.com>

Hi C?dric,

Le 17/10/2016 ? 18:57, C?dric Le Goater a ?crit :
> This driver adds mtd support for spi-nor attached to either or both of
> the Firmware Memory Controller or the SPI Flash Controller (AST2400
> only).
> 
> The SMC controllers on the Aspeed AST2500 SoC are very similar to the
> ones found on the AST2400. The differences are on the number of
> supported flash modules and their default mappings in the SoC address
> space.
> 
> The Aspeed AST2500 has one SPI controller for the BMC firmware and two
> for the host firmware. All controllers have now the same set of
> registers compatible with the AST2400 FMC controller and the legacy
> 'SMC' controller is fully gone.
> 
> Based on previous work from Milton D. Miller II <miltonm at us.ibm.com>
> 
> Signed-off-by: C?dric Le Goater <clg at kaod.org>
> ---
[...]
> +
> +static void aspeed_smc_send_cmd_addr(struct spi_nor *nor, u8 cmd, u32 addr)
> +{
> +	struct aspeed_smc_chip *chip = nor->priv;
> +	__be32 temp;
> +	u32 cmdaddr;
> +
> +	switch (nor->addr_width) {
> +	default:
> +		WARN_ONCE(1, "Unexpected address width %u, defaulting to 3\n",
> +			  nor->addr_width);
> +		/* FALLTHROUGH */
> +	case 3:
> +		cmdaddr = addr & 0xFFFFFF;
> +
> +		cmdaddr |= (u32)cmd << 24;
> +
> +		temp = cpu_to_be32(cmdaddr);
> +		aspeed_smc_to_fifo(chip->base, &temp, 4);
> +		break;
> +	case 4:
> +		temp = cpu_to_be32(addr);
> +		aspeed_smc_to_fifo(chip->base, &cmd, 1);
> +		aspeed_smc_to_fifo(chip->base, &temp, 4);
> +		break;
> +	}
> +}
> +
> +static ssize_t aspeed_smc_read_user(struct spi_nor *nor, loff_t from, size_t len,
> +				    u_char *read_buf)
> +{
> +	struct aspeed_smc_chip *chip = nor->priv;
> +
> +	mutex_lock(&chip->controller->mutex);
> +
> +	aspeed_smc_start_user(nor);
> +	aspeed_smc_send_cmd_addr(nor, nor->read_opcode, from);

I guess the dummy cycles are missing between address cycles and data cycles!
Check nor->read_dummy ;)

Or maybe this controller can really only perform READ operations but no FAST
READ commands. Hence the "spi_nor_scan(&chip->nor, NULL, SPI_NOR_NORMAL)"
below.

> +	aspeed_smc_from_fifo(read_buf, chip->base, len);
> +	aspeed_smc_stop_user(nor);
> +
> +	mutex_unlock(&chip->controller->mutex);
> +
> +	return len;
> +}
[...]

Best regards,

Cyrille


From sergio.prado at e-labworks.com  Wed Oct 19 12:52:02 2016
From: sergio.prado at e-labworks.com (Sergio Prado)
Date: Wed, 19 Oct 2016 17:52:02 -0200
Subject: [PATCH v2 0/3] mtd: s3c2410: add device tree support
Message-ID: <1476906725-22613-1-git-send-email-sergio.prado@e-labworks.com>

This series adds support for configuring Samsung's s3c2410 and
compatible flash memory controller via devicetree.

Tested on FriendlyARM mini2440, based on s3c2440 SoC.

Patch 3 depends on patch 1.

Changes since v1:
- automate timing selection when booting with a device tree
- make s3c24XX_nand_devtype_data structs "static const"
- removing samsung,s3c6400-nand compatible since it is equivalent to
  samsung,s3c2412-nand

Changes since initial version:
- patch converted to a patch series
- read timings from nand_sdr_timings when booting with a device tree
- naming improvements in the device tree binding
  (s/nand/nand-controller/, s/_/-, s/children/child)
- dropped property samsung,ignore_unset_ecc
- remove @0 from nand device node
- checking pdev->dev.of_node instead of using ifdef CONFIG_OF_MTD
- preventing from parsing device tree properties twice
- increment the nand controller child node refcount, since we
  maintain a reference to it and its name field
- using of_device_get_match_data() instead of of_match_device()
  to make the code simpler
- remove CONFIG_MTD_NAND_S3C2410_HWECC compile option so we can
  select ECC mode using nand-ecc-mode property in the device tree

Sergio Prado (3):
  mtd: s3c2410: make ecc mode configurable via platform data
  dt-bindings: mtd: add DT binding for s3c2410 flash controller
  mtd: s3c2410: parse the device configuration from OF node

 .../devicetree/bindings/mtd/samsung-s3c2410.txt    |  56 +++++
 arch/arm/mach-s3c24xx/common-smdk.c                |   1 +
 arch/arm/mach-s3c24xx/mach-anubis.c                |   1 +
 arch/arm/mach-s3c24xx/mach-at2440evb.c             |   1 +
 arch/arm/mach-s3c24xx/mach-bast.c                  |   1 +
 arch/arm/mach-s3c24xx/mach-gta02.c                 |   1 +
 arch/arm/mach-s3c24xx/mach-jive.c                  |   1 +
 arch/arm/mach-s3c24xx/mach-mini2440.c              |   1 +
 arch/arm/mach-s3c24xx/mach-osiris.c                |   1 +
 arch/arm/mach-s3c24xx/mach-qt2410.c                |   1 +
 arch/arm/mach-s3c24xx/mach-rx1950.c                |   1 +
 arch/arm/mach-s3c24xx/mach-rx3715.c                |   1 +
 arch/arm/mach-s3c24xx/mach-vstms.c                 |   1 +
 arch/arm/mach-s3c64xx/mach-hmt.c                   |   1 +
 arch/arm/mach-s3c64xx/mach-mini6410.c              |   1 +
 arch/arm/mach-s3c64xx/mach-real6410.c              |   1 +
 drivers/mtd/nand/Kconfig                           |   9 -
 drivers/mtd/nand/s3c2410.c                         | 274 +++++++++++++++------
 include/linux/platform_data/mtd-nand-s3c2410.h     |   7 +-
 19 files changed, 275 insertions(+), 86 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt

-- 
1.9.1



From sergio.prado at e-labworks.com  Wed Oct 19 12:52:03 2016
From: sergio.prado at e-labworks.com (Sergio Prado)
Date: Wed, 19 Oct 2016 17:52:03 -0200
Subject: [PATCH v2 1/3] mtd: s3c2410: make ecc mode configurable via platform
 data
In-Reply-To: <1476906725-22613-1-git-send-email-sergio.prado@e-labworks.com>
References: <1476906725-22613-1-git-send-email-sergio.prado@e-labworks.com>
Message-ID: <1476906725-22613-2-git-send-email-sergio.prado@e-labworks.com>

Removing CONFIG_MTD_NAND_S3C2410_HWECC option and adding a ecc_mode
field in the drivers's platform data structure so it can be selectable
via platform data.

Also setting this field to NAND_ECC_SOFT in all boards using this
driver since none of them had CONFIG_MTD_NAND_S3C2410_HWECC enabled.

Signed-off-by: Sergio Prado <sergio.prado at e-labworks.com>
---
 arch/arm/mach-s3c24xx/common-smdk.c            |   1 +
 arch/arm/mach-s3c24xx/mach-anubis.c            |   1 +
 arch/arm/mach-s3c24xx/mach-at2440evb.c         |   1 +
 arch/arm/mach-s3c24xx/mach-bast.c              |   1 +
 arch/arm/mach-s3c24xx/mach-gta02.c             |   1 +
 arch/arm/mach-s3c24xx/mach-jive.c              |   1 +
 arch/arm/mach-s3c24xx/mach-mini2440.c          |   1 +
 arch/arm/mach-s3c24xx/mach-osiris.c            |   1 +
 arch/arm/mach-s3c24xx/mach-qt2410.c            |   1 +
 arch/arm/mach-s3c24xx/mach-rx1950.c            |   1 +
 arch/arm/mach-s3c24xx/mach-rx3715.c            |   1 +
 arch/arm/mach-s3c24xx/mach-vstms.c             |   1 +
 arch/arm/mach-s3c64xx/mach-hmt.c               |   1 +
 arch/arm/mach-s3c64xx/mach-mini6410.c          |   1 +
 arch/arm/mach-s3c64xx/mach-real6410.c          |   1 +
 drivers/mtd/nand/Kconfig                       |   9 --
 drivers/mtd/nand/s3c2410.c                     | 119 +++++++++++++------------
 include/linux/platform_data/mtd-nand-s3c2410.h |   6 +-
 18 files changed, 79 insertions(+), 70 deletions(-)

diff --git a/arch/arm/mach-s3c24xx/common-smdk.c b/arch/arm/mach-s3c24xx/common-smdk.c
index e9fbcc91c5c0..9e0bc46e90ec 100644
--- a/arch/arm/mach-s3c24xx/common-smdk.c
+++ b/arch/arm/mach-s3c24xx/common-smdk.c
@@ -171,6 +171,7 @@
 	.twrph1		= 20,
 	.nr_sets	= ARRAY_SIZE(smdk_nand_sets),
 	.sets		= smdk_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* devices we initialise */
diff --git a/arch/arm/mach-s3c24xx/mach-anubis.c b/arch/arm/mach-s3c24xx/mach-anubis.c
index d03df0df01fa..029ef1b58925 100644
--- a/arch/arm/mach-s3c24xx/mach-anubis.c
+++ b/arch/arm/mach-s3c24xx/mach-anubis.c
@@ -223,6 +223,7 @@ static void anubis_nand_select(struct s3c2410_nand_set *set, int slot)
 	.nr_sets	= ARRAY_SIZE(anubis_nand_sets),
 	.sets		= anubis_nand_sets,
 	.select_chip	= anubis_nand_select,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* IDE channels */
diff --git a/arch/arm/mach-s3c24xx/mach-at2440evb.c b/arch/arm/mach-s3c24xx/mach-at2440evb.c
index 9ae170fef2a7..7b28eb623fc1 100644
--- a/arch/arm/mach-s3c24xx/mach-at2440evb.c
+++ b/arch/arm/mach-s3c24xx/mach-at2440evb.c
@@ -114,6 +114,7 @@
 	.twrph1		= 40,
 	.nr_sets	= ARRAY_SIZE(at2440evb_nand_sets),
 	.sets		= at2440evb_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* DM9000AEP 10/100 ethernet controller */
diff --git a/arch/arm/mach-s3c24xx/mach-bast.c b/arch/arm/mach-s3c24xx/mach-bast.c
index ed07cf392d4b..5185036765db 100644
--- a/arch/arm/mach-s3c24xx/mach-bast.c
+++ b/arch/arm/mach-s3c24xx/mach-bast.c
@@ -299,6 +299,7 @@ static void bast_nand_select(struct s3c2410_nand_set *set, int slot)
 	.nr_sets	= ARRAY_SIZE(bast_nand_sets),
 	.sets		= bast_nand_sets,
 	.select_chip	= bast_nand_select,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* DM9000 */
diff --git a/arch/arm/mach-s3c24xx/mach-gta02.c b/arch/arm/mach-s3c24xx/mach-gta02.c
index 27ae6877550f..b0ed401da3a3 100644
--- a/arch/arm/mach-s3c24xx/mach-gta02.c
+++ b/arch/arm/mach-s3c24xx/mach-gta02.c
@@ -443,6 +443,7 @@ static void gta02_udc_vbus_draw(unsigned int ma)
 	.twrph1		= 15,
 	.nr_sets	= ARRAY_SIZE(gta02_nand_sets),
 	.sets		= gta02_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 
diff --git a/arch/arm/mach-s3c24xx/mach-jive.c b/arch/arm/mach-s3c24xx/mach-jive.c
index 7d99fe8f6157..895aca225952 100644
--- a/arch/arm/mach-s3c24xx/mach-jive.c
+++ b/arch/arm/mach-s3c24xx/mach-jive.c
@@ -232,6 +232,7 @@
 	.twrph1		= 40,
 	.sets		= jive_nand_sets,
 	.nr_sets	= ARRAY_SIZE(jive_nand_sets),
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 static int __init jive_mtdset(char *options)
diff --git a/arch/arm/mach-s3c24xx/mach-mini2440.c b/arch/arm/mach-s3c24xx/mach-mini2440.c
index ec60bd4a1646..71af8d2fd320 100644
--- a/arch/arm/mach-s3c24xx/mach-mini2440.c
+++ b/arch/arm/mach-s3c24xx/mach-mini2440.c
@@ -287,6 +287,7 @@
 	.nr_sets	= ARRAY_SIZE(mini2440_nand_sets),
 	.sets		= mini2440_nand_sets,
 	.ignore_unset_ecc = 1,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* DM9000AEP 10/100 ethernet controller */
diff --git a/arch/arm/mach-s3c24xx/mach-osiris.c b/arch/arm/mach-s3c24xx/mach-osiris.c
index 2f6fdc326835..70b0eb7d3134 100644
--- a/arch/arm/mach-s3c24xx/mach-osiris.c
+++ b/arch/arm/mach-s3c24xx/mach-osiris.c
@@ -238,6 +238,7 @@ static void osiris_nand_select(struct s3c2410_nand_set *set, int slot)
 	.nr_sets	= ARRAY_SIZE(osiris_nand_sets),
 	.sets		= osiris_nand_sets,
 	.select_chip	= osiris_nand_select,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* PCMCIA control and configuration */
diff --git a/arch/arm/mach-s3c24xx/mach-qt2410.c b/arch/arm/mach-s3c24xx/mach-qt2410.c
index 984516e8307a..868c82087403 100644
--- a/arch/arm/mach-s3c24xx/mach-qt2410.c
+++ b/arch/arm/mach-s3c24xx/mach-qt2410.c
@@ -284,6 +284,7 @@
 	.twrph1		= 20,
 	.nr_sets	= ARRAY_SIZE(qt2410_nand_sets),
 	.sets		= qt2410_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* UDC */
diff --git a/arch/arm/mach-s3c24xx/mach-rx1950.c b/arch/arm/mach-s3c24xx/mach-rx1950.c
index 25a139bb9826..e86ad6a68a0b 100644
--- a/arch/arm/mach-s3c24xx/mach-rx1950.c
+++ b/arch/arm/mach-s3c24xx/mach-rx1950.c
@@ -611,6 +611,7 @@ static void rx1950_set_mmc_power(unsigned char power_mode, unsigned short vdd)
 	.twrph1 = 15,
 	.nr_sets = ARRAY_SIZE(rx1950_nand_sets),
 	.sets = rx1950_nand_sets,
+	.ecc_mode = NAND_ECC_SOFT,
 };
 
 static struct s3c2410_udc_mach_info rx1950_udc_cfg __initdata = {
diff --git a/arch/arm/mach-s3c24xx/mach-rx3715.c b/arch/arm/mach-s3c24xx/mach-rx3715.c
index cf55196f89ca..a39fb9780dd3 100644
--- a/arch/arm/mach-s3c24xx/mach-rx3715.c
+++ b/arch/arm/mach-s3c24xx/mach-rx3715.c
@@ -164,6 +164,7 @@
 	.twrph1		= 15,
 	.nr_sets	= ARRAY_SIZE(rx3715_nand_sets),
 	.sets		= rx3715_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 static struct platform_device *rx3715_devices[] __initdata = {
diff --git a/arch/arm/mach-s3c24xx/mach-vstms.c b/arch/arm/mach-s3c24xx/mach-vstms.c
index b4460d5f7011..f5e6322145fa 100644
--- a/arch/arm/mach-s3c24xx/mach-vstms.c
+++ b/arch/arm/mach-s3c24xx/mach-vstms.c
@@ -117,6 +117,7 @@
 	.twrph1		= 20,
 	.nr_sets	= ARRAY_SIZE(vstms_nand_sets),
 	.sets		= vstms_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 static struct platform_device *vstms_devices[] __initdata = {
diff --git a/arch/arm/mach-s3c64xx/mach-hmt.c b/arch/arm/mach-s3c64xx/mach-hmt.c
index bc7dc1fcbf7d..59b5531f1987 100644
--- a/arch/arm/mach-s3c64xx/mach-hmt.c
+++ b/arch/arm/mach-s3c64xx/mach-hmt.c
@@ -204,6 +204,7 @@ static void hmt_bl_exit(struct device *dev)
 	.twrph1		= 40,
 	.nr_sets	= ARRAY_SIZE(hmt_nand_sets),
 	.sets		= hmt_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 static struct gpio_led hmt_leds[] = {
diff --git a/arch/arm/mach-s3c64xx/mach-mini6410.c b/arch/arm/mach-s3c64xx/mach-mini6410.c
index ae999fb3fe6d..a3e3e25728b4 100644
--- a/arch/arm/mach-s3c64xx/mach-mini6410.c
+++ b/arch/arm/mach-s3c64xx/mach-mini6410.c
@@ -142,6 +142,7 @@
 	.twrph1		= 40,
 	.nr_sets	= ARRAY_SIZE(mini6410_nand_sets),
 	.sets		= mini6410_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 static struct s3c_fb_pd_win mini6410_lcd_type0_fb_win = {
diff --git a/arch/arm/mach-s3c64xx/mach-real6410.c b/arch/arm/mach-s3c64xx/mach-real6410.c
index 4e240ffa7ac7..d6b3ffd7704b 100644
--- a/arch/arm/mach-s3c64xx/mach-real6410.c
+++ b/arch/arm/mach-s3c64xx/mach-real6410.c
@@ -194,6 +194,7 @@
 	.twrph1		= 40,
 	.nr_sets	= ARRAY_SIZE(real6410_nand_sets),
 	.sets		= real6410_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 static struct platform_device *real6410_devices[] __initdata = {
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 7b7a887b4709..9748f3580d4b 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -179,15 +179,6 @@ config MTD_NAND_S3C2410_DEBUG
 	help
 	  Enable debugging of the S3C NAND driver
 
-config MTD_NAND_S3C2410_HWECC
-	bool "Samsung S3C NAND Hardware ECC"
-	depends on MTD_NAND_S3C2410
-	help
-	  Enable the use of the controller's internal ECC generator when
-	  using NAND. Early versions of the chips have had problems with
-	  incorrect ECC generation, and if using these, the default of
-	  software ECC is preferable.
-
 config MTD_NAND_NDFC
 	tristate "NDFC NanD Flash Controller"
 	depends on 4xx
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index d459c19d78de..371db0d48135 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -497,7 +497,6 @@ static int s3c2412_nand_devready(struct mtd_info *mtd)
 
 /* ECC handling functions */
 
-#ifdef CONFIG_MTD_NAND_S3C2410_HWECC
 static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
 				     u_char *read_ecc, u_char *calc_ecc)
 {
@@ -649,7 +648,6 @@ static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
 
 	return 0;
 }
-#endif
 
 /* over-ride the standard functions for a little more speed. We can
  * use read/write block to move the data buffers to/from the controller
@@ -858,50 +856,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
 	nmtd->info	   = info;
 	nmtd->set	   = set;
 
-#ifdef CONFIG_MTD_NAND_S3C2410_HWECC
-	chip->ecc.calculate = s3c2410_nand_calculate_ecc;
-	chip->ecc.correct   = s3c2410_nand_correct_data;
-	chip->ecc.mode	    = NAND_ECC_HW;
-	chip->ecc.strength  = 1;
-
-	switch (info->cpu_type) {
-	case TYPE_S3C2410:
-		chip->ecc.hwctl	    = s3c2410_nand_enable_hwecc;
-		chip->ecc.calculate = s3c2410_nand_calculate_ecc;
-		break;
-
-	case TYPE_S3C2412:
-		chip->ecc.hwctl     = s3c2412_nand_enable_hwecc;
-		chip->ecc.calculate = s3c2412_nand_calculate_ecc;
-		break;
-
-	case TYPE_S3C2440:
-		chip->ecc.hwctl     = s3c2440_nand_enable_hwecc;
-		chip->ecc.calculate = s3c2440_nand_calculate_ecc;
-		break;
-	}
-#else
-	chip->ecc.mode	    = NAND_ECC_SOFT;
-	chip->ecc.algo	= NAND_ECC_HAMMING;
-#endif
-
-	if (set->disable_ecc)
-		chip->ecc.mode	= NAND_ECC_NONE;
-
-	switch (chip->ecc.mode) {
-	case NAND_ECC_NONE:
-		dev_info(info->device, "NAND ECC disabled\n");
-		break;
-	case NAND_ECC_SOFT:
-		dev_info(info->device, "NAND soft ECC\n");
-		break;
-	case NAND_ECC_HW:
-		dev_info(info->device, "NAND hardware ECC\n");
-		break;
-	default:
-		dev_info(info->device, "NAND ECC UNKNOWN\n");
-		break;
-	}
+	chip->ecc.mode = info->platform->ecc_mode;
 
 	/* If you use u-boot BBT creation code, specifying this flag will
 	 * let the kernel fish out the BBT from the NAND, and also skip the
@@ -923,28 +878,72 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
  *
  * The internal state is currently limited to the ECC state information.
 */
-static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
+static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
 				     struct s3c2410_nand_mtd *nmtd)
 {
 	struct nand_chip *chip = &nmtd->chip;
 
-	dev_dbg(info->device, "chip %p => page shift %d\n",
-		chip, chip->page_shift);
+	switch (chip->ecc.mode) {
 
-	if (chip->ecc.mode != NAND_ECC_HW)
-		return;
+	case NAND_ECC_NONE:
+		dev_info(info->device, "ECC disabled\n");
+		break;
+
+	case NAND_ECC_SOFT:
+		/*
+		 * This driver expects Hamming based ECC when ecc_mode is set
+		 * to NAND_ECC_SOFT. Force ecc.algo to NAND_ECC_HAMMING to
+		 * avoid adding an extra ecc_algo field to s3c2410_platform_nand.
+		 */
+		chip->ecc.algo = NAND_ECC_HAMMING;
+		dev_info(info->device, "soft ECC\n");
+		break;
+
+	case NAND_ECC_HW:
+		chip->ecc.calculate = s3c2410_nand_calculate_ecc;
+		chip->ecc.correct   = s3c2410_nand_correct_data;
+		chip->ecc.strength  = 1;
+
+		switch (info->cpu_type) {
+		case TYPE_S3C2410:
+			chip->ecc.hwctl	    = s3c2410_nand_enable_hwecc;
+			chip->ecc.calculate = s3c2410_nand_calculate_ecc;
+			break;
+
+		case TYPE_S3C2412:
+			chip->ecc.hwctl     = s3c2412_nand_enable_hwecc;
+			chip->ecc.calculate = s3c2412_nand_calculate_ecc;
+			break;
+
+		case TYPE_S3C2440:
+			chip->ecc.hwctl     = s3c2440_nand_enable_hwecc;
+			chip->ecc.calculate = s3c2440_nand_calculate_ecc;
+			break;
+		}
+
+		dev_dbg(info->device, "chip %p => page shift %d\n",
+			chip, chip->page_shift);
 
 		/* change the behaviour depending on whether we are using
 		 * the large or small page nand device */
+		if (chip->page_shift > 10) {
+			chip->ecc.size	    = 256;
+			chip->ecc.bytes	    = 3;
+		} else {
+			chip->ecc.size	    = 512;
+			chip->ecc.bytes	    = 3;
+			mtd_set_ooblayout(nand_to_mtd(chip), &s3c2410_ooblayout_ops);
+		}
 
-	if (chip->page_shift > 10) {
-		chip->ecc.size	    = 256;
-		chip->ecc.bytes	    = 3;
-	} else {
-		chip->ecc.size	    = 512;
-		chip->ecc.bytes	    = 3;
-		mtd_set_ooblayout(nand_to_mtd(chip), &s3c2410_ooblayout_ops);
+		dev_info(info->device, "hardware ECC\n");
+		break;
+
+	default:
+		dev_err(info->device, "invalid ECC mode!\n");
+		return -EINVAL;
 	}
+
+	return 0;
 }
 
 /* s3c24xx_nand_probe
@@ -1046,7 +1045,9 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 						 NULL);
 
 		if (nmtd->scan_res == 0) {
-			s3c2410_nand_update_chip(info, nmtd);
+			err = s3c2410_nand_update_chip(info, nmtd);
+			if (err < 0)
+				goto exit_error;
 			nand_scan_tail(mtd);
 			s3c2410_nand_add_partition(info, nmtd, sets);
 		}
diff --git a/include/linux/platform_data/mtd-nand-s3c2410.h b/include/linux/platform_data/mtd-nand-s3c2410.h
index c55e42ee57fa..729af13d1773 100644
--- a/include/linux/platform_data/mtd-nand-s3c2410.h
+++ b/include/linux/platform_data/mtd-nand-s3c2410.h
@@ -12,9 +12,10 @@
 #ifndef __MTD_NAND_S3C2410_H
 #define __MTD_NAND_S3C2410_H
 
+#include <linux/mtd/nand.h>
+
 /**
  * struct s3c2410_nand_set - define a set of one or more nand chips
- * @disable_ecc:	Entirely disable ECC - Dangerous
  * @flash_bbt: 		Openmoko u-boot can create a Bad Block Table
  *			Setting this flag will allow the kernel to
  *			look for it at boot time and also skip the NAND
@@ -31,7 +32,6 @@
  * a warning at boot time.
  */
 struct s3c2410_nand_set {
-	unsigned int		disable_ecc:1;
 	unsigned int		flash_bbt:1;
 
 	unsigned int		options;
@@ -51,6 +51,8 @@ struct s3c2410_platform_nand {
 
 	unsigned int	ignore_unset_ecc:1;
 
+	nand_ecc_modes_t	ecc_mode;
+
 	int			nr_sets;
 	struct s3c2410_nand_set *sets;
 
-- 
1.9.1



From sergio.prado at e-labworks.com  Wed Oct 19 12:52:04 2016
From: sergio.prado at e-labworks.com (Sergio Prado)
Date: Wed, 19 Oct 2016 17:52:04 -0200
Subject: [PATCH v2 2/3] dt-bindings: mtd: add DT binding for s3c2410 flash
 controller
In-Reply-To: <1476906725-22613-1-git-send-email-sergio.prado@e-labworks.com>
References: <1476906725-22613-1-git-send-email-sergio.prado@e-labworks.com>
Message-ID: <1476906725-22613-3-git-send-email-sergio.prado@e-labworks.com>

Adds the device tree bindings description for Samsung S3C2410 and
compatible NAND flash controller.

Signed-off-by: Sergio Prado <sergio.prado at e-labworks.com>
---
 .../devicetree/bindings/mtd/samsung-s3c2410.txt    | 56 ++++++++++++++++++++++
 1 file changed, 56 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt

diff --git a/Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt b/Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt
new file mode 100644
index 000000000000..0040eb8895e0
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt
@@ -0,0 +1,56 @@
+* Samsung S3C2410 and compatible NAND flash controller
+
+Required properties:
+- compatible : The possible values are:
+	"samsung,s3c2410-nand"
+	"samsung,s3c2412-nand"
+	"samsung,s3c2440-nand"
+- reg : register's location and length.
+- #address-cells, #size-cells : see nand.txt
+- clocks : phandle to the nand controller clock
+- clock-names : must contain "nand"
+
+Optional child nodes:
+Child nodes representing the available nand chips.
+
+Optional child properties:
+- nand-ecc-mode : see nand.txt
+- nand-on-flash-bbt : see nand.txt
+
+Each child device node may optionally contain a 'partitions' sub-node,
+which further contains sub-nodes describing the flash partition mapping.
+See partition.txt for more detail.
+
+Example:
+
+nand-controller at 4e000000 {
+	compatible = "samsung,s3c2440-nand";
+	reg = <0x4e000000 0x40>;
+
+	#address-cells = <1>;
+        #size-cells = <0>;
+
+	clocks = <&clocks HCLK_NAND>;
+	clock-names = "nand";
+
+	nand {
+		nand-ecc-mode = "soft";
+		nand-on-flash-bbt;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition at 0 {
+				label = "u-boot";
+				reg = <0 0x040000>;
+			};
+
+			partition at 40000 {
+				label = "kernel";
+				reg = <0x040000 0x500000>;
+			};
+		};
+	};
+};
-- 
1.9.1



From sergio.prado at e-labworks.com  Wed Oct 19 12:52:05 2016
From: sergio.prado at e-labworks.com (Sergio Prado)
Date: Wed, 19 Oct 2016 17:52:05 -0200
Subject: [PATCH v2 3/3] mtd: s3c2410: parse the device configuration from OF
 node
In-Reply-To: <1476906725-22613-1-git-send-email-sergio.prado@e-labworks.com>
References: <1476906725-22613-1-git-send-email-sergio.prado@e-labworks.com>
Message-ID: <1476906725-22613-4-git-send-email-sergio.prado@e-labworks.com>

Allows configuring Samsung's s3c2410 memory controller using a
devicetree.

Signed-off-by: Sergio Prado <sergio.prado at e-labworks.com>
---
 drivers/mtd/nand/s3c2410.c                     | 155 ++++++++++++++++++++++---
 include/linux/platform_data/mtd-nand-s3c2410.h |   1 +
 2 files changed, 140 insertions(+), 16 deletions(-)

diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index 371db0d48135..52f768f01b0d 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -39,6 +39,8 @@
 #include <linux/slab.h>
 #include <linux/clk.h>
 #include <linux/cpufreq.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
@@ -185,6 +187,22 @@ struct s3c2410_nand_info {
 #endif
 };
 
+struct s3c24XX_nand_devtype_data {
+	enum s3c_cpu_type type;
+};
+
+static const struct s3c24XX_nand_devtype_data s3c2410_nand_devtype_data = {
+	.type = TYPE_S3C2410,
+};
+
+static const struct s3c24XX_nand_devtype_data s3c2412_nand_devtype_data = {
+	.type = TYPE_S3C2412,
+};
+
+static const struct s3c24XX_nand_devtype_data s3c2440_nand_devtype_data = {
+	.type = TYPE_S3C2440,
+};
+
 /* conversion functions */
 
 static struct s3c2410_nand_mtd *s3c2410_nand_mtd_toours(struct mtd_info *mtd)
@@ -794,6 +812,34 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
 	return -ENODEV;
 }
 
+static int s3c2410_nand_setup_data_interface(struct mtd_info *mtd,
+					     const struct nand_data_interface *conf,
+					     bool check_only)
+{
+	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+	struct s3c2410_platform_nand *pdata = info->platform;
+	struct device_node *np = info->device->of_node;
+	const struct nand_sdr_timings *timings;
+	int tacls;
+
+	/* auto-detect timings when booting with a device tree */
+	if (np) {
+		timings = nand_get_sdr_timings(conf);
+		if (IS_ERR(timings))
+			return -ENOTSUPP;
+
+		tacls = timings->tCLS_min - timings->tWP_min;
+		if (tacls < 0)
+			tacls = 0;
+
+		pdata->tacls  = DIV_ROUND_UP(tacls, 1000);
+		pdata->twrph0 = DIV_ROUND_UP(timings->tWP_min, 1000);
+		pdata->twrph1 = DIV_ROUND_UP(timings->tCLH_min, 1000);
+	}
+
+	return 0;
+}
+
 /**
  * s3c2410_nand_init_chip - initialise a single instance of an chip
  * @info: The base NAND controller the chip is on.
@@ -811,9 +857,12 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
 	struct nand_chip *chip = &nmtd->chip;
 	void __iomem *regs = info->regs;
 
+	nand_set_flash_node(chip, set->of_node);
+
 	chip->write_buf    = s3c2410_nand_write_buf;
 	chip->read_buf     = s3c2410_nand_read_buf;
 	chip->select_chip  = s3c2410_nand_select_chip;
+	chip->setup_data_interface = s3c2410_nand_setup_data_interface;
 	chip->chip_delay   = 50;
 	nand_set_controller_data(chip, nmtd);
 	chip->options	   = set->options;
@@ -859,12 +908,9 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
 	chip->ecc.mode = info->platform->ecc_mode;
 
 	/* If you use u-boot BBT creation code, specifying this flag will
-	 * let the kernel fish out the BBT from the NAND, and also skip the
-	 * full NAND scan that can take 1/2s or so. Little things... */
-	if (set->flash_bbt) {
+	 * let the kernel fish out the BBT from the NAND */
+	if (set->flash_bbt)
 		chip->bbt_options |= NAND_BBT_USE_FLASH;
-		chip->options |= NAND_SKIP_BBTSCAN;
-	}
 }
 
 /**
@@ -943,6 +989,77 @@ static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
 		return -EINVAL;
 	}
 
+	if (chip->bbt_options & NAND_BBT_USE_FLASH)
+		chip->options |= NAND_SKIP_BBTSCAN;
+
+	return 0;
+}
+
+static const struct of_device_id s3c24xx_nand_dt_ids[] = {
+	{
+		.compatible = "samsung,s3c2410-nand",
+		.data = &s3c2410_nand_devtype_data,
+	}, {
+		.compatible = "samsung,s3c2412-nand", /* also compatible with s3c6400 */
+		.data = &s3c2412_nand_devtype_data,
+	}, {
+		.compatible = "samsung,s3c2440-nand",
+		.data = &s3c2440_nand_devtype_data,
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, s3c24xx_nand_dt_ids);
+
+static int s3c24xx_nand_probe_dt(struct platform_device *pdev)
+{
+	const struct s3c24XX_nand_devtype_data *devtype_data;
+	struct s3c2410_platform_nand *pdata;
+	struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
+	struct device_node *np = pdev->dev.of_node, *child;
+	struct s3c2410_nand_set *sets;
+
+	devtype_data = of_device_get_match_data(&pdev->dev);
+	if (!devtype_data)
+		return -ENODEV;
+
+	info->cpu_type = devtype_data->type;
+
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	pdev->dev.platform_data = pdata;
+
+	pdata->nr_sets = of_get_child_count(np);
+	if (!pdata->nr_sets)
+		return 0;
+
+	sets = devm_kzalloc(&pdev->dev, sizeof(*sets) * pdata->nr_sets, GFP_KERNEL);
+	if (!sets)
+		return -ENOMEM;
+
+	pdata->sets = sets;
+
+	for_each_available_child_of_node(np, child) {
+
+		sets->name = (char *)child->name;
+		sets->of_node = child;
+		sets->nr_chips = 1;
+
+		of_node_get(child);
+
+		sets++;
+	}
+
+	return 0;
+}
+
+static int s3c24xx_nand_probe_pdata(struct platform_device *pdev)
+{
+	struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
+
+	info->cpu_type = platform_get_device_id(pdev)->driver_data;
+
 	return 0;
 }
 
@@ -955,8 +1072,7 @@ static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
 */
 static int s3c24xx_nand_probe(struct platform_device *pdev)
 {
-	struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
-	enum s3c_cpu_type cpu_type;
+	struct s3c2410_platform_nand *plat;
 	struct s3c2410_nand_info *info;
 	struct s3c2410_nand_mtd *nmtd;
 	struct s3c2410_nand_set *sets;
@@ -966,8 +1082,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 	int nr_sets;
 	int setno;
 
-	cpu_type = platform_get_device_id(pdev)->driver_data;
-
 	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
 	if (info == NULL) {
 		err = -ENOMEM;
@@ -989,6 +1103,16 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 
 	s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
 
+	if (pdev->dev.of_node)
+		err = s3c24xx_nand_probe_dt(pdev);
+	else
+		err = s3c24xx_nand_probe_pdata(pdev);
+
+	if (err)
+		goto exit_error;
+
+	plat = to_nand_plat(pdev);
+
 	/* allocate and map the resource */
 
 	/* currently we assume we have the one resource */
@@ -997,7 +1121,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 
 	info->device	= &pdev->dev;
 	info->platform	= plat;
-	info->cpu_type	= cpu_type;
 
 	info->regs = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(info->regs)) {
@@ -1007,12 +1130,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 
 	dev_dbg(&pdev->dev, "mapped registers at %p\n", info->regs);
 
-	/* initialise the hardware */
-
-	err = s3c2410_nand_inithw(info);
-	if (err != 0)
-		goto exit_error;
-
 	sets = (plat != NULL) ? plat->sets : NULL;
 	nr_sets = (plat != NULL) ? plat->nr_sets : 1;
 
@@ -1056,6 +1173,11 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 			sets++;
 	}
 
+	/* initialise the hardware */
+	err = s3c2410_nand_inithw(info);
+	if (err != 0)
+		goto exit_error;
+
 	err = s3c2410_nand_cpufreq_register(info);
 	if (err < 0) {
 		dev_err(&pdev->dev, "failed to init cpufreq support\n");
@@ -1156,6 +1278,7 @@ static int s3c24xx_nand_resume(struct platform_device *dev)
 	.id_table	= s3c24xx_driver_ids,
 	.driver		= {
 		.name	= "s3c24xx-nand",
+		.of_match_table = s3c24xx_nand_dt_ids,
 	},
 };
 
diff --git a/include/linux/platform_data/mtd-nand-s3c2410.h b/include/linux/platform_data/mtd-nand-s3c2410.h
index 729af13d1773..f01659026b26 100644
--- a/include/linux/platform_data/mtd-nand-s3c2410.h
+++ b/include/linux/platform_data/mtd-nand-s3c2410.h
@@ -40,6 +40,7 @@ struct s3c2410_nand_set {
 	char			*name;
 	int			*nr_map;
 	struct mtd_partition	*partitions;
+	struct device_node	*of_node;
 };
 
 struct s3c2410_platform_nand {
-- 
1.9.1



From boris.brezillon at free-electrons.com  Wed Oct 19 13:10:12 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Wed, 19 Oct 2016 22:10:12 +0200
Subject: [PATCH v2 3/3] mtd: s3c2410: parse the device configuration
 from OF node
In-Reply-To: <1476906725-22613-4-git-send-email-sergio.prado@e-labworks.com>
References: <1476906725-22613-1-git-send-email-sergio.prado@e-labworks.com>
 <1476906725-22613-4-git-send-email-sergio.prado@e-labworks.com>
Message-ID: <20161019221012.5a20e7df@bbrezillon>

On Wed, 19 Oct 2016 17:52:05 -0200
Sergio Prado <sergio.prado at e-labworks.com> wrote:

> Allows configuring Samsung's s3c2410 memory controller using a
> devicetree.
> 
> Signed-off-by: Sergio Prado <sergio.prado at e-labworks.com>
> ---
>  drivers/mtd/nand/s3c2410.c                     | 155 ++++++++++++++++++++++---
>  include/linux/platform_data/mtd-nand-s3c2410.h |   1 +
>  2 files changed, 140 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
> index 371db0d48135..52f768f01b0d 100644
> --- a/drivers/mtd/nand/s3c2410.c
> +++ b/drivers/mtd/nand/s3c2410.c
> @@ -39,6 +39,8 @@
>  #include <linux/slab.h>
>  #include <linux/clk.h>
>  #include <linux/cpufreq.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
>  
>  #include <linux/mtd/mtd.h>
>  #include <linux/mtd/nand.h>
> @@ -185,6 +187,22 @@ struct s3c2410_nand_info {
>  #endif
>  };
>  
> +struct s3c24XX_nand_devtype_data {
> +	enum s3c_cpu_type type;
> +};
> +
> +static const struct s3c24XX_nand_devtype_data s3c2410_nand_devtype_data = {
> +	.type = TYPE_S3C2410,
> +};
> +
> +static const struct s3c24XX_nand_devtype_data s3c2412_nand_devtype_data = {
> +	.type = TYPE_S3C2412,
> +};
> +
> +static const struct s3c24XX_nand_devtype_data s3c2440_nand_devtype_data = {
> +	.type = TYPE_S3C2440,
> +};
> +
>  /* conversion functions */
>  
>  static struct s3c2410_nand_mtd *s3c2410_nand_mtd_toours(struct mtd_info *mtd)
> @@ -794,6 +812,34 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
>  	return -ENODEV;
>  }
>  
> +static int s3c2410_nand_setup_data_interface(struct mtd_info *mtd,
> +					     const struct nand_data_interface *conf,
> +					     bool check_only)
> +{
> +	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
> +	struct s3c2410_platform_nand *pdata = info->platform;
> +	struct device_node *np = info->device->of_node;
> +	const struct nand_sdr_timings *timings;
> +	int tacls;
> +
> +	/* auto-detect timings when booting with a device tree */
> +	if (np) {

That's not really dependent on the use of DT, but I understand why you
want to keep it unchanged for users who did not switch to DT.

Instead of testing the np value here, I'd recommend that you
conditionally assign chip->setup_data_interface to
s3c2410_nand_setup_data_interface in s3c2410_nand_init_chip().

Can you also explain in more details in the comment why you don't want
to do it for non-DT configs (keep behavior unchanged for legacy boards)?

> +		timings = nand_get_sdr_timings(conf);
> +		if (IS_ERR(timings))
> +			return -ENOTSUPP;
> +
> +		tacls = timings->tCLS_min - timings->tWP_min;
> +		if (tacls < 0)
> +			tacls = 0;
> +
> +		pdata->tacls  = DIV_ROUND_UP(tacls, 1000);
> +		pdata->twrph0 = DIV_ROUND_UP(timings->tWP_min, 1000);
> +		pdata->twrph1 = DIV_ROUND_UP(timings->tCLH_min, 1000);
> +	}
> +
> +	return 0;
> +}




From joel.esponde at honeywell.com  Wed Oct 19 15:11:18 2016
From: joel.esponde at honeywell.com (=?UTF-8?q?Jo=C3=ABl=20Esponde?=)
Date: Thu, 20 Oct 2016 00:11:18 +0200
Subject: [PATCH] mtd: spi-nor: fixed spansion quad enable
Message-ID: <1476915078-98841-1-git-send-email-joel.esponde@honeywell.com>

With the S25FL127S nor flash part, each writing to the configuration 
register takes hundreds of ms. During that  time, no more accesses to 
the flash should be done (even reads).

This commit adds:
- a pre check of the quad enable bit to avoid a useless and time 
  consuming writing to the flash,
- a wait loop after the register writing until the flash finishes its 
  work.

This issue could make rootfs mounting fail when the latter was done too 
much closely to this quad enable bit setting step. And in this case, a 
driver as UBIFS may try to recover the filesystem and may broke it 
completely.
---
 drivers/mtd/spi-nor/spi-nor.c | 31 +++++++++++++++++++++++++++----
 1 file changed, 27 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index d0fc165..df43cd7 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1246,18 +1246,41 @@ static int spansion_quad_enable(struct spi_nor *nor)
 	int ret;
 	int quad_en = CR_QUAD_EN_SPAN << 8;
 
+	/* check quad enable bit
+	 * as S25FL127S takes 200 ms to execute each write of SR & CR 
+	 * registers even if data is the same, write step will be shorted 
+	 * if not needed
+	 */
+	ret = read_cr(nor);
+	if (ret < 0) {
+		dev_err(nor->dev, "error %d reading CR\n", ret);
+		return ret;
+	} 
+	if (ret & CR_QUAD_EN_SPAN) {
+		/* quad enable bit is already set */
+		return 0;
+	}
+
+	/* set SR & CR, enable quad I/O */
 	write_enable(nor);
 
 	ret = write_sr_cr(nor, quad_en);
 	if (ret < 0) {
-		dev_err(nor->dev,
-			"error while writing configuration register\n");
+		dev_err(nor->dev, "error while writing SR and CR registers\n");
 		return -EINVAL;
 	}
 
-	/* read back and check it */
+	ret = spi_nor_wait_till_ready(nor);
+	if (ret)
+		return ret;
+	
+	/* read CR and check it */
 	ret = read_cr(nor);
-	if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
+	if (ret < 0) {
+		dev_err(nor->dev, "error %d reading CR\n", ret);
+		return ret;
+	}
+	if (!(ret & CR_QUAD_EN_SPAN)) {
 		dev_err(nor->dev, "Spansion Quad bit not set\n");
 		return -EINVAL;
 	}
-- 
2.7.4



From pascal.eberhard at gmail.com  Wed Oct 19 17:04:36 2016
From: pascal.eberhard at gmail.com (Pascal Eberhard)
Date: Thu, 20 Oct 2016 02:04:36 +0200
Subject: [PATCH] ubifs: implement POSIX Access Control Lists (ACLs)
In-Reply-To: <CAHc6FU7Sh3cX2NAs6bu1jBWQwwpQK0OLsLMAEZMpzocb7L5teg@mail.gmail.com>
References: <1476046382-19185-1-git-send-email-pascal.eberhard@gmail.com>
 <443b11a2-729a-32ec-0a6f-5a3276290329@nod.at>
 <CAHc6FU7Sh3cX2NAs6bu1jBWQwwpQK0OLsLMAEZMpzocb7L5teg@mail.gmail.com>
Message-ID: <b33816493ce16664014c1410bb144211@38plumes.fr>

Hi Andreas,

Thanks for your comments.

On 2016-10-19 16:34, Andreas Gruenbacher wrote:
> Pascal,
> 
> On Tue, Oct 18, 2016 at 11:32 PM, Richard Weinberger <richard at nod.at> 
> wrote:
>> Pascal,
>> 
>> On 09.10.2016 22:53, Pascal Eberhard wrote:
>>> This patch implements POSIX Access Control Lists (ACLs) in UBIFS.
>>> It uses posix_acl_(access|default)_xattr_handler ACL generic handlers
>>> as xattr handlers are now used in UBIFS.
>> 
>> Cool! :)
>> CC'ing Andreas, maybe he also has comments.
> 
> please run this through xfstests as well. Note the following fixes /
> improvements I've made in the course of reviewing this; they've
> obviously not been merged, yet:
> 
>   https://github.com/andreas-gruenbacher/xfsprogs-dev/commits/io
>   https://github.com/andreas-gruenbacher/xfstests/commits/tmpfile

Ok, nice :), I will run them.

>>> Signed-off-by: Pascal Eberhard <pascal.eberhard at gmail.com>
>>> ---
>>>  fs/ubifs/Kconfig  |  13 +++++
>>>  fs/ubifs/Makefile |   1 +
>>>  fs/ubifs/acl.c    | 143 
>>> ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>  fs/ubifs/dir.c    |  22 +++++++++
>>>  fs/ubifs/file.c   |   9 ++++
>>>  fs/ubifs/super.c  |  15 ++++++
>>>  fs/ubifs/ubifs.h  |  18 +++++++
>>>  fs/ubifs/xattr.c  |  11 +++--
>>>  8 files changed, 229 insertions(+), 3 deletions(-)
>>>  create mode 100644 fs/ubifs/acl.c
>>> 
>>> diff --git a/fs/ubifs/Kconfig b/fs/ubifs/Kconfig
>>> index 7ff7712..39119e5 100644
>>> --- a/fs/ubifs/Kconfig
>>> +++ b/fs/ubifs/Kconfig
>>> @@ -50,3 +50,16 @@ config UBIFS_ATIME_SUPPORT
>>>         strictatime is the "heavy", relatime is "lighter", etc.
>>> 
>>>         If unsure, say 'N'
>>> +
>>> +config UBIFS_FS_POSIX_ACL
>>> +     bool "UBIFS POSIX Access Control Lists"
>>> +     depends on UBIFS_FS
>>> +     select FS_POSIX_ACL
>>> +     help
>>> +       POSIX Access Control Lists (ACLs) support permissions for 
>>> users and
>>> +       groups beyond the owner/group/world scheme.
>>> +
>>> +       To learn more about Access Control Lists, visit the POSIX 
>>> ACLs for
>>> +       Linux website <http://acl.bestbits.at/>.
>>> +
>>> +       If you don't know what Access Control Lists are, say N
>>> diff --git a/fs/ubifs/Makefile b/fs/ubifs/Makefile
>>> index c54a243..af7a83f 100644
>>> --- a/fs/ubifs/Makefile
>>> +++ b/fs/ubifs/Makefile
>>> @@ -5,3 +5,4 @@ ubifs-y += tnc.o master.o scan.o replay.o log.o 
>>> commit.o gc.o orphan.o
>>>  ubifs-y += budget.o find.o tnc_commit.o compress.o lpt.o lprops.o
>>>  ubifs-y += recovery.o ioctl.o lpt_commit.o tnc_misc.o xattr.o 
>>> debug.o
>>>  ubifs-y += misc.o
>>> +ubifs-$(CONFIG_UBIFS_FS_POSIX_ACL) += acl.o
>>> \ No newline at end of file
>>> diff --git a/fs/ubifs/acl.c b/fs/ubifs/acl.c
>>> new file mode 100644
>>> index 0000000..a4d4734
>>> --- /dev/null
>>> +++ b/fs/ubifs/acl.c
>>> @@ -0,0 +1,143 @@
>>> +/*
>>> + * This file is part of UBIFS.
>>> + *
>>> + * This program is free software; you can redistribute it and/or 
>>> modify it
>>> + * under the terms of the GNU General Public License version 2 as 
>>> published by
>>> + * the Free Software Foundation.
>>> + *
>>> + * This program is distributed in the hope that it will be useful, 
>>> but WITHOUT
>>> + * ANY WARRANTY; without even the implied warranty of 
>>> MERCHANTABILITY or
>>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public 
>>> License for
>>> + * more details.
>>> + *
>>> + */
>>> +
>>> +#include <linux/fs.h>
>> 
>> ubifs.h includes this already.
>> 
>>> +#include <linux/xattr.h>
>> 
>> Ditto.
>> 
>>> +#include <linux/posix_acl_xattr.h>
>>> +
>>> +#include "ubifs.h"
>>> +
>>> +struct posix_acl *ubifs_get_acl(struct inode *inode, int type)
>>> +{
>>> +     int size;
>>> +     const char *name;
>>> +     char *value = NULL;
>>> +     struct posix_acl *acl;
>>> +
>>> +     switch (type) {
>>> +     case ACL_TYPE_ACCESS:
>>> +             name = XATTR_NAME_POSIX_ACL_ACCESS;
>>> +             break;
>>> +     case ACL_TYPE_DEFAULT:
>>> +             name = XATTR_NAME_POSIX_ACL_DEFAULT;
>>> +             break;
>>> +     default:
>>> +             return ERR_PTR(-EINVAL);
>>> +     }
>>> +
>>> +     size = __ubifs_getxattr(inode, name, NULL, 0);
>>> +     if (size > 0) {
>>> +             value = kzalloc(size, GFP_KERNEL);
>>> +             if (!value)
>>> +                     return ERR_PTR(-ENOMEM);
>>> +             size = __ubifs_getxattr(inode, name, value, size);
>>> +     }
>>> +     if (size > 0)
>>> +             acl = posix_acl_from_xattr(&init_user_ns, value, size);
>>> +     else if (size == -ERANGE || size == -ENODATA || size == 0)
>>> +             acl = NULL;
>>> +     else
>>> +             acl = ERR_PTR(size);
>>> +
>>> +     kfree(value);
>>> +     if (!IS_ERR(acl))
>>> +             set_cached_acl(inode, type, acl);
> 
> The get_acl inode operation should no longer call set_cached_acl; the
> cached ACL is updated automatically. (It's correct to use
> set_cached_acl in the set_acl inode operation though.)

ok

>>> +
>>> +     return acl;
>>> +}
>>> +
>>> +int ubifs_set_acl(struct inode *inode, struct posix_acl *acl, int 
>>> type)
>>> +{
>>> +     int ret;
>>> +     int size = 0;
>>> +     const char *name;
>>> +     char *value = NULL;
>>> +     int flags = 0;
>>> +
>>> +     switch (type) {
>>> +     case ACL_TYPE_ACCESS:
>>> +             name = XATTR_NAME_POSIX_ACL_ACCESS;
>>> +             if (acl) {
>>> +                     ret = posix_acl_equiv_mode(acl, 
>>> &inode->i_mode);
>>> +                     if (ret < 0)
>>> +                             return ret;
>>> +                     if (ret == 0)
>>> +                             acl = NULL;
>>> +             }
>>> +             ret = 0;
>>> +             break;
>>> +     case ACL_TYPE_DEFAULT:
>>> +             if (!S_ISDIR(inode->i_mode))
>>> +                     return acl ? -EINVAL : 0;
>>> +             name = XATTR_NAME_POSIX_ACL_DEFAULT;
>>> +             break;
>>> +     default:
>>> +             return -EINVAL;
>>> +     }
>>> +
>>> +     if (acl) {
>>> +             size = posix_acl_xattr_size(acl->a_count);
>>> +             value = kmalloc(size, GFP_KERNEL);
>>> +             if (!value)
>>> +                     return -ENOMEM;
>>> +
>>> +             ret = posix_acl_to_xattr(&init_user_ns, acl, value, 
>>> size);
>>> +             if (ret < 0)
>>> +                     goto out;
>>> +     }
>>> +
>>> +     if (size == 0)
>>> +             flags = XATTR_REPLACE;
>>> +     ret = __ubifs_setxattr(inode, name, value, size, flags);
>>> +
>>> +out:
>>> +     kfree(value);
>>> +     if (!ret)
>>> +             set_cached_acl(inode, type, acl);
>>> +
>>> +     return ret;
>>> +}
>>> +
>>> +/*
>>> + * Initialize the ACLs of a new inode.
>> 
>> Please use the Javadoc style we use for all UBIFS functions.
>> (applies to other functions too in this patch)-
>> 
>>> + */
>>> +int ubifs_init_acl(struct inode *dir, struct inode *inode)
>>> +{
>>> +     struct posix_acl *default_acl, *acl;
>>> +     int ret = 0;
>>> +
>>> +     ret = posix_acl_create(dir, &inode->i_mode, &default_acl, 
>>> &acl);
>>> +     if (ret)
>>> +             return ret;
>>> +
>>> +     if (default_acl) {
>>> +             inode_lock(inode);
> 
> Why the inode locking here?

I see no reason why we should keep it but I will double check.

>>> +             ret = ubifs_set_acl(inode, default_acl, 
>>> ACL_TYPE_DEFAULT);
>>> +             inode_unlock(inode);
>>> +             posix_acl_release(default_acl);
>>> +     }
>>> +
>>> +     if (acl) {
>>> +             if (!ret) {
>>> +                     inode_lock(inode);
> 
> Same here.

Same here :)

>>> +                     ret = ubifs_set_acl(inode, acl, 
>>> ACL_TYPE_ACCESS);
>>> +                     inode_unlock(inode);
>>> +             }
>>> +             posix_acl_release(acl);
>>> +     }
>>> +
>>> +     if (!default_acl && !acl)
>>> +             cache_no_acl(inode);
> 
> This call to cache_no_acl doesn't make sense; please check. It may be
> wrong in btrfs as well; copying Josef for that.

Both i_acl and i_default_acl are set to ACL_NOT_CACHED when entering
ubifs_init_acl().
As proposed, the function will be updated so cache_no_acl() will be
called unconditionally before setting the actual ACLs (if any).

>>> +     return ret;
>>> +}
>>> diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
>>> index ccd9128..a2e5609 100644
>>> --- a/fs/ubifs/dir.c
>>> +++ b/fs/ubifs/dir.c
>>> @@ -270,6 +270,10 @@ static int ubifs_create(struct inode *dir, 
>>> struct dentry *dentry, umode_t mode,
>>>               goto out_budg;
>>>       }
>>> 
>>> +     err = ubifs_init_acl(dir, inode);
>>> +     if (err)
>>> +             goto out_inode;
>>> +
> 
> The pattern ubifs_budget_space / ubifs_new_inode / ubifs_init_acl /
> ubifs_init_security repeats a number of times in the code, so it
> should probably be put in a function.

I will look into it.

>>>       err = ubifs_init_security(dir, inode, &dentry->d_name);
>>>       if (err)
>>>               goto out_inode;
>>> @@ -341,6 +345,10 @@ static int do_tmpfile(struct inode *dir, struct 
>>> dentry *dentry,
>>>               ubifs_assert(inode->i_op == 
>>> &ubifs_file_inode_operations);
>>>       }
>>> 
>>> +     err = ubifs_init_acl(dir, inode);
>>> +     if (err)
>>> +             goto out_inode;
>> 
>> Why do we need ACLs for O_TMPFILE?
>> 
>>> +
>>>       err = ubifs_init_security(dir, inode, &dentry->d_name);
>>>       if (err)
>>>               goto out_inode;
>>> @@ -821,6 +829,10 @@ static int ubifs_mkdir(struct inode *dir, struct 
>>> dentry *dentry, umode_t mode)
>>>               goto out_budg;
>>>       }
>>> 
>>> +     err = ubifs_init_acl(dir, inode);
>>> +     if (err)
>>> +             goto out_inode;
>>> +
>>>       err = ubifs_init_security(dir, inode, &dentry->d_name);
>>>       if (err)
>>>               goto out_inode;
>>> @@ -903,6 +915,10 @@ static int ubifs_mknod(struct inode *dir, struct 
>>> dentry *dentry,
>>>       ui->data = dev;
>>>       ui->data_len = devlen;
>>> 
>>> +     err = ubifs_init_acl(dir, inode);
>>> +     if (err)
>>> +             goto out_inode;
>>> +
>>>       err = ubifs_init_security(dir, inode, &dentry->d_name);
>>>       if (err)
>>>               goto out_inode;
>>> @@ -985,6 +1001,10 @@ static int ubifs_symlink(struct inode *dir, 
>>> struct dentry *dentry,
>>>       ui->data_len = len;
>>>       inode->i_size = ubifs_inode(inode)->ui_size = len;
>>> 
>>> +     err = ubifs_init_acl(dir, inode);
>>> +     if (err)
>>> +             goto out_inode;
>> 
>> Do we really need ACLs for symlinks too? I thought permissions for 
>> symlinks are irrelevant.
>> 
>>>       err = ubifs_init_security(dir, inode, &dentry->d_name);
>>>       if (err)
>>>               goto out_inode;
>>> @@ -1395,6 +1415,8 @@ const struct inode_operations 
>>> ubifs_dir_inode_operations = {
>>>       .update_time = ubifs_update_time,
>>>  #endif
>>>       .tmpfile     = ubifs_tmpfile,
>>> +     .get_acl     = ubifs_get_acl,
>>> +     .set_acl     = ubifs_set_acl,
>>>  };
>>> 
>>>  const struct file_operations ubifs_dir_operations = {
>>> diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
>>> index 4ed270b..17f6098 100644
>>> --- a/fs/ubifs/file.c
>>> +++ b/fs/ubifs/file.c
>>> @@ -53,6 +53,7 @@
>>>  #include <linux/mount.h>
>>>  #include <linux/slab.h>
>>>  #include <linux/migrate.h>
>>> +#include <linux/posix_acl.h>
>>> 
>>>  static int read_block(struct inode *inode, void *addr, unsigned int 
>>> block,
>>>                     struct ubifs_data_node *dn)
>>> @@ -1251,6 +1252,10 @@ static int do_setattr(struct ubifs_info *c, 
>>> struct inode *inode,
>>>               ubifs_release_budget(c, &req);
>>>       if (IS_SYNC(inode))
>>>               err = inode->i_sb->s_op->write_inode(inode, NULL);
>>> +
>>> +     if (!err && (attr->ia_valid & ATTR_MODE))
>>> +             err = posix_acl_chmod(inode, inode->i_mode);
>>> +
>>>       return err;
>>>  }
>>> 
>>> @@ -1628,6 +1633,8 @@ const struct inode_operations 
>>> ubifs_file_inode_operations = {
>>>  #ifdef CONFIG_UBIFS_ATIME_SUPPORT
>>>       .update_time = ubifs_update_time,
>>>  #endif
>>> +     .get_acl     = ubifs_get_acl,
>>> +     .set_acl     = ubifs_set_acl,
>>>  };
>>> 
>>>  const struct inode_operations ubifs_symlink_inode_operations = {
>>> @@ -1642,6 +1649,8 @@ const struct inode_operations 
>>> ubifs_symlink_inode_operations = {
>>>  #ifdef CONFIG_UBIFS_ATIME_SUPPORT
>>>       .update_time = ubifs_update_time,
>>>  #endif
>>> +     .get_acl     = ubifs_get_acl,
>>> +     .set_acl     = ubifs_set_acl,
>>>  };
>>> 
>>>  const struct file_operations ubifs_file_operations = {
>>> diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
>>> index 4ec0510..8239dfd 100644
>>> --- a/fs/ubifs/super.c
>>> +++ b/fs/ubifs/super.c
>>> @@ -444,6 +444,9 @@ static int ubifs_show_options(struct seq_file *s, 
>>> struct dentry *root)
>>>                          ubifs_compr_name(c->mount_opts.compr_type));
>>>       }
>>> 
>>> +     if (c->vfs_sb->s_flags & MS_POSIXACL)
>>> +             seq_puts(s, ",acl");
>>> +
>>>       return 0;
>>>  }
>>> 
>>> @@ -929,6 +932,8 @@ enum {
>>>       Opt_chk_data_crc,
>>>       Opt_no_chk_data_crc,
>>>       Opt_override_compr,
>>> +     Opt_acl,
>>> +     Opt_noacl,
>>>       Opt_err,
>>>  };
>>> 
>>> @@ -940,6 +945,8 @@ static const match_table_t tokens = {
>>>       {Opt_chk_data_crc, "chk_data_crc"},
>>>       {Opt_no_chk_data_crc, "no_chk_data_crc"},
>>>       {Opt_override_compr, "compr=%s"},
>>> +     {Opt_acl, "acl"},
>>> +     {Opt_noacl, "noacl"},
>>>       {Opt_err, NULL},
>>>  };
>>> 
>>> @@ -1040,6 +1047,14 @@ static int ubifs_parse_options(struct 
>>> ubifs_info *c, char *options,
>>>                       c->default_compr = c->mount_opts.compr_type;
>>>                       break;
>>>               }
>>> +#ifdef CONFIG_UBIFS_FS_POSIX_ACL
>>> +             case Opt_acl:
>>> +                     c->vfs_sb->s_flags |= MS_POSIXACL;
>>> +                     break;
>>> +             case Opt_noacl:
>>> +                     c->vfs_sb->s_flags &= ~MS_POSIXACL;
>>> +                     break;
>>> +#endif
>>>               default:
>>>               {
>>>                       unsigned long flag;
>>> diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
>>> index 096035e..7935449 100644
>>> --- a/fs/ubifs/ubifs.h
>>> +++ b/fs/ubifs/ubifs.h
>>> @@ -1743,6 +1743,24 @@ extern const struct xattr_handler 
>>> *ubifs_xattr_handlers[];
>>>  ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t 
>>> size);
>>>  int ubifs_init_security(struct inode *dentry, struct inode *inode,
>>>                       const struct qstr *qstr);
>>> +ssize_t __ubifs_getxattr(struct inode *host, const char *name,
>>> +                             void *buf, size_t size);
>>> +int __ubifs_setxattr(struct inode *host, const char *name,
>>> +                         const void *value, size_t size, int flags);
>>> +
>>> +/* acl.c */
>>> +#ifdef CONFIG_UBIFS_FS_POSIX_ACL
>>> +int ubifs_init_acl(struct inode *dir, struct inode *inode);
>>> +int ubifs_set_acl(struct inode *inode, struct posix_acl *acl, int 
>>> type);
>>> +struct posix_acl *ubifs_get_acl(struct inode *inode, int type);
>>> +#else
>>> +static inline int ubifs_init_acl(struct inode *inode, struct inode 
>>> *dir)
>>> +{
>>> +     return 0;
>>> +}
>>> +#define ubifs_get_acl NULL
>>> +#define ubifs_set_acl NULL
>>> +#endif
>>> 
>>>  /* super.c */
>>>  struct inode *ubifs_iget(struct super_block *sb, unsigned long 
>>> inum);
>>> diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c
>>> index 6c2f4d4..0a596a1 100644
>>> --- a/fs/ubifs/xattr.c
>>> +++ b/fs/ubifs/xattr.c
>>> @@ -52,13 +52,14 @@
>>>   * in the VFS inode cache. The xentries are cached in the LNC cache 
>>> (see
>>>   * tnc.c).
>>>   *
>>> - * ACL support is not implemented.
>>> + * ACL support is now implemented.
>> 
>> I think we can just drop that line now. :-)
>> 
>>>   */
>>> 
>>>  #include "ubifs.h"
>>>  #include <linux/fs.h>
>>>  #include <linux/slab.h>
>>>  #include <linux/xattr.h>
>>> +#include <linux/posix_acl_xattr.h>
>> 
>> While we are here, these includes should also be cleaned up.
>> 
>>>  /*
>>>   * Limit the number of extended attributes per inode so that the 
>>> total size
>>> @@ -268,7 +269,7 @@ static struct inode *iget_xattr(struct ubifs_info 
>>> *c, ino_t inum)
>>>       return ERR_PTR(-EINVAL);
>>>  }
>>> 
>>> -static int __ubifs_setxattr(struct inode *host, const char *name,
>>> +int __ubifs_setxattr(struct inode *host, const char *name,
>>>                           const void *value, size_t size, int flags)
>>>  {
>>>       struct inode *inode;
>>> @@ -328,7 +329,7 @@ out_free:
>>>       return err;
>>>  }
>>> 
>>> -static ssize_t __ubifs_getxattr(struct inode *host, const char 
>>> *name,
>>> +ssize_t __ubifs_getxattr(struct inode *host, const char *name,
>>>                               void *buf, size_t size)
>>>  {
>>>       struct inode *inode;
>>> @@ -619,5 +620,9 @@ const struct xattr_handler 
>>> *ubifs_xattr_handlers[] = {
>>>       &ubifs_user_xattr_handler,
>>>       &ubifs_trusted_xattr_handler,
>>>       &ubifs_security_xattr_handler,
>>> +#ifdef CONFIG_UBIFS_FS_POSIX_ACL
>>> +     &posix_acl_access_xattr_handler,
>>> +     &posix_acl_default_xattr_handler,
>>> +#endif
>>>       NULL
>>>  };
>>> 
>> 
>> Overall the patch does not look bad and I'm sure we can add it for 
>> v4.10 soon.
>> I'm a bit confused since most stuff is not really UBIFS specific.
>> Andreas, is just "normal" for ACL support? I thought most code is 
>> generic and already in VFS.
> 
> There are several filesystems like ubifs that use the xattr
> representation as the on-disk format, so ubifs_get_acl and
> ubifs_set_acl could be abstracted and shared across those filesystems.

I'd like that, unfortunately ubifs_[gs]et_acl() calls 
__ubifs_[gs]etxattr() which
are internal ubifs functions. I am not sure yet how this could be 
abstracted.
I will look into it too.

> The rest looks good.
> 
> Thanks,
> Andreas


From kings3 at absamail.co.za  Wed Oct 19 22:45:33 2016
From: kings3 at absamail.co.za (kings3 at absamail.co.za)
Date: Thu, 20 Oct 2016 07:45:33 +0200
Subject: Funding Approved In Minutes!
Message-ID: <201610200548.u9K5mhlR018908-u9K5mhlS018908@fortimail-02.voxtelecom.co.za>

Hello,

We currently have opennings to fund early startups at the preferential interest rate of two percent per year.

Regards,
Lionel Griffin 


From albert.aribaud at 3adev.fr  Thu Oct 20 00:16:30 2016
From: albert.aribaud at 3adev.fr (Albert ARIBAUD)
Date: Thu, 20 Oct 2016 09:16:30 +0200
Subject: [PATCH 1/2] fsl-quadspi: fix QUAD read, add NORMAL, DUAL and
 FAST reads
In-Reply-To: <69a5b0d7-6b89-7edc-738d-c9e25802ba31@atmel.com>
References: <20160927055957.427-1-albert.aribaud@3adev.fr>
 <69a5b0d7-6b89-7edc-738d-c9e25802ba31@atmel.com>
Message-ID: <20161020091630.3477efab.albert.aribaud@3adev.fr>

Hi Cyrille,

Le Wed, 19 Oct 2016 18:42:36 +0200, Cyrille Pitchen
<cyrille.pitchen at atmel.com> a ?crit :

> Hi Albert,
> 
> +Yunhui


> It seems that both Yunhui and you work on the same topic, maybe you can
> synchronize?
> https://patchwork.ozlabs.org/patch/660356/

I am already preparing a v2 based over Yunhui's series. :)

> I don't think it is a good thing to select the relevant "READ" LUT entry
> according to the command op code. What if spi-nor.c introduces new op codes?
> 
> Maybe you could index the LUT entries by functions:
> - READ_REG: the LUT op code would be dynamically updated by your
>             .read_reg(nor, opcode, ...) implementation according to opcode.
> - WRITE_REG: the same as above with the .write_reg(nor, opcode, ...) hook.
> - READ_SLAVE1: read memory from the first SPI-NOR memory.
> - WRITE_SLAVE1: write into the first SPI-NOR memory.
> - READ_SLAVE2: read memory form the 2nd SPI-NOR memory.
> ...
> - WRITE_SLAVEN: write into the N-th SPI-NOR memory.

Actually, my needs could be met using Han Xu's dynamic LUT entries
without the need to introduce 'virtual' opcodes (and without having
to 'leak back' those new opcodes into other kernel code portions).

The per-slave differences (in my case, bus width essentially) can be
managed though DT entries and corresponding per-nor flags in the driver.

> Also be aware even for the .read() hook the nor->read_opcode might changes
> between calls!

Noted -- I'll check that the driver always use the current NOR codes.

> I don't know whether those comments fit your actual needs and the Freescale SPI
> controller hardware constraints but I'm always worried about the ease to maintain
> SPI-NOR controller drivers when they are not "op code agnostic".

Understood and agreed.

Thanks for yuor feedback!
 
> Best regards,
> 
> Cyrille

Cordialement,
Albert ARIBAUD
3ADEV


From albert.aribaud at 3adev.fr  Thu Oct 20 00:17:38 2016
From: albert.aribaud at 3adev.fr (Albert ARIBAUD)
Date: Thu, 20 Oct 2016 09:17:38 +0200
Subject: [PATCH 2/2] fsl-quadspi: introduce per-bus spi-bus-width property
In-Reply-To: <CAMuHMdW-L=Wc7mcs6s_N+joEZ8hX7DLHoY_YU0wuvnM=3DN8ug@mail.gmail.com>
References: <20160927055957.427-1-albert.aribaud@3adev.fr>
 <20160927055957.427-2-albert.aribaud@3adev.fr>
 <20161003185143.GA27634@rob-hp-laptop>
 <CAMuHMdW6WJBj3TiXU0mmwKJmcwp28HEVUSD17-7RH7-UXFtX1g@mail.gmail.com>
 <20161018220334.6452fc5b.albert.aribaud@3adev.fr>
 <CAMuHMdW-L=Wc7mcs6s_N+joEZ8hX7DLHoY_YU0wuvnM=3DN8ug@mail.gmail.com>
Message-ID: <20161020091738.37596c14.albert.aribaud@3adev.fr>

Hi Geert,

Le Wed, 19 Oct 2016 08:57:27 +0200, Geert Uytterhoeven
<geert at linux-m68k.org> a ?crit :

> > The fsl-quadspi driver already supports per-NOR read and erase commands
> > to support heterogeneous NOR setups. A per-NOR bus width property would
> > make sense in this light.  
> 
> spi-[tx]x-bus-width is already a property for the SPI slave, not for
> the whole bus.
> So you can use 4 for the quad-capable device, and 1 or 2 for the other.

My bad, then -- I'll use these.

> Gr{oetje,eeting}s,
> 
>                         Geert

Cordialement,
Albert ARIBAUD
3ADEV


From maxime.ripard at free-electrons.com  Thu Oct 20 01:12:41 2016
From: maxime.ripard at free-electrons.com (Maxime Ripard)
Date: Thu, 20 Oct 2016 10:12:41 +0200
Subject: [PATCH 0/8] ARM: gr8: Add support for the CHIP Pro
Message-ID: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>

Hi,

This is a serie introducing the CHIP Pro support.

The most exciting thing about this is that it's the first board we'll be
able to enable the NAND on, benefiting from the awesome work Boris did over
the last couple of years.

This is possible because the NAND chip is an SLC one, for which we don't
have to wait for the current UBI / UBIFS work.

Let me know what you think,
Maxime

Boris Brezillon (2):
  mtd: nand: sunxi: fix support for 512bytes ECC chunks
  mtd: nand: add support for the TC58NVG2S0H chip

Maxime Ripard (6):
  ARM: gr8: Add the UART3
  ARM: gr8: Fix typo in the i2s mclk pin group
  ARM: gr8: Add missing pwm channel 1 pin
  ARM: gr8: Add UART2 pins
  ARM: gr8: Add UART3 pins
  ARM: gr8: Add CHIP Pro support

 arch/arm/boot/dts/Makefile             |   1 +-
 arch/arm/boot/dts/ntc-gr8-chip-pro.dts | 266 ++++++++++++++++++++++++++-
 arch/arm/boot/dts/ntc-gr8.dtsi         |  47 ++++-
 drivers/mtd/nand/nand_ids.c            |   3 +-
 drivers/mtd/nand/sunxi_nand.c          |   4 +-
 5 files changed, 320 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/boot/dts/ntc-gr8-chip-pro.dts

-- 
git-series 0.8.10


From maxime.ripard at free-electrons.com  Thu Oct 20 01:12:42 2016
From: maxime.ripard at free-electrons.com (Maxime Ripard)
Date: Thu, 20 Oct 2016 10:12:42 +0200
Subject: [PATCH 1/8] mtd: nand: sunxi: fix support for 512bytes ECC chunks
In-Reply-To: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
References: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
Message-ID: <f1cb6efb6817c11b235f073639a137bec6ac17e5.1476951078.git-series.maxime.ripard@free-electrons.com>

From: Boris Brezillon <boris.brezillon at free-electrons.com>

The driver is incorrectly assuming that the ECC block size is always 1k
which is not always true.

Also take the other cases into account.

Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
Signed-off-by: Maxime Ripard <maxime.ripard at free-electrons.com>
---
 drivers/mtd/nand/sunxi_nand.c | 4 ++++
 1 file changed, 4 insertions(+), 0 deletions(-)

diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index 8b8470c4e6d0..e40482a65de6 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -145,6 +145,7 @@
 #define NFC_ECC_PIPELINE	BIT(3)
 #define NFC_ECC_EXCEPTION	BIT(4)
 #define NFC_ECC_BLOCK_SIZE_MSK	BIT(5)
+#define NFC_ECC_BLOCK_512	BIT(5)
 #define NFC_RANDOM_EN		BIT(9)
 #define NFC_RANDOM_DIRECTION	BIT(10)
 #define NFC_ECC_MODE_MSK	GENMASK(15, 12)
@@ -817,6 +818,9 @@ static void sunxi_nfc_hw_ecc_enable(struct mtd_info *mtd)
 	ecc_ctl |= NFC_ECC_EN | NFC_ECC_MODE(data->mode) | NFC_ECC_EXCEPTION |
 		   NFC_ECC_PIPELINE;
 
+	if (nand->ecc.size == 512)
+		ecc_ctl |= NFC_ECC_BLOCK_512;
+
 	writel(ecc_ctl, nfc->regs + NFC_REG_ECC_CTL);
 }
 
-- 
git-series 0.8.10


From maxime.ripard at free-electrons.com  Thu Oct 20 01:12:44 2016
From: maxime.ripard at free-electrons.com (Maxime Ripard)
Date: Thu, 20 Oct 2016 10:12:44 +0200
Subject: [PATCH 3/8] ARM: gr8: Add the UART3
In-Reply-To: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
References: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
Message-ID: <b62c8661eb3c2d72e61511794a3ab1b43f005805.1476951078.git-series.maxime.ripard@free-electrons.com>

The GR8 has access to the UART3 controller, which was missing in the
DTSI. Add it.

Signed-off-by: Maxime Ripard <maxime.ripard at free-electrons.com>
---
 arch/arm/boot/dts/ntc-gr8.dtsi | 10 ++++++++++
 1 file changed, 10 insertions(+), 0 deletions(-)

diff --git a/arch/arm/boot/dts/ntc-gr8.dtsi b/arch/arm/boot/dts/ntc-gr8.dtsi
index ca54e03ef366..d7cf6be2549c 100644
--- a/arch/arm/boot/dts/ntc-gr8.dtsi
+++ b/arch/arm/boot/dts/ntc-gr8.dtsi
@@ -978,6 +978,16 @@
 			status = "disabled";
 		};
 
+		uart3: serial at 01c28c00 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x01c28c00 0x400>;
+			interrupts = <4>;
+			reg-shift = <2>;
+			reg-io-width = <4>;
+			clocks = <&apb1_gates 19>;
+			status = "disabled";
+		};
+
 		i2c0: i2c at 01c2ac00 {
 			compatible = "allwinner,sun4i-a10-i2c";
 			reg = <0x01c2ac00 0x400>;
-- 
git-series 0.8.10


From maxime.ripard at free-electrons.com  Thu Oct 20 01:12:46 2016
From: maxime.ripard at free-electrons.com (Maxime Ripard)
Date: Thu, 20 Oct 2016 10:12:46 +0200
Subject: [PATCH 5/8] ARM: gr8: Add missing pwm channel 1 pin
In-Reply-To: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
References: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
Message-ID: <0df42247c3348e7f6aed945e5669cec87f96f7ac.1476951078.git-series.maxime.ripard@free-electrons.com>

The PWM controller has two different channels, but only the first pin was
exposed in the DTSI. Add the other one.

Signed-off-by: Maxime Ripard <maxime.ripard at free-electrons.com>
---
 arch/arm/boot/dts/ntc-gr8.dtsi | 7 +++++++
 1 file changed, 7 insertions(+), 0 deletions(-)

diff --git a/arch/arm/boot/dts/ntc-gr8.dtsi b/arch/arm/boot/dts/ntc-gr8.dtsi
index 74aff795e723..fad7381630f3 100644
--- a/arch/arm/boot/dts/ntc-gr8.dtsi
+++ b/arch/arm/boot/dts/ntc-gr8.dtsi
@@ -854,6 +854,13 @@
 				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
+			pwm1_pins_a: pwm1 at 0 {
+				allwinner,pins = "PG13";
+				allwinner,function = "pwm1";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
 			spdif_tx_pins_a: spdif at 0 {
 				allwinner,pins = "PB10";
 				allwinner,function = "spdif";
-- 
git-series 0.8.10


From maxime.ripard at free-electrons.com  Thu Oct 20 01:12:47 2016
From: maxime.ripard at free-electrons.com (Maxime Ripard)
Date: Thu, 20 Oct 2016 10:12:47 +0200
Subject: [PATCH 6/8] ARM: gr8: Add UART2 pins
In-Reply-To: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
References: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
Message-ID: <0c1f98755c7dd1764dcd89a599f182a0face286f.1476951078.git-series.maxime.ripard@free-electrons.com>

The UART2 pins were missing from the DTSI. Add them.

Signed-off-by: Maxime Ripard <maxime.ripard at free-electrons.com>
---
 arch/arm/boot/dts/ntc-gr8.dtsi | 14 ++++++++++++++
 1 file changed, 14 insertions(+), 0 deletions(-)

diff --git a/arch/arm/boot/dts/ntc-gr8.dtsi b/arch/arm/boot/dts/ntc-gr8.dtsi
index fad7381630f3..52c150592953 100644
--- a/arch/arm/boot/dts/ntc-gr8.dtsi
+++ b/arch/arm/boot/dts/ntc-gr8.dtsi
@@ -881,6 +881,20 @@
 				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
 				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
+
+			uart2_pins_a: uart2 at 1 {
+				allwinner,pins = "PD2", "PD3";
+				allwinner,function = "uart2";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			uart2_cts_rts_pins_a: uart2-cts-rts at 0 {
+				allwinner,pins = "PD4", "PD5";
+				allwinner,function = "uart2";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
 		};
 
 		pwm: pwm at 01c20e00 {
-- 
git-series 0.8.10


From maxime.ripard at free-electrons.com  Thu Oct 20 01:12:49 2016
From: maxime.ripard at free-electrons.com (Maxime Ripard)
Date: Thu, 20 Oct 2016 10:12:49 +0200
Subject: [PATCH 8/8] ARM: gr8: Add CHIP Pro support
In-Reply-To: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
References: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
Message-ID: <d3f91b731f944fe0e23b4532f6e83a1c2fc345f0.1476951078.git-series.maxime.ripard@free-electrons.com>

The CHIP Pro is a small embeddable board. It features a GR8, an AXP209
PMIC, a 512MB SLC NAND and a WiFi/BT chip.

Signed-off-by: Maxime Ripard <maxime.ripard at free-electrons.com>
---
 arch/arm/boot/dts/Makefile             |   1 +-
 arch/arm/boot/dts/ntc-gr8-chip-pro.dts | 266 ++++++++++++++++++++++++++-
 2 files changed, 267 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/boot/dts/ntc-gr8-chip-pro.dts

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index befcd2619902..3dab5b593158 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -745,6 +745,7 @@ dtb-$(CONFIG_MACH_SUN4I) += \
 	sun4i-a10-pcduino2.dtb \
 	sun4i-a10-pov-protab2-ips9.dtb
 dtb-$(CONFIG_MACH_SUN5I) += \
+	ntc-gr8-chip-pro.dtb \
 	ntc-gr8-evb.dtb \
 	sun5i-a10s-auxtek-t003.dtb \
 	sun5i-a10s-auxtek-t004.dtb \
diff --git a/arch/arm/boot/dts/ntc-gr8-chip-pro.dts b/arch/arm/boot/dts/ntc-gr8-chip-pro.dts
new file mode 100644
index 000000000000..3c86f214c493
--- /dev/null
+++ b/arch/arm/boot/dts/ntc-gr8-chip-pro.dts
@@ -0,0 +1,266 @@
+/*
+ * Copyright 2016 Free Electrons
+ * Copyright 2016 NextThing Co
+ *
+ * Maxime Ripard <maxime.ripard at free-electrons.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "ntc-gr8.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+	model = "NextThing C.H.I.P. Pro";
+	compatible = "nextthing,chip-pro", "nextthing,gr8";
+
+	aliases {
+		i2c0 = &i2c0;
+		i2c1 = &i2c1;
+		serial0 = &uart1;
+		serial1 = &uart2;
+		serial2 = &uart3;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		status {
+			label = "chip-pro:white:status";
+			gpios = <&axp_gpio 2 GPIO_ACTIVE_HIGH>;
+			default-state = "on";
+		};
+	};
+
+	mmc0_pwrseq: mmc0_pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		pinctrl-names = "default";
+		pinctrl-0 = <&wifi_reg_on_pin_chip_pro>;
+		reset-gpios = <&pio 1 10 GPIO_ACTIVE_LOW>; /* PB10 */
+	};
+};
+
+&codec {
+	status = "okay";
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c0_pins_a>;
+	status = "okay";
+
+	axp209: pmic at 34 {
+		reg = <0x34>;
+
+		/*
+		* The interrupt is routed through the "External Fast
+		* Interrupt Request" pin (ball G13 of the module)
+		* directly to the main interrupt controller, without
+		* any other controller interfering.
+		*/
+		interrupts = <0>;
+	};
+};
+
+#include "axp209.dtsi"
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins_a>;
+	status = "disabled";
+};
+
+&i2s0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2s0_mclk_pins_a>, <&i2s0_data_pins_a>;
+	status = "disabled";
+};
+
+&mmc0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins_a>;
+	vmmc-supply = <&reg_vcc3v3>;
+	mmc-pwrseq = <&mmc0_pwrseq>;
+	bus-width = <4>;
+	non-removable;
+	status = "okay";
+};
+
+&nfc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&nand_pins_a &nand_cs0_pins_a &nand_rb0_pins_a>;
+	status = "okay";
+
+	nand at 0 {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		reg = <0>;
+		allwinner,rb = <0>;
+		nand-ecc-mode = "hw";
+	};
+};
+
+&ohci0 {
+	status = "okay";
+};
+
+&otg_sram {
+	status = "okay";
+};
+
+&pio {
+	usb0_id_pin_chip_pro: usb0-id-pin at 0 {
+		allwinner,pins = "PG2";
+		allwinner,function = "gpio_in";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+	};
+
+	wifi_reg_on_pin_chip_pro: wifi-reg-on-pin at 0 {
+		allwinner,pins = "PB10";
+		allwinner,function = "gpio_out";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm0_pins_a>, <&pwm1_pins_a>;
+	status = "disabled";
+};
+
+&reg_dcdc2 {
+	regulator-min-microvolt = <1000000>;
+	regulator-max-microvolt = <1400000>;
+	regulator-name = "vdd-cpu";
+	regulator-always-on;
+};
+
+&reg_dcdc3 {
+	regulator-min-microvolt = <1000000>;
+	regulator-max-microvolt = <1300000>;
+	regulator-name = "vdd-sys";
+	regulator-always-on;
+};
+
+&reg_ldo1 {
+	regulator-name = "vdd-rtc";
+};
+
+&reg_ldo2 {
+	regulator-min-microvolt = <2700000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "avcc";
+	regulator-always-on;
+};
+
+/*
+ * Both LDO3 and LDO4 are used in parallel to power up the
+ * WiFi/BT chip.
+ */
+&reg_ldo3 {
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "vcc-wifi-1";
+	regulator-always-on;
+};
+
+&reg_ldo4 {
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "vcc-wifi-2";
+	regulator-always-on;
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins_a>, <&uart1_cts_rts_pins_a>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins_a>, <&uart2_cts_rts_pins_a>;
+	status = "disabled";
+};
+
+&uart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart3_pins_a>, <&uart3_cts_rts_pins_a>;
+	status = "okay";
+};
+
+&usb_otg {
+	/*
+	 * The CHIP Pro doesn't have a controllable VBUS, nor does it
+	 * have any 5v rail on the board itself.
+	 *
+	 * If one wants to use it as a true OTG port, it should be
+	 * done in the baseboard, and its DT / overlay will add it.
+	 */
+	dr_mode = "otg";
+	status = "okay";
+};
+
+&usb_power_supply {
+	status = "okay";
+};
+
+&usbphy {
+	pinctrl-names = "default";
+	pinctrl-0 = <&usb0_id_pin_chip_pro>;
+	usb0_id_det-gpio = <&pio 6 2 GPIO_ACTIVE_HIGH>; /* PG2 */
+	usb0_vbus_power-supply = <&usb_power_supply>;
+	usb1_vbus-supply = <&reg_vcc5v0>;
+	status = "okay";
+};
-- 
git-series 0.8.10


From maxime.ripard at free-electrons.com  Thu Oct 20 01:12:48 2016
From: maxime.ripard at free-electrons.com (Maxime Ripard)
Date: Thu, 20 Oct 2016 10:12:48 +0200
Subject: [PATCH 7/8] ARM: gr8: Add UART3 pins
In-Reply-To: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
References: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
Message-ID: <cc81030de43c26dfc15ad9a9e525188ad8fb8ec9.1476951078.git-series.maxime.ripard@free-electrons.com>

The UART3 pins were missing from the DTSI. Add them.

Signed-off-by: Maxime Ripard <maxime.ripard at free-electrons.com>
---
 arch/arm/boot/dts/ntc-gr8.dtsi | 14 ++++++++++++++
 1 file changed, 14 insertions(+), 0 deletions(-)

diff --git a/arch/arm/boot/dts/ntc-gr8.dtsi b/arch/arm/boot/dts/ntc-gr8.dtsi
index 52c150592953..4480ffadc42d 100644
--- a/arch/arm/boot/dts/ntc-gr8.dtsi
+++ b/arch/arm/boot/dts/ntc-gr8.dtsi
@@ -895,6 +895,20 @@
 				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
 				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
+
+			uart3_pins_a: uart3 at 1 {
+				allwinner,pins = "PG9", "PG10";
+				allwinner,function = "uart3";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			uart3_cts_rts_pins_a: uart3-cts-rts at 0 {
+				allwinner,pins = "PG11", "PG12";
+				allwinner,function = "uart3";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
 		};
 
 		pwm: pwm at 01c20e00 {
-- 
git-series 0.8.10


From narmstrong at baylibre.com  Thu Oct 20 01:49:01 2016
From: narmstrong at baylibre.com (Neil Armstrong)
Date: Thu, 20 Oct 2016 10:49:01 +0200
Subject: [PATCH v2] mtd: nand: Add OX820 NAND Support
Message-ID: <20161020084901.6486-1-narmstrong@baylibre.com>

Add NAND driver to support the Oxford Semiconductor OX820 NAND Controller.
This is a simple memory mapped NAND controller with single chip select and
software ECC.

Acked-by: Rob Herring <robh at kernel.org>
Signed-off-by: Neil Armstrong <narmstrong at baylibre.com>
---
 .../devicetree/bindings/mtd/oxnas-nand.txt         |  41 +++++
 drivers/mtd/nand/Kconfig                           |   5 +
 drivers/mtd/nand/Makefile                          |   1 +
 drivers/mtd/nand/oxnas_nand.c                      | 196 +++++++++++++++++++++
 4 files changed, 243 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/oxnas-nand.txt
 create mode 100644 drivers/mtd/nand/oxnas_nand.c

Changes since v1 http://lkml.kernel.org/r/20161019145523.6763-1-narmstrong at baylibre.com :
 - Simplify cmd_ctrl command and drop the ctrl address offset
 - Change oxnas_nand struct name to oxnas_nand_ctrl
 - Update DT-Bindings example to reflect the ctrl->chip->partitions hierarchy

Changes since RFC http://lkml.kernel.org/r/20161018090927.1990-1-narmstrong at baylibre.com :
 - Avoid using chip->IO_ADDR*
 - Use new DT structure
 - Assign a chip for the subnode
 - Use the nand_hw_control structure
 - Cleanup probe
 - Cleanup cmd_ctrl by using a context ctrl offset used in write_bytes

diff --git a/Documentation/devicetree/bindings/mtd/oxnas-nand.txt b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
new file mode 100644
index 0000000..33a77b8
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
@@ -0,0 +1,41 @@
+* Oxford Semiconductor OXNAS NAND Controller
+
+Please refer to nand.txt for generic information regarding MTD NAND bindings.
+
+Required properties:
+ - compatible: "oxsemi,ox820-nand"
+ - reg: Base address and length for NAND mapped memory.
+
+Optional Properties:
+ - clocks: phandle to the NAND gate clock if needed.
+ - resets: phandle to the NAND reset control if needed.
+
+Example:
+
+nand: nand-controller at 41000000 {
+	compatible = "oxsemi,ox820-nand";
+	reg = <0x41000000 0x100000>;
+	clocks = <&stdclk CLK_820_NAND>;
+	resets = <&reset RESET_NAND>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	nand at 0 {
+		reg = <0>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		nand-ecc-mode = "soft";
+		nand-ecc-algo = "hamming";
+
+		partition at 0 {
+			label = "boot";
+			reg = <0x00000000 0x00e00000>;
+			read-only;
+		};
+
+		partition at e00000 {
+			label = "ubi";
+			reg = <0x00e00000 0x07200000>;
+		};
+	};
+};
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 7b7a887..c023125 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -426,6 +426,11 @@ config MTD_NAND_ORION
 	  No board specific support is done by this driver, each board
 	  must advertise a platform_device for the driver to attach.
 
+config MTD_NAND_OXNAS
+	tristate "NAND Flash support for Oxford Semiconductor SoC"
+	help
+	  This enables the NAND flash controller on Oxford Semiconductor SoCs.
+
 config MTD_NAND_FSL_ELBC
 	tristate "NAND support for Freescale eLBC controllers"
 	depends on FSL_SOC
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index cafde6f..05fc054 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_MTD_NAND_TMIO)		+= tmio_nand.o
 obj-$(CONFIG_MTD_NAND_PLATFORM)		+= plat_nand.o
 obj-$(CONFIG_MTD_NAND_PASEMI)		+= pasemi_nand.o
 obj-$(CONFIG_MTD_NAND_ORION)		+= orion_nand.o
+obj-$(CONFIG_MTD_NAND_OXNAS)		+= oxnas_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_ELBC)		+= fsl_elbc_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_IFC)		+= fsl_ifc_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_UPM)		+= fsl_upm.o
diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/oxnas_nand.c
new file mode 100644
index 0000000..35c94af
--- /dev/null
+++ b/drivers/mtd/nand/oxnas_nand.c
@@ -0,0 +1,196 @@
+/*
+ * Oxford Semiconductor OXNAS NAND driver
+
+ * Copyright (C) 2016 Neil Armstrong <narmstrong at baylibre.com>
+ * Heavily based on plat_nand.c :
+ * Author: Vitaly Wool <vitalywool at gmail.com>
+ * Copyright (C) 2013 Ma Haijun <mahaijuns at gmail.com>
+ * Copyright (C) 2012 John Crispin <blogic at openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/reset.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of.h>
+
+/* Nand commands */
+#define OXNAS_NAND_CMD_ALE		BIT(18)
+#define OXNAS_NAND_CMD_CLE		BIT(19)
+
+#define OXNAS_NAND_MAX_CHIPS	1
+
+struct oxnas_nand_ctrl {
+	struct nand_hw_control base;
+	void __iomem *io_base;
+	struct clk *clk;
+	struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS];
+};
+
+static uint8_t oxnas_nand_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
+
+	return readb(oxnas->io_base);
+}
+
+static void oxnas_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
+
+	ioread8_rep(oxnas->io_base, buf, len);
+}
+
+static void oxnas_nand_write_buf(struct mtd_info *mtd,
+				 const uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
+
+	iowrite8_rep(oxnas->io_base, buf, len);
+}
+
+/* Single CS command control */
+static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+				unsigned int ctrl)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
+
+	if (ctrl & NAND_CLE)
+		writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_CLE);
+	else if (ctrl & NAND_ALE)
+		writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_ALE);
+}
+
+/*
+ * Probe for the NAND device.
+ */
+static int oxnas_nand_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *nand_np;
+	struct oxnas_nand_ctrl *oxnas;
+	struct nand_chip *chip;
+	struct mtd_info *mtd;
+	struct resource *res;
+	int nchips = 0;
+	int count = 0;
+	int err = 0;
+
+	/* Allocate memory for the device structure (and zero it) */
+	oxnas = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip),
+			    GFP_KERNEL);
+	if (!oxnas)
+		return -ENOMEM;
+
+	nand_hw_control_init(&oxnas->base);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	oxnas->io_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(oxnas->io_base))
+		return PTR_ERR(oxnas->io_base);
+
+	oxnas->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(oxnas->clk))
+		oxnas->clk = NULL;
+
+	/* Only a single chip node is supported */
+	count = of_get_child_count(np);
+	if (count > 1)
+		return -EINVAL;
+
+	clk_prepare_enable(oxnas->clk);
+	device_reset_optional(&pdev->dev);
+
+	for_each_child_of_node(np, nand_np) {
+		chip = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip),
+				    GFP_KERNEL);
+		if (!chip)
+			return -ENOMEM;
+
+		chip->controller = &oxnas->base;
+
+		nand_set_flash_node(chip, nand_np);
+		nand_set_controller_data(chip, oxnas);
+
+		mtd = nand_to_mtd(chip);
+		mtd->dev.parent = &pdev->dev;
+		mtd->priv = chip;
+
+		chip->cmd_ctrl = oxnas_nand_cmd_ctrl;
+		chip->read_buf = oxnas_nand_read_buf;
+		chip->read_byte = oxnas_nand_read_byte;
+		chip->write_buf = oxnas_nand_write_buf;
+		chip->chip_delay = 30;
+
+		/* Scan to find existence of the device */
+		err = nand_scan(mtd, 1);
+		if (err)
+			return err;
+
+		err = mtd_device_register(mtd, NULL, 0);
+		if (err) {
+			nand_release(mtd);
+			return err;
+		}
+
+		oxnas->chips[nchips] = chip;
+		++nchips;
+	}
+
+	/* Exit if no chips found */
+	if (!nchips)
+		return -ENODEV;
+
+	platform_set_drvdata(pdev, oxnas);
+
+	return 0;
+}
+
+static int oxnas_nand_remove(struct platform_device *pdev)
+{
+	struct oxnas_nand_ctrl *oxnas = platform_get_drvdata(pdev);
+
+	if (oxnas->chips[0])
+		nand_release(nand_to_mtd(oxnas->chips[0]));
+
+	clk_disable_unprepare(oxnas->clk);
+
+	return 0;
+}
+
+static const struct of_device_id oxnas_nand_match[] = {
+	{ .compatible = "oxsemi,ox820-nand" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, oxnas_nand_match);
+
+static struct platform_driver oxnas_nand_driver = {
+	.probe	= oxnas_nand_probe,
+	.remove	= oxnas_nand_remove,
+	.driver	= {
+		.name		= "oxnas_nand",
+		.of_match_table = oxnas_nand_match,
+	},
+};
+
+module_platform_driver(oxnas_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Neil Armstrong <narmstrong at baylibre.com>");
+MODULE_DESCRIPTION("Oxnas NAND driver");
+MODULE_ALIAS("platform:oxnas_nand");
-- 
2.7.0



From boris.brezillon at free-electrons.com  Thu Oct 20 02:00:25 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Thu, 20 Oct 2016 11:00:25 +0200
Subject: [PATCH v2] mtd: nand: Add OX820 NAND Support
In-Reply-To: <20161020084901.6486-1-narmstrong@baylibre.com>
References: <20161020084901.6486-1-narmstrong@baylibre.com>
Message-ID: <20161020110025.11b06090@bbrezillon>

On Thu, 20 Oct 2016 10:49:01 +0200
Neil Armstrong <narmstrong at baylibre.com> wrote:

> Add NAND driver to support the Oxford Semiconductor OX820 NAND Controller.
> This is a simple memory mapped NAND controller with single chip select and
> software ECC.
> 
> Acked-by: Rob Herring <robh at kernel.org>
> Signed-off-by: Neil Armstrong <narmstrong at baylibre.com>
> ---
>  .../devicetree/bindings/mtd/oxnas-nand.txt         |  41 +++++
>  drivers/mtd/nand/Kconfig                           |   5 +
>  drivers/mtd/nand/Makefile                          |   1 +
>  drivers/mtd/nand/oxnas_nand.c                      | 196 +++++++++++++++++++++
>  4 files changed, 243 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mtd/oxnas-nand.txt
>  create mode 100644 drivers/mtd/nand/oxnas_nand.c
> 
> Changes since v1 http://lkml.kernel.org/r/20161019145523.6763-1-narmstrong at baylibre.com :
>  - Simplify cmd_ctrl command and drop the ctrl address offset
>  - Change oxnas_nand struct name to oxnas_nand_ctrl
>  - Update DT-Bindings example to reflect the ctrl->chip->partitions hierarchy
> 
> Changes since RFC http://lkml.kernel.org/r/20161018090927.1990-1-narmstrong at baylibre.com :
>  - Avoid using chip->IO_ADDR*
>  - Use new DT structure
>  - Assign a chip for the subnode
>  - Use the nand_hw_control structure
>  - Cleanup probe
>  - Cleanup cmd_ctrl by using a context ctrl offset used in write_bytes
> 
> diff --git a/Documentation/devicetree/bindings/mtd/oxnas-nand.txt b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
> new file mode 100644
> index 0000000..33a77b8
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
> @@ -0,0 +1,41 @@
> +* Oxford Semiconductor OXNAS NAND Controller
> +
> +Please refer to nand.txt for generic information regarding MTD NAND bindings.
> +
> +Required properties:
> + - compatible: "oxsemi,ox820-nand"
> + - reg: Base address and length for NAND mapped memory.
> +
> +Optional Properties:
> + - clocks: phandle to the NAND gate clock if needed.
> + - resets: phandle to the NAND reset control if needed.
> +
> +Example:
> +
> +nand: nand-controller at 41000000 {

'nandc:' or 'nand_ctrl:'

Otherwise it may conflict with a NAND chip alias.
The rest looks good, so no need to send a new version (I can fix it when
applying the patch).

One last thing, I saw there was other people owning boards with this
controller. Can I get one or two Tested-by?

Thanks taking my reviews into account.

Regards,

Boris


From narmstrong at baylibre.com  Thu Oct 20 02:04:29 2016
From: narmstrong at baylibre.com (Neil Armstrong)
Date: Thu, 20 Oct 2016 11:04:29 +0200
Subject: [PATCH v2] mtd: nand: Add OX820 NAND Support
In-Reply-To: <20161020110025.11b06090@bbrezillon>
References: <20161020084901.6486-1-narmstrong@baylibre.com>
 <20161020110025.11b06090@bbrezillon>
Message-ID: <d64d3ed6-b02f-2ad8-3df2-91b3e6d22626@baylibre.com>

On 10/20/2016 11:00 AM, Boris Brezillon wrote:
> On Thu, 20 Oct 2016 10:49:01 +0200
> Neil Armstrong <narmstrong at baylibre.com> wrote:
> 
>> Add NAND driver to support the Oxford Semiconductor OX820 NAND Controller.
>> This is a simple memory mapped NAND controller with single chip select and
>> software ECC.
>>
>> Acked-by: Rob Herring <robh at kernel.org>
>> Signed-off-by: Neil Armstrong <narmstrong at baylibre.com>
>> ---
>>  .../devicetree/bindings/mtd/oxnas-nand.txt         |  41 +++++
>>  drivers/mtd/nand/Kconfig                           |   5 +
>>  drivers/mtd/nand/Makefile                          |   1 +
>>  drivers/mtd/nand/oxnas_nand.c                      | 196 +++++++++++++++++++++
>>  4 files changed, 243 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/mtd/oxnas-nand.txt
>>  create mode 100644 drivers/mtd/nand/oxnas_nand.c
>>
>> Changes since v1 http://lkml.kernel.org/r/20161019145523.6763-1-narmstrong at baylibre.com :
>>  - Simplify cmd_ctrl command and drop the ctrl address offset
>>  - Change oxnas_nand struct name to oxnas_nand_ctrl
>>  - Update DT-Bindings example to reflect the ctrl->chip->partitions hierarchy
>>
>> Changes since RFC http://lkml.kernel.org/r/20161018090927.1990-1-narmstrong at baylibre.com :
>>  - Avoid using chip->IO_ADDR*
>>  - Use new DT structure
>>  - Assign a chip for the subnode
>>  - Use the nand_hw_control structure
>>  - Cleanup probe
>>  - Cleanup cmd_ctrl by using a context ctrl offset used in write_bytes
>>
>> diff --git a/Documentation/devicetree/bindings/mtd/oxnas-nand.txt b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
>> new file mode 100644
>> index 0000000..33a77b8
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
>> @@ -0,0 +1,41 @@
>> +* Oxford Semiconductor OXNAS NAND Controller
>> +
>> +Please refer to nand.txt for generic information regarding MTD NAND bindings.
>> +
>> +Required properties:
>> + - compatible: "oxsemi,ox820-nand"
>> + - reg: Base address and length for NAND mapped memory.
>> +
>> +Optional Properties:
>> + - clocks: phandle to the NAND gate clock if needed.
>> + - resets: phandle to the NAND reset control if needed.
>> +
>> +Example:
>> +
>> +nand: nand-controller at 41000000 {
> 
> 'nandc:' or 'nand_ctrl:'
> 
> Otherwise it may conflict with a NAND chip alias.
> The rest looks good, so no need to send a new version (I can fix it when
> applying the patch).

OK, thanks, I will fix in the dtsi accordingly.

> 
> One last thing, I saw there was other people owning boards with this
> controller. Can I get one or two Tested-by?

I would like too, but it seems I'm the only one working upstream for now....
I hope it will change in near future once there is enough upstream for booting the platform.

> 
> Thanks taking my reviews into account.

Thanks for reviewing !

Neil
> 
> Regards,
> 
> Boris
> 



From clg at kaod.org  Thu Oct 20 02:17:14 2016
From: clg at kaod.org (=?UTF-8?Q?C=c3=a9dric_Le_Goater?=)
Date: Thu, 20 Oct 2016 11:17:14 +0200
Subject: [PATCH] mtd/spi-nor: Add SPI memory controllers for Aspeed SoCs
In-Reply-To: <6964c1fd-3ac1-a28f-7b73-8113f0837e75@atmel.com>
References: <1476723427-13243-1-git-send-email-clg@kaod.org>
 <6964c1fd-3ac1-a28f-7b73-8113f0837e75@atmel.com>
Message-ID: <f5074ac1-e536-5817-377a-e39514c8ca97@kaod.org>

Hello Cyrille,

Thanks for taking a look, some answers and more questions below.

On 10/19/2016 07:06 PM, Cyrille Pitchen wrote:
> Hi C?dric,
> 
> Le 17/10/2016 ? 18:57, C?dric Le Goater a ?crit :
>> This driver adds mtd support for spi-nor attached to either or both of
>> the Firmware Memory Controller or the SPI Flash Controller (AST2400
>> only).
>>
>> The SMC controllers on the Aspeed AST2500 SoC are very similar to the
>> ones found on the AST2400. The differences are on the number of
>> supported flash modules and their default mappings in the SoC address
>> space.
>>
>> The Aspeed AST2500 has one SPI controller for the BMC firmware and two
>> for the host firmware. All controllers have now the same set of
>> registers compatible with the AST2400 FMC controller and the legacy
>> 'SMC' controller is fully gone.
>>
>> Based on previous work from Milton D. Miller II <miltonm at us.ibm.com>
>>
>> Signed-off-by: C?dric Le Goater <clg at kaod.org>
>> ---
> [...]
>> +
>> +static void aspeed_smc_send_cmd_addr(struct spi_nor *nor, u8 cmd, u32 addr)
>> +{
>> +	struct aspeed_smc_chip *chip = nor->priv;
>> +	__be32 temp;
>> +	u32 cmdaddr;
>> +
>> +	switch (nor->addr_width) {
>> +	default:
>> +		WARN_ONCE(1, "Unexpected address width %u, defaulting to 3\n",
>> +			  nor->addr_width);
>> +		/* FALLTHROUGH */
>> +	case 3:
>> +		cmdaddr = addr & 0xFFFFFF;
>> +
>> +		cmdaddr |= (u32)cmd << 24;
>> +
>> +		temp = cpu_to_be32(cmdaddr);
>> +		aspeed_smc_to_fifo(chip->base, &temp, 4);
>> +		break;
>> +	case 4:
>> +		temp = cpu_to_be32(addr);
>> +		aspeed_smc_to_fifo(chip->base, &cmd, 1);
>> +		aspeed_smc_to_fifo(chip->base, &temp, 4);
>> +		break;
>> +	}
>> +}
>> +
>> +static ssize_t aspeed_smc_read_user(struct spi_nor *nor, loff_t from, size_t len,
>> +				    u_char *read_buf)
>> +{
>> +	struct aspeed_smc_chip *chip = nor->priv;
>> +
>> +	mutex_lock(&chip->controller->mutex);
>> +
>> +	aspeed_smc_start_user(nor);

I think this section of code lock+start_user should be in a prepare handler 
if I am correct ? and I could get rid of the lock in that case to rely on
the one of the spi nor.

>> +	aspeed_smc_send_cmd_addr(nor, nor->read_opcode, from);
> 
> I guess the dummy cycles are missing between address cycles and data cycles!
> Check nor->read_dummy ;)

ah yes, I meant to and I forgot to add it ... will do in v2. I suppose 
we are doing fine with the driver now because we only use normal speed.

> Or maybe this controller can really only perform READ operations but no FAST
> READ commands. Hence the "spi_nor_scan(&chip->nor, NULL, SPI_NOR_NORMAL)"
> below.

yes it can. I suppose the driver should also call spi_nor_set_flash_node() 
for module supporting it. that brings another question I would like 
to discuss for possible followups patches. 

The controller can be fine tuned for a particular chip module. The 
CE0 control register has a few bits to set the spi clock, the dummy 
cycles, the CS inactive width and there is also a register to setup 
read timings delay.
 
So you need to loop on these different settings to find a correct one
and for that, you use a gold image captured at low speed as reference.

But you need to know which chip module you are dealing with. would it 
be possible to expose the jedec to the controller for this purpose ? 
and then do the training to build the timing settings in the driver. 
This is a similar approach taken by some nand controllers.

Thanks,

C.

 
>> +	aspeed_smc_from_fifo(read_buf, chip->base, len);
>> +	aspeed_smc_stop_user(nor);
>> +
>> +	mutex_unlock(&chip->controller->mutex);
>> +
>> +	return len;
>> +}
> [...]
> 
> Best regards,
> 
> Cyrille
> 
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/
> 



From maxime.ripard at free-electrons.com  Thu Oct 20 01:12:43 2016
From: maxime.ripard at free-electrons.com (Maxime Ripard)
Date: Thu, 20 Oct 2016 10:12:43 +0200
Subject: [PATCH 2/8] mtd: nand: add support for the TC58NVG2S0H chip
In-Reply-To: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
References: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
Message-ID: <62d5d978da8c6bc6b47c340c86e9a5fe5f6971ef.1476951078.git-series.maxime.ripard@free-electrons.com>

From: Boris Brezillon <boris.brezillon at free-electrons.com>

Add the description of the Toshiba TC58NVG2S0H SLC nand to the nand_ids
table so we can use the NAND ECC infos and the ONFI timings.

Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
Signed-off-by: Maxime Ripard <maxime.ripard at free-electrons.com>
---
 drivers/mtd/nand/nand_ids.c | 3 +++
 1 file changed, 3 insertions(+), 0 deletions(-)

diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
index 2af9869a115e..b3a332f37e14 100644
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -36,6 +36,9 @@ struct nand_flash_dev nand_flash_ids[] = {
 	{"TC58NVG2S0F 4G 3.3V 8-bit",
 		{ .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} },
 		  SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) },
+	{"TC58NVG2S0H 4G 3.3V 8-bit",
+		{ .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x16, 0x08, 0x00} },
+		  SZ_4K, SZ_512, SZ_256K, 0, 8, 256, NAND_ECC_INFO(8, SZ_512) },
 	{"TC58NVG3S0F 8G 3.3V 8-bit",
 		{ .id = {0x98, 0xd3, 0x90, 0x26, 0x76, 0x15, 0x02, 0x08} },
 		  SZ_4K, SZ_1K, SZ_256K, 0, 8, 232, NAND_ECC_INFO(4, SZ_512) },
-- 
git-series 0.8.10


From maxime.ripard at free-electrons.com  Thu Oct 20 01:12:45 2016
From: maxime.ripard at free-electrons.com (Maxime Ripard)
Date: Thu, 20 Oct 2016 10:12:45 +0200
Subject: [PATCH 4/8] ARM: gr8: Fix typo in the i2s mclk pin group
In-Reply-To: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
References: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
Message-ID: <f1c79380c34fcc2a1c1ff75ca91177de3b7380a9.1476951078.git-series.maxime.ripard@free-electrons.com>

There was a dumb copy and paste mistake here, fix it.

Signed-off-by: Maxime Ripard <maxime.ripard at free-electrons.com>
---
 arch/arm/boot/dts/ntc-gr8.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/ntc-gr8.dtsi b/arch/arm/boot/dts/ntc-gr8.dtsi
index d7cf6be2549c..74aff795e723 100644
--- a/arch/arm/boot/dts/ntc-gr8.dtsi
+++ b/arch/arm/boot/dts/ntc-gr8.dtsi
@@ -792,7 +792,7 @@
 			};
 
 			i2s0_mclk_pins_a: i2s0-mclk at 0 {
-				allwinner,pins = "PB6", "PB7", "PB8", "PB9";
+				allwinner,pins = "PB5";
 				allwinner,function = "i2s0";
 				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
 				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
-- 
git-series 0.8.10


From clg at kaod.org  Thu Oct 20 02:32:08 2016
From: clg at kaod.org (=?UTF-8?Q?C=c3=a9dric_Le_Goater?=)
Date: Thu, 20 Oct 2016 11:32:08 +0200
Subject: [PATCH] mtd/spi-nor: Add SPI memory controllers for Aspeed SoCs
In-Reply-To: <20161018163913.7z337iyc53atp4yd@rob-hp-laptop>
References: <1476723427-13243-1-git-send-email-clg@kaod.org>
 <20161018163913.7z337iyc53atp4yd@rob-hp-laptop>
Message-ID: <d675d2e6-c7fe-37a4-16ca-278f78e1f158@kaod.org>

On 10/18/2016 06:39 PM, Rob Herring wrote:
> On Mon, Oct 17, 2016 at 06:57:07PM +0200, C?dric Le Goater wrote:
>> This driver adds mtd support for spi-nor attached to either or both of
>> the Firmware Memory Controller or the SPI Flash Controller (AST2400
>> only).
>>
>> The SMC controllers on the Aspeed AST2500 SoC are very similar to the
>> ones found on the AST2400. The differences are on the number of
>> supported flash modules and their default mappings in the SoC address
>> space.
>>
>> The Aspeed AST2500 has one SPI controller for the BMC firmware and two
>> for the host firmware. All controllers have now the same set of
>> registers compatible with the AST2400 FMC controller and the legacy
>> 'SMC' controller is fully gone.
>>
>> Based on previous work from Milton D. Miller II <miltonm at us.ibm.com>
>>
>> Signed-off-by: C?dric Le Goater <clg at kaod.org>
>> ---
>>  .../devicetree/bindings/mtd/aspeed-smc.txt         |  86 +++
>>  drivers/mtd/spi-nor/Kconfig                        |  12 +
>>  drivers/mtd/spi-nor/Makefile                       |   1 +
>>  drivers/mtd/spi-nor/aspeed-smc.c                   | 746 +++++++++++++++++++++
>>  4 files changed, 845 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/mtd/aspeed-smc.txt
>>  create mode 100644 drivers/mtd/spi-nor/aspeed-smc.c
>>
>> diff --git a/Documentation/devicetree/bindings/mtd/aspeed-smc.txt b/Documentation/devicetree/bindings/mtd/aspeed-smc.txt
>> new file mode 100644
>> index 000000000000..f6bfa7761205
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mtd/aspeed-smc.txt
>> @@ -0,0 +1,86 @@
>> +* Aspeed Static Memory controller
>> +* Aspeed SPI Flash Controller
>> +
>> +The Static memory controller in the ast2400 supports 5 chip selects each
>> +can be attached to NAND, parallel NOR, or SPI NOR attached flash.  The
>> +Firmware Memory Controller in the ast2500 supports 3 chip selects, two of
>> +which are always in SPI-NOR mode and the third can be SPI-NOR or parallel
>> +flash.  The SPI flash controller in the ast2400 supports one of 2 chip
>> +selects selected by pinmux.  The two SPI flash controllers in the ast2500
>> +each support two chip selects.
>> +
>> +Required properties:
>> +  - compatible : Should be one of
>> +	"aspeed,ast2400-fmc" for the AST2400 Static Memory Controller
>> +	"aspeed,ast2400-smc" for the AST2400 SPI Flash Controller
>> +	"aspeed,ast2500-fmc" for the AST2500 Firmware SPI Memory Controller
>> +	"aspeed,ast2500-smc" for the AST2500 SPI Flash Controllers
>> +  - reg : the first contains the control register location and length,
>> +          the second contains the memory window mapping address and length
>> +  - clocks : The APB clock input to the controller
>> +  - #address-cells : must be 1 corresponding to chip select child binding
>> +  - #size-cells : must be 0 corresponding to chip select child binding
>> +
>> +Optional properties:
>> +  - aspeed,fmc-has-dma : controller supports DMA transfers
> 
> The compatible should imply this.

yes you are right. this is the case for the *fmc.

> 
>> +  - interrupts : Should contain the interrupt for the dma device if an fmc
>> +
>> +Child node required properties:
> 
> Need to say what the child nodes are.

yes again. the child node definitions really need more care. will do in v2.

Thanks for the review,

C. 


> 
>> +  - reg : must contain chip select number in first cell of address, must
>> +	  be 1 tuple long
>> +  - compatible : may contain "vendor,part", must include "jedec,spi-nor"
>> +		when attached to SPI flash (see spi-nor.txt binding).
>> +
>> +Child node optional properties:
>> +  - label           - (optional) name to assign to mtd, default os assigned
>> +
>> +Child node optional properties for SPI mode (may be ignored):
>> +  - spi-max-frequency - (optional) max frequency of spi bus
>> +  - spi-cpol        - (optional) Empty property indicating device requires
>> +			inverse clock polarity (CPOL) mode (boolean)
>> +  - spi-cpha        - (optional) Empty property indicating device requires
>> +			shifted clock phase (CPHA) mode (boolean)
>> +  - spi-tx-bus-width - (optional) The bus width(number of data wires) that
>> +                        used for MOSI. Defaults to 1 if not present.
>> +  - spi-rx-bus-width - (optional) The bus width(number of data wires) that
>> +                        used for MOSI. Defaults to 1 if not present.
>> +
>> +Grandchild node optional properties:
>> + - see mtd/partiton.txt for partitioning bindings and mtd naming
>> +
>> +
>> +Example:
>> +
>> +fmc: fmc at 1e620000 {
>> +	compatible = "aspeed,ast2400-fmc";
>> +	reg = < 0x1e620000 0x94
>> +		0x20000000 0x02000000
>> +		0x22000000 0x02000000 >;
>> +	#address-cells = <1>;
>> +	#size-cells = <0>;
>> +	flash at 0 {
>> +		reg = < 0 >;
>> +		compatible = "jedec,spi-nor" ;
>> +		label = "bmc";
> 
> label isn't really a defined property here. Belongs in jedec,spi-nor 
> binding if you want to add it.
> 
>> +		/* spi-max-frequency = <>; */
>> +		/* m25p,fast-read; */
>> +		#address-cells = <1>;
>> +		#size-cells = <1>;
>> +		boot at 0 {
> 
> Use the newer style with all partitions under a 'partitions' node.
> 
>> +			label = "boot-loader";
>> +			reg = < 0 0x8000 >
> 
> Missing ';'
> 
>> +		}
>> +		image at 8000 {
>> +			label = "kernel-image";
>> +			reg = < 0x8000 0x1f8000 >
> 
> ditto
> 
>> +		}
>> +	};
>> +	flash at 1 {
>> +		reg = < 1 >;
>> +		compatible = "jedec,spi-nor" ;
>> +		label = "alt";
>> +		/* spi-max-frequency = <>; */
>> +		status = "fail";
>> +		/* m25p,fast-read; */
>> +	};
>> +};
> 
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/
> 



From linus.walleij at linaro.org  Thu Oct 20 06:42:27 2016
From: linus.walleij at linaro.org (Linus Walleij)
Date: Thu, 20 Oct 2016 15:42:27 +0200
Subject: [PATCH 00/10] Introduce Juniper PTXPMB CPLD driver
In-Reply-To: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <CACRpkdYkgondu3NuReFg=FZ29Xzi0zncpku0+++_OSsPnUs+Ew@mail.gmail.com>

On Fri, Oct 7, 2016 at 5:17 PM, Pantelis Antoniou
<pantelis.antoniou at konsulko.com> wrote:

> Add Juniper's PTXPMB FPGA CPLD driver. Those FPGAs
> are present in Juniper's PTX series of routers.
>
> The MFD driver provices watchdog/i2c/gpio/mtd devices.

Since it's quite a bunch of patches to quite a bunch of controllers
I think it's best if you get the MFD parts ready and merged through
Lee first for v4.10, then we can add the subdrivers on top, maybe
in v4.11, or on top of an immutable branch from Lee once he is
happy with the core if the MFD core is finished quickly.

I will review all the GPIO stuff though so you can revise these
patches too :)

Yours,
Linus Walleij


From marex at denx.de  Thu Oct 20 06:42:24 2016
From: marex at denx.de (Marek Vasut)
Date: Thu, 20 Oct 2016 15:42:24 +0200
Subject: [PATCH v2 1/1] MAINTAINERS: add a maintainer for the SPI NOR
 subsystem
In-Reply-To: <aad52b708dcf6754edab87d2e0afe4f0ee6831f9.1476891131.git.cyrille.pitchen@atmel.com>
References: <aad52b708dcf6754edab87d2e0afe4f0ee6831f9.1476891131.git.cyrille.pitchen@atmel.com>
Message-ID: <d92f8ef8-be78-0386-fa84-117c3cae6459@denx.de>

On 10/19/2016 05:34 PM, Cyrille Pitchen wrote:
> I would like to volunteer as a maintainer for the SPI NOR part of the MTD
> subsystem.
> 
> Over the last months, a significant number of SPI NOR related patches have
> been submitted, some of them have been reviewed, but very few have finally
> been merged. Hence, the number of pending SPI NOR related patches continues
> to increase over the time.
> 
> Through my work on SPI NOR memories from many manufacturers over the last
> two years, I've gained a solid understanding of this technology.
> I've already helped by reviewing patches from other contributors on the
> mailing list, and would like to help getting those patches integrated by
> volunteering as a maintainer for this specific area.
> 
> Boris Brezillon has already stepped up as a maintainer for the NAND
> sub-subsystem in MTD, and the SPI NOR sub-subsystem could be handled in
> the same way: I would be reviewing patches touching this area, collecting
> them and sending pull requests to Brian Norris.
> 
> Also both Marek Vasut and Richard Weinberger have volunteered as well as
> maintainers for the SPI NOR subsystem.
> 
> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
> Acked-by: Boris Brezillon <boris.brezillon at free-electrons.com>

Acked-by: Marek Vasut <marek.vasut at gmail.com>

btw I think I'll need higher privileges in patchwork to fiddle with patches.

> ---
> ChangeLog:
> 
> v1 -> v2:
> - add Marek and Richard as maintainers.
> - add Acked-by from Boris Brezillon.
> 
> 
>  MAINTAINERS | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 757f9c4b388d..7e63b2015072 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -11390,6 +11390,18 @@ W:	http://www.st.com/spear
>  S:	Maintained
>  F:	drivers/clk/spear/
>  
> +SPI NOR SUBSYSTEM
> +M:	Cyrille Pitchen <cyrille.pitchen at atmel.com>
> +M:	Marek Vasut <marek.vasut at gmail.com>
> +M:	Richard Weinberger <richard at nod.at>
> +L:	linux-mtd at lists.infradead.org
> +W:	http://www.linux-mtd.infradead.org/
> +Q:	http://patchwork.ozlabs.org/project/linux-mtd/list/
> +T:	git git://github.com/spi-nor/linux.git
> +S:	Maintained
> +F:	drivers/mtd/spi-nor/
> +F:	include/linux/mtd/spi-nor.h
> +
>  SPI SUBSYSTEM
>  M:	Mark Brown <broonie at kernel.org>
>  L:	linux-spi at vger.kernel.org
> 


-- 
Best regards,
Marek Vasut


From pantelis.antoniou at konsulko.com  Thu Oct 20 06:43:41 2016
From: pantelis.antoniou at konsulko.com (Pantelis Antoniou)
Date: Thu, 20 Oct 2016 16:43:41 +0300
Subject: [PATCH 00/10] Introduce Juniper PTXPMB CPLD driver
In-Reply-To: <CACRpkdYkgondu3NuReFg=FZ29Xzi0zncpku0+++_OSsPnUs+Ew@mail.gmail.com>
References: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
 <CACRpkdYkgondu3NuReFg=FZ29Xzi0zncpku0+++_OSsPnUs+Ew@mail.gmail.com>
Message-ID: <E368DA67-BAD4-462C-9323-548E55A2E7D2@konsulko.com>

Hi Linus,

> On Oct 20, 2016, at 16:42 , Linus Walleij <linus.walleij at linaro.org> wrote:
> 
> On Fri, Oct 7, 2016 at 5:17 PM, Pantelis Antoniou
> <pantelis.antoniou at konsulko.com> wrote:
> 
>> Add Juniper's PTXPMB FPGA CPLD driver. Those FPGAs
>> are present in Juniper's PTX series of routers.
>> 
>> The MFD driver provices watchdog/i2c/gpio/mtd devices.
> 
> Since it's quite a bunch of patches to quite a bunch of controllers
> I think it's best if you get the MFD parts ready and merged through
> Lee first for v4.10, then we can add the subdrivers on top, maybe
> in v4.11, or on top of an immutable branch from Lee once he is
> happy with the core if the MFD core is finished quickly.
> 

Will do.

> I will review all the GPIO stuff though so you can revise these
> patches too :)
> 

Goodie :)

> Yours,
> Linus Walleij

Regards

? Pantelis



From joel.esponde at honeywell.com  Thu Oct 20 06:43:46 2016
From: joel.esponde at honeywell.com (=?UTF-8?q?Jo=C3=ABl=20Esponde?=)
Date: Thu, 20 Oct 2016 15:43:46 +0200
Subject: [PATCH] mtd: spi-nor: fixed spansion quad enable
Message-ID: <1476971026-9665-1-git-send-email-joel.esponde@honeywell.com>

With the S25FL127S nor flash part, each writing to the configuration register takes hundreds of ms. During that  time, no more accesses to the flash should be done (even reads).

This commit adds:
- a pre check of the quad enable bit to avoid a useless and time consuming writing to the flash,
- a wait loop after the register writing until the flash finishes its work.

This issue could make rootfs mounting fail when the latter was done too much closely to this quad enable bit setting step. And in this case, a driver as UBIFS may try to recover the filesystem and may broke it completely.
---
 drivers/mtd/spi-nor/spi-nor.c | 31 +++++++++++++++++++++++++++----
 1 file changed, 27 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index d0fc165..df43cd7 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1246,18 +1246,41 @@ static int spansion_quad_enable(struct spi_nor *nor)
 	int ret;
 	int quad_en = CR_QUAD_EN_SPAN << 8;
 
+	/* check quad enable bit
+	 * as S25FL127S takes 200 ms to execute each write of SR & CR 
+	 * registers even if data is the same, write step will be shorted 
+	 * if not needed
+	 */
+	ret = read_cr(nor);
+	if (ret < 0) {
+		dev_err(nor->dev, "error %d reading CR\n", ret);
+		return ret;
+	} 
+	if (ret & CR_QUAD_EN_SPAN) {
+		/* quad enable bit is already set */
+		return 0;
+	}
+
+	/* set SR & CR, enable quad I/O */
 	write_enable(nor);
 
 	ret = write_sr_cr(nor, quad_en);
 	if (ret < 0) {
-		dev_err(nor->dev,
-			"error while writing configuration register\n");
+		dev_err(nor->dev, "error while writing SR and CR registers\n");
 		return -EINVAL;
 	}
 
-	/* read back and check it */
+	ret = spi_nor_wait_till_ready(nor);
+	if (ret)
+		return ret;
+	
+	/* read CR and check it */
 	ret = read_cr(nor);
-	if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
+	if (ret < 0) {
+		dev_err(nor->dev, "error %d reading CR\n", ret);
+		return ret;
+	}
+	if (!(ret & CR_QUAD_EN_SPAN)) {
 		dev_err(nor->dev, "Spansion Quad bit not set\n");
 		return -EINVAL;
 	}
-- 
2.7.4



From ricardo.ribalda at gmail.com  Thu Oct 20 07:03:37 2016
From: ricardo.ribalda at gmail.com (Ricardo Ribalda Delgado)
Date: Thu, 20 Oct 2016 16:03:37 +0200
Subject: [PATCH] mtd: spi-nor: Add support for S3AN spi-nor devices
In-Reply-To: <CAPybu_2j6vn9y-rOAvs2vp18RvSEe8qkg_r3RdRGNgna7-J31A@mail.gmail.com>
References: <20160920154551.3494-1-ricardo.ribalda@gmail.com>
 <20160921090704.2cfebfc8@bbrezillon>
 <CAPybu_0S0juNTNO1eQUbxyvcDR8o8W-69+oK5G_i42Z8CHS+FA@mail.gmail.com>
 <20160921101420.7ea87f2d@bbrezillon>
 <CAPybu_1f924DvgT1hSPyEMyD7tTN8Cng=mkq5ydDBBbZqpUtuw@mail.gmail.com>
 <20160921102137.6ff58bc7@bbrezillon>
 <CAPybu_2j6vn9y-rOAvs2vp18RvSEe8qkg_r3RdRGNgna7-J31A@mail.gmail.com>
Message-ID: <CAPybu_0U-j6yrO0oOY99UqdVoSqqzN=2c3MbRV8wosWqhm_8EA@mail.gmail.com>

Ping?

On Wed, Sep 21, 2016 at 10:26 AM, Ricardo Ribalda Delgado
<ricardo.ribalda at gmail.com> wrote:
> Hi
>
>>>
>>> Unsinged long is more than enough for s3an. I think v7 is ok.
>>
>> Then, why did you change the spi_nor_s3an_addr_convert() prototype?
>>
>
> Because it is used in spi_nor_read and spi_nor_write, which use loff_t.
>
> I think it is more clean to have only one comment explaining the max
> size of the s3an, instead of having them scattered around. But if
> think that it is better to have unsinged int as prototype I have no
> problem in changing it.
>
> Regards!
>
>
> --
> Ricardo Ribalda



-- 
Ricardo Ribalda


From wens at csie.org  Thu Oct 20 07:06:47 2016
From: wens at csie.org (Chen-Yu Tsai)
Date: Thu, 20 Oct 2016 22:06:47 +0800
Subject: [PATCH 3/8] ARM: gr8: Add the UART3
In-Reply-To: <b62c8661eb3c2d72e61511794a3ab1b43f005805.1476951078.git-series.maxime.ripard@free-electrons.com>
References: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
 <b62c8661eb3c2d72e61511794a3ab1b43f005805.1476951078.git-series.maxime.ripard@free-electrons.com>
Message-ID: <CAGb2v65iR=mZyCQrF64HOku5Sq7fNKGhV=Yy3zUFYzB=4ozkWg@mail.gmail.com>

On Thu, Oct 20, 2016 at 4:12 PM, Maxime Ripard
<maxime.ripard at free-electrons.com> wrote:
> The GR8 has access to the UART3 controller, which was missing in the
> DTSI. Add it.
>
> Signed-off-by: Maxime Ripard <maxime.ripard at free-electrons.com>

Acked-by: Chen-Yu Tsai <wens at csie.org>


From wens at csie.org  Thu Oct 20 07:07:46 2016
From: wens at csie.org (Chen-Yu Tsai)
Date: Thu, 20 Oct 2016 22:07:46 +0800
Subject: [PATCH 4/8] ARM: gr8: Fix typo in the i2s mclk pin group
In-Reply-To: <f1c79380c34fcc2a1c1ff75ca91177de3b7380a9.1476951078.git-series.maxime.ripard@free-electrons.com>
References: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
 <f1c79380c34fcc2a1c1ff75ca91177de3b7380a9.1476951078.git-series.maxime.ripard@free-electrons.com>
Message-ID: <CAGb2v65P6WEZCy8AXCk5mV4gWgiWuZJiDZzJnEgr+sj9qf8ORA@mail.gmail.com>

On Thu, Oct 20, 2016 at 4:12 PM, Maxime Ripard
<maxime.ripard at free-electrons.com> wrote:
> There was a dumb copy and paste mistake here, fix it.
>
> Signed-off-by: Maxime Ripard <maxime.ripard at free-electrons.com>

Acked-by: Chen-Yu Tsai <wens at csie.org>


From wens at csie.org  Thu Oct 20 07:10:03 2016
From: wens at csie.org (Chen-Yu Tsai)
Date: Thu, 20 Oct 2016 22:10:03 +0800
Subject: [PATCH 5/8] ARM: gr8: Add missing pwm channel 1 pin
In-Reply-To: <0df42247c3348e7f6aed945e5669cec87f96f7ac.1476951078.git-series.maxime.ripard@free-electrons.com>
References: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
 <0df42247c3348e7f6aed945e5669cec87f96f7ac.1476951078.git-series.maxime.ripard@free-electrons.com>
Message-ID: <CAGb2v66w0sTzn_SWH4rrpWKOosSxALV8ot3CBQbGhwLxvX1vxw@mail.gmail.com>

On Thu, Oct 20, 2016 at 4:12 PM, Maxime Ripard
<maxime.ripard at free-electrons.com> wrote:
> The PWM controller has two different channels, but only the first pin was
> exposed in the DTSI. Add the other one.
>
> Signed-off-by: Maxime Ripard <maxime.ripard at free-electrons.com>

Acked-by: Chen-Yu Tsai <wens at csie.org>

> ---
>  arch/arm/boot/dts/ntc-gr8.dtsi | 7 +++++++
>  1 file changed, 7 insertions(+), 0 deletions(-)
>
> diff --git a/arch/arm/boot/dts/ntc-gr8.dtsi b/arch/arm/boot/dts/ntc-gr8.dtsi
> index 74aff795e723..fad7381630f3 100644
> --- a/arch/arm/boot/dts/ntc-gr8.dtsi
> +++ b/arch/arm/boot/dts/ntc-gr8.dtsi
> @@ -854,6 +854,13 @@
>                                 allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
>                         };
>
> +                       pwm1_pins_a: pwm1 at 0 {

Nit: really don't need "_a" and "@0" here.

> +                               allwinner,pins = "PG13";
> +                               allwinner,function = "pwm1";
> +                               allwinner,drive = <SUN4I_PINCTRL_10_MA>;
> +                               allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
> +                       };
> +
>                         spdif_tx_pins_a: spdif at 0 {
>                                 allwinner,pins = "PB10";
>                                 allwinner,function = "spdif";
> --
> git-series 0.8.10


From wens at csie.org  Thu Oct 20 07:14:09 2016
From: wens at csie.org (Chen-Yu Tsai)
Date: Thu, 20 Oct 2016 22:14:09 +0800
Subject: [PATCH 6/8] ARM: gr8: Add UART2 pins
In-Reply-To: <0c1f98755c7dd1764dcd89a599f182a0face286f.1476951078.git-series.maxime.ripard@free-electrons.com>
References: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
 <0c1f98755c7dd1764dcd89a599f182a0face286f.1476951078.git-series.maxime.ripard@free-electrons.com>
Message-ID: <CAGb2v641SWJTG=3AmHE3zAypuoq7fL7gFLBXwfXpmCYw7K0Guw@mail.gmail.com>

On Thu, Oct 20, 2016 at 4:12 PM, Maxime Ripard
<maxime.ripard at free-electrons.com> wrote:
> The UART2 pins were missing from the DTSI. Add them.
>
> Signed-off-by: Maxime Ripard <maxime.ripard at free-electrons.com>

Acked-by: Chen-Yu Tsai <wens at csie.org>


From wens at csie.org  Thu Oct 20 07:16:11 2016
From: wens at csie.org (Chen-Yu Tsai)
Date: Thu, 20 Oct 2016 22:16:11 +0800
Subject: [PATCH 7/8] ARM: gr8: Add UART3 pins
In-Reply-To: <cc81030de43c26dfc15ad9a9e525188ad8fb8ec9.1476951078.git-series.maxime.ripard@free-electrons.com>
References: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
 <cc81030de43c26dfc15ad9a9e525188ad8fb8ec9.1476951078.git-series.maxime.ripard@free-electrons.com>
Message-ID: <CAGb2v65OXss+_jKMSJD-KUDeK2iH96mmvDvPEzgW60PUXoS90g@mail.gmail.com>

On Thu, Oct 20, 2016 at 4:12 PM, Maxime Ripard
<maxime.ripard at free-electrons.com> wrote:
> The UART3 pins were missing from the DTSI. Add them.
>
> Signed-off-by: Maxime Ripard <maxime.ripard at free-electrons.com>

Acked-by: Chen-Yu Tsai <wens at csie.org>


From wens at csie.org  Thu Oct 20 07:26:09 2016
From: wens at csie.org (Chen-Yu Tsai)
Date: Thu, 20 Oct 2016 22:26:09 +0800
Subject: [PATCH 8/8] ARM: gr8: Add CHIP Pro support
In-Reply-To: <d3f91b731f944fe0e23b4532f6e83a1c2fc345f0.1476951078.git-series.maxime.ripard@free-electrons.com>
References: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
 <d3f91b731f944fe0e23b4532f6e83a1c2fc345f0.1476951078.git-series.maxime.ripard@free-electrons.com>
Message-ID: <CAGb2v67S8rK6Hdkvkgtfz6hDtiR4a4yUUqB01AnQ4sJ3-SQc0A@mail.gmail.com>

On Thu, Oct 20, 2016 at 4:12 PM, Maxime Ripard
<maxime.ripard at free-electrons.com> wrote:
> The CHIP Pro is a small embeddable board. It features a GR8, an AXP209
> PMIC, a 512MB SLC NAND and a WiFi/BT chip.
>
> Signed-off-by: Maxime Ripard <maxime.ripard at free-electrons.com>

Acked-by: Chen-Yu Tsai <wens at csie.org>


From cyrille.pitchen at atmel.com  Thu Oct 20 07:33:06 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Thu, 20 Oct 2016 16:33:06 +0200
Subject: [PATCH] mtd/spi-nor: Add SPI memory controllers for Aspeed SoCs
In-Reply-To: <f5074ac1-e536-5817-377a-e39514c8ca97@kaod.org>
References: <1476723427-13243-1-git-send-email-clg@kaod.org>
 <6964c1fd-3ac1-a28f-7b73-8113f0837e75@atmel.com>
 <f5074ac1-e536-5817-377a-e39514c8ca97@kaod.org>
Message-ID: <420eece6-277d-6c8f-70ed-ba2a1c42d5d5@atmel.com>

Hi C?dric,

Le 20/10/2016 ? 11:17, C?dric Le Goater a ?crit :
> Hello Cyrille,
> 
> Thanks for taking a look, some answers and more questions below.
> 
> On 10/19/2016 07:06 PM, Cyrille Pitchen wrote:
>> Hi C?dric,
>>
>> Le 17/10/2016 ? 18:57, C?dric Le Goater a ?crit :
>>> This driver adds mtd support for spi-nor attached to either or both of
>>> the Firmware Memory Controller or the SPI Flash Controller (AST2400
>>> only).
>>>
>>> The SMC controllers on the Aspeed AST2500 SoC are very similar to the
>>> ones found on the AST2400. The differences are on the number of
>>> supported flash modules and their default mappings in the SoC address
>>> space.
>>>
>>> The Aspeed AST2500 has one SPI controller for the BMC firmware and two
>>> for the host firmware. All controllers have now the same set of
>>> registers compatible with the AST2400 FMC controller and the legacy
>>> 'SMC' controller is fully gone.
>>>
>>> Based on previous work from Milton D. Miller II <miltonm at us.ibm.com>
>>>
>>> Signed-off-by: C?dric Le Goater <clg at kaod.org>
>>> ---
>> [...]
>>> +
>>> +static void aspeed_smc_send_cmd_addr(struct spi_nor *nor, u8 cmd, u32 addr)
>>> +{
>>> +	struct aspeed_smc_chip *chip = nor->priv;
>>> +	__be32 temp;
>>> +	u32 cmdaddr;
>>> +
>>> +	switch (nor->addr_width) {
>>> +	default:
>>> +		WARN_ONCE(1, "Unexpected address width %u, defaulting to 3\n",
>>> +			  nor->addr_width);
>>> +		/* FALLTHROUGH */
>>> +	case 3:
>>> +		cmdaddr = addr & 0xFFFFFF;
>>> +
>>> +		cmdaddr |= (u32)cmd << 24;
>>> +
>>> +		temp = cpu_to_be32(cmdaddr);
>>> +		aspeed_smc_to_fifo(chip->base, &temp, 4);
>>> +		break;
>>> +	case 4:
>>> +		temp = cpu_to_be32(addr);
>>> +		aspeed_smc_to_fifo(chip->base, &cmd, 1);
>>> +		aspeed_smc_to_fifo(chip->base, &temp, 4);
>>> +		break;
>>> +	}
>>> +}
>>> +
>>> +static ssize_t aspeed_smc_read_user(struct spi_nor *nor, loff_t from, size_t len,
>>> +				    u_char *read_buf)
>>> +{
>>> +	struct aspeed_smc_chip *chip = nor->priv;
>>> +
>>> +	mutex_lock(&chip->controller->mutex);
>>> +
>>> +	aspeed_smc_start_user(nor);
> 
> I think this section of code lock+start_user should be in a prepare handler 
> if I am correct ? and I could get rid of the lock in that case to rely on
> the one of the spi nor.
> 

For the mutex, looking at your driver, you lock it at the beginning then unlock
at the end of the four handlers:
- nor->read()
- nor->write()
- nor->read_reg()
- nor->write_reg()

If this is the only purpose of this mutex, yes, you can remove it and relie on
the internal spi-nor one (nor->lock), which is locked from
spi_nor_lock_and_prep() hence at the beginning of spi_nor_erase(),
spi_nor_read() and spi_nor_write() calls.

However, about moving the call of aspeed_smc_start_user() into a new prepare
handler, I don't know whether it would actually fit your needs: for sure, 
aspeed_smc_start_user() would be no longer called at some points.

2 examples:

A - spi_nor_write() calls:
1 - spi_nor_lock_and_prep() -> nor->prepare()
2 - write_enable() -> nor->write_reg()
3 - nor->write()
4 - spi_nor_wait_till_ready() -> nor->read_reg()
5 - spi_nor_unlock_and_unprep() -> nor->unprepare()

With your current driver, aspeed_smc_start_user()/aspeed_smc_stop_user() are
called 3 times, indeed each time a command is sent on the SPI bus:
WRITE ENABLE, PAGE PROGRAM, READ STATUS

Then if you move then into spi_nor_[un]lock_and_[un]prep(), those two functions
would only be called once each.


B - spi_nor_scan() calls:
1 - spi_nor_read_id() -> nor->read_reg()

but spi_nor_lock_and_prep() is not called before, so if you nead to call
aspeed_smc_start_user() before sending any command on the SPI bus, it won't
work.

I don't know how your SPI controller works but maybe using the nor->prepare()
handler is not what you want!


>>> +	aspeed_smc_send_cmd_addr(nor, nor->read_opcode, from);
>>
>> I guess the dummy cycles are missing between address cycles and data cycles!
>> Check nor->read_dummy ;)
> 
> ah yes, I meant to and I forgot to add it ... will do in v2. I suppose 
> we are doing fine with the driver now because we only use normal speed.
> 

Indeed, the legacy READ (03h) command has no dummy cycles as opposed to all
other FAST READ commands. Of course, the READ command is far much slower.

>> Or maybe this controller can really only perform READ operations but no FAST
>> READ commands. Hence the "spi_nor_scan(&chip->nor, NULL, SPI_NOR_NORMAL)"
>> below.
> 
> yes it can. I suppose the driver should also call spi_nor_set_flash_node() 
> for module supporting it. that brings another question I would like 
> to discuss for possible followups patches. 
> 

Calling spi_nor_set_flash_node() with the relevant parameter tells
spi_nor_scan() which DT node to parse to tune some settings.
For instance, you could add the "m25p,fast-read" DT property so spi_nor_scan()
would select Fast Read operations rather than Read operations.

> The controller can be fine tuned for a particular chip module. The 
> CE0 control register has a few bits to set the spi clock, the dummy 
> cycles, the CS inactive width and there is also a register to setup 
> read timings delay.
>  
> So you need to loop on these different settings to find a correct one
> and for that, you use a gold image captured at low speed as reference.
> 
> But you need to know which chip module you are dealing with. would it 
> be possible to expose the jedec to the controller for this purpose ? 
> and then do the training to build the timing settings in the driver. 
> This is a similar approach taken by some nand controllers.
> 

I'm not sure to fully understand your needs.
The spi clock is often provided in the device tree, on the controller or memory
node, with the "spi-max-frequency" DT property.
The number of dummy cycles is set in nor->read_dummy by spi_nor_scan()
according to the actual memory model and the selected (Fast) Read op code.
For chip-select timings, those settings aren't currently handled by
spi_nor_scan() but might be supported inside the SPI controller driver through
DT properties if needed.

I don't know why your SPI controller driver needs to know the exact memory
model to work. Aren't the pieces of information provided by spi-nor.c enough?
Actually, for this point I don't quite exactly understand your needs! :)

Best regards,

Cyrille


> Thanks,
> 
> C.
> 
>  
>>> +	aspeed_smc_from_fifo(read_buf, chip->base, len);
>>> +	aspeed_smc_stop_user(nor);
>>> +
>>> +	mutex_unlock(&chip->controller->mutex);
>>> +
>>> +	return len;
>>> +}
>> [...]
>>
>> Best regards,
>>
>> Cyrille
>>
>> ______________________________________________________
>> Linux MTD discussion mailing list
>> http://lists.infradead.org/mailman/listinfo/linux-mtd/
>>
> 



From han.xu at nxp.com  Thu Oct 20 07:54:20 2016
From: han.xu at nxp.com (Han Xu)
Date: Thu, 20 Oct 2016 14:54:20 +0000
Subject: [PATCH 1/2] fsl-quadspi: fix QUAD read, add NORMAL, DUAL and FAST
 reads
In-Reply-To: <20161020091630.3477efab.albert.aribaud@3adev.fr>
References: <20160927055957.427-1-albert.aribaud@3adev.fr>
 <69a5b0d7-6b89-7edc-738d-c9e25802ba31@atmel.com>,
 <20161020091630.3477efab.albert.aribaud@3adev.fr>
Message-ID: <AM4PR0401MB1841BD90C29964BB2324E2CE97D50@AM4PR0401MB1841.eurprd04.prod.outlook.com>



________________________________________
From: Albert ARIBAUD <albert.aribaud at 3adev.fr>
Sent: Thursday, October 20, 2016 1:16 AM
To: Cyrille Pitchen
Cc: linux-mtd at lists.infradead.org; Yunhui Cui; devicetree at vger.kernel.org; Han Xu
Subject: Re: [PATCH 1/2] fsl-quadspi: fix QUAD read, add NORMAL, DUAL and FAST reads

Hi Cyrille,

Le Wed, 19 Oct 2016 18:42:36 +0200, Cyrille Pitchen
<cyrille.pitchen at atmel.com> a ?crit :

> Hi Albert,
>
> +Yunhui


> It seems that both Yunhui and you work on the same topic, maybe you can
> synchronize?
> https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatchwork.ozlabs.org%2Fpatch%2F660356%2F&data=01%7C01%7Chan.xu%40nxp.com%7C4b7dcf6422694f68dc1408d3f8b90a4d%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0&sdata=WjiiPqupc9bGtqixGvPeFoBddg51SJwehI4L0Zup9RY%3D&reserved=0

I am already preparing a v2 based over Yunhui's series. :)

> I don't think it is a good thing to select the relevant "READ" LUT entry
> according to the command op code. What if spi-nor.c introduces new op codes?
>
> Maybe you could index the LUT entries by functions:
> - READ_REG: the LUT op code would be dynamically updated by your
>             .read_reg(nor, opcode, ...) implementation according to opcode.
> - WRITE_REG: the same as above with the .write_reg(nor, opcode, ...) hook.
> - READ_SLAVE1: read memory from the first SPI-NOR memory.
> - WRITE_SLAVE1: write into the first SPI-NOR memory.
> - READ_SLAVE2: read memory form the 2nd SPI-NOR memory.
> ...
> - WRITE_SLAVEN: write into the N-th SPI-NOR memory.

Actually, my needs could be met using Han Xu's dynamic LUT entries
without the need to introduce 'virtual' opcodes (and without having
to 'leak back' those new opcodes into other kernel code portions).

The per-slave differences (in my case, bus width essentially) can be
managed though DT entries and corresponding per-nor flags in the driver.

> Also be aware even for the .read() hook the nor->read_opcode might changes
> between calls!

Noted -- I'll check that the driver always use the current NOR codes.

> I don't know whether those comments fit your actual needs and the Freescale SPI
> controller hardware constraints but I'm always worried about the ease to maintain
> SPI-NOR controller drivers when they are not "op code agnostic".

Understood and agreed.

Thanks for yuor feedback!

Good. I have another question about Yunhui's patch set. Who are in charge of review
and merge code change in spi-nor.c? Some patches have been pending for a while.

> Best regards,
>
> Cyrille

Cordialement,
Albert ARIBAUD
3ADEV


From zach.brown at ni.com  Thu Oct 20 07:58:56 2016
From: zach.brown at ni.com (Zach Brown)
Date: Thu, 20 Oct 2016 09:58:56 -0500
Subject: [PATCH v2 1/3] mtd: introduce function max_bad_blocks
In-Reply-To: <1476975538-19051-1-git-send-email-zach.brown@ni.com>
References: <1476975538-19051-1-git-send-email-zach.brown@ni.com>
Message-ID: <1476975538-19051-2-git-send-email-zach.brown@ni.com>

From: Jeff Westfahl <jeff.westfahl at ni.com>

If implemented, 'max_bad_blocks' returns the maximum number of bad
blocks to reserve for an MTD. An implementation for NAND is coming soon.

Signed-off-by: Jeff Westfahl <jeff.westfahl at ni.com>
Signed-off-by: Zach Brown <zach.brown at ni.com>
---
 drivers/mtd/mtdpart.c   | 12 ++++++++++++
 include/linux/mtd/mtd.h |  1 +
 2 files changed, 13 insertions(+)

diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index c1f34f0..65d3563 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -350,6 +350,16 @@ static const struct mtd_ooblayout_ops part_ooblayout_ops = {
 	.free = part_ooblayout_free,
 };
 
+static int part_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+	struct mtd_part *part = mtd_to_part(mtd);
+
+	if ((len + ofs) > mtd->size)
+		return -EINVAL;
+	return part->master->_max_bad_blocks(part->master,
+					     ofs + part->offset, len);
+}
+
 static inline void free_partition(struct mtd_part *p)
 {
 	kfree(p->mtd.name);
@@ -482,6 +492,8 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
 	if (master->_put_device)
 		slave->mtd._put_device = part_put_device;
 
+	if (master->_max_bad_blocks)
+		slave->mtd._max_bad_blocks = part_max_bad_blocks;
 	slave->mtd._erase = part_erase;
 	slave->master = master;
 	slave->offset = part->offset;
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 13f8052..bd277eb 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -322,6 +322,7 @@ struct mtd_info {
 	int (*_block_isreserved) (struct mtd_info *mtd, loff_t ofs);
 	int (*_block_isbad) (struct mtd_info *mtd, loff_t ofs);
 	int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs);
+	int (*_max_bad_blocks) (struct mtd_info *mtd, loff_t ofs, size_t len);
 	int (*_suspend) (struct mtd_info *mtd);
 	void (*_resume) (struct mtd_info *mtd);
 	void (*_reboot) (struct mtd_info *mtd);
-- 
2.7.4



From zach.brown at ni.com  Thu Oct 20 07:58:57 2016
From: zach.brown at ni.com (Zach Brown)
Date: Thu, 20 Oct 2016 09:58:57 -0500
Subject: [PATCH v2 2/3] mtd: nand: implement 'max_bad_blocks' mtd function
In-Reply-To: <1476975538-19051-1-git-send-email-zach.brown@ni.com>
References: <1476975538-19051-1-git-send-email-zach.brown@ni.com>
Message-ID: <1476975538-19051-3-git-send-email-zach.brown@ni.com>

From: Jeff Westfahl <jeff.westfahl at ni.com>

Implement the new mtd function 'max_bad_blocks'. Use the ONFI parameter
page to find the maximum bad blocks to reserve for an MTD, taking into
account how many LUNs the MTD spans.

Signed-off-by: Jeff Westfahl <jeff.westfahl at ni.com>
Signed-off-by: Zach Brown <zach.brown at ni.com>
---
 drivers/mtd/nand/nand_base.c | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index e5718e5..ac08224 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -3226,6 +3226,39 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
 }
 
 /**
+ * nand_max_bad_blocks - [MTD Interface] Max number of bad blocks for an mtd
+ * @mtd: MTD device structure
+ * @ofs: offset relative to mtd start
+ * @len: length of mtd
+ */
+static int nand_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	uint32_t part_start_block;
+	uint32_t part_end_block;
+	uint32_t part_start_lun;
+	uint32_t part_end_lun;
+
+	/* ONFI is used to determine the maximum bad block count. */
+	if (!chip->onfi_version)
+		return -ENOTSUPP;
+
+	/* Get the start and end of the partition in erase blocks. */
+	part_start_block = mtd_div_by_eb(ofs, mtd);
+	part_end_block = mtd_div_by_eb(len, mtd) + part_start_block - 1;
+
+	/* Get the start and end LUNs of the partition. */
+	part_start_lun = part_start_block / chip->onfi_params.blocks_per_lun;
+	part_end_lun = part_end_block / chip->onfi_params.blocks_per_lun;
+
+	/* Look up the bad blocks per unit and multiply by the number of units
+	 * that the partition spans.
+	 */
+	return chip->onfi_params.bb_per_lun *
+		(part_end_lun - part_start_lun + 1);
+}
+
+/**
  * nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand
  * @mtd: MTD device structure
  * @chip: nand chip info structure
@@ -4743,6 +4776,7 @@ int nand_scan_tail(struct mtd_info *mtd)
 	mtd->_block_isreserved = nand_block_isreserved;
 	mtd->_block_isbad = nand_block_isbad;
 	mtd->_block_markbad = nand_block_markbad;
+	mtd->_max_bad_blocks = nand_max_bad_blocks;
 	mtd->writebufsize = mtd->writesize;
 
 	/*
-- 
2.7.4



From zach.brown at ni.com  Thu Oct 20 07:58:55 2016
From: zach.brown at ni.com (Zach Brown)
Date: Thu, 20 Oct 2016 09:58:55 -0500
Subject: [PATCH v2 0/3] mtd: use ONFI bad blocks per LUN to calculate UBI bad
 PEB limit
Message-ID: <1476975538-19051-1-git-send-email-zach.brown@ni.com>

For ONFI-compliant NAND devices, the ONFI parameters report the maximum number
of bad blocks per LUN that will be encountered over the lifetime of the device,
so we can use that information to get a more accurate (and smaller) value for
the UBI bad PEB limit.

The ONFI parameter "maxiumum number of bad blocks per LUN" is the max number of
bad blocks that each individual LUN will ever ecounter. It is not the number of
bad blocks to reserve for the nand device per LUN in the device.

This means that in the worst case a UBI device spanning X LUNs will encounter
"maximum number of bad blocks per LUN" * X bad blocks. The implementation in
this patch assumes this worst case and allocates bad block accordingly.

These patches are ordered in terms of their dependencies, but ideally, all 3
would need to be applied for this to work as intended.

v1:
 * Changed commit message to address concerns from v1[1] about this patch set
   making best case assumptions.

[1]
http://lkml.iu.edu/hypermail/linux/kernel/1505.1/04822.html

Jeff Westfahl (3):
  mtd: introduce function max_bad_blocks
  mtd: nand: implement 'max_bad_blocks' mtd function
  mtd: ubi: use 'max_bad_blocks' to compute bad_peb_limit if available

 drivers/mtd/mtdpart.c        | 12 ++++++++++++
 drivers/mtd/nand/nand_base.c | 34 ++++++++++++++++++++++++++++++++++
 drivers/mtd/ubi/build.c      |  9 +++++++++
 include/linux/mtd/mtd.h      |  1 +
 4 files changed, 56 insertions(+)

--
2.7.4



From zach.brown at ni.com  Thu Oct 20 07:58:58 2016
From: zach.brown at ni.com (Zach Brown)
Date: Thu, 20 Oct 2016 09:58:58 -0500
Subject: [PATCH v2 3/3] mtd: ubi: use 'max_bad_blocks' to compute
 bad_peb_limit if available
In-Reply-To: <1476975538-19051-1-git-send-email-zach.brown@ni.com>
References: <1476975538-19051-1-git-send-email-zach.brown@ni.com>
Message-ID: <1476975538-19051-4-git-send-email-zach.brown@ni.com>

From: Jeff Westfahl <jeff.westfahl at ni.com>

Use the MTD function 'max_bad_blocks' to compute the UBI bad_peb_limit,
if the function is implemented for an MTD and doesn't return an error.

Signed-off-by: Jeff Westfahl <jeff.westfahl at ni.com>
Signed-off-by: Zach Brown <zach.brown at ni.com>
---
 drivers/mtd/ubi/build.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 0680516..f713a30 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -584,6 +584,15 @@ static int get_bad_peb_limit(const struct ubi_device *ubi, int max_beb_per1024)
 	int limit, device_pebs;
 	uint64_t device_size;
 
+	/* If the MTD provides a max_bad_blocks function, use that value. Fall
+	 * back to max_beb_per1024 if that function returns an error.
+	 */
+	if (ubi->mtd->_max_bad_blocks) {
+		limit = ubi->mtd->_max_bad_blocks(ubi->mtd, 0, ubi->mtd->size);
+		if (limit > 0)
+			return limit;
+	}
+
 	if (!max_beb_per1024)
 		return 0;
 
-- 
2.7.4



From cyrille.pitchen at atmel.com  Thu Oct 20 08:23:08 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Thu, 20 Oct 2016 17:23:08 +0200
Subject: [PATCH] mtd: spi-nor: fixed spansion quad enable
In-Reply-To: <1476971026-9665-1-git-send-email-joel.esponde@honeywell.com>
References: <1476971026-9665-1-git-send-email-joel.esponde@honeywell.com>
Message-ID: <56670303-e8e8-fb2c-e043-035c566f347c@atmel.com>

Hi Jo?l,

Le 20/10/2016 ? 15:43, Jo?l Esponde a ?crit :
> With the S25FL127S nor flash part, each writing to the configuration register takes hundreds of ms. During that  time, no more accesses to the flash should be done (even reads).
> 
> This commit adds:
> - a pre check of the quad enable bit to avoid a useless and time consuming writing to the flash,
> - a wait loop after the register writing until the flash finishes its work.
> 
> This issue could make rootfs mounting fail when the latter was done too much closely to this quad enable bit setting step. And in this case, a driver as UBIFS may try to recover the filesystem and may broke it completely.
> ---
>  drivers/mtd/spi-nor/spi-nor.c | 31 +++++++++++++++++++++++++++----
>  1 file changed, 27 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
> index d0fc165..df43cd7 100644
> --- a/drivers/mtd/spi-nor/spi-nor.c
> +++ b/drivers/mtd/spi-nor/spi-nor.c
> @@ -1246,18 +1246,41 @@ static int spansion_quad_enable(struct spi_nor *nor)
>  	int ret;
>  	int quad_en = CR_QUAD_EN_SPAN << 8;
>  
> +	/* check quad enable bit
> +	 * as S25FL127S takes 200 ms to execute each write of SR & CR 
> +	 * registers even if data is the same, write step will be shorted 
> +	 * if not needed
> +	 */
> +	ret = read_cr(nor);

Sorry but the Read Configuration Register (35h) command is not supported by
all Spansion (or Spansion-like) memories.

For more details, please refer to the JEDEC JESD216B specification, especially
the part dealing with the "Quad Enable Requirements". An extract of this
specification can also be found in this patch:
https://patchwork.ozlabs.org/patch/678408/

Please have a look at values 001b, 100b and 101b for the bits[22:20] of the
15th DWORD.

I think your patch is likely to introduce a regression on some old memory
parts.

However, *if* your S25FL127S memory implements the SFDP tables correctly,
bits[22:20] of the 15th DWORD should be set to 101b, hence using SFDP patch
above should fix the issue:
spansion_new_quad_enable() will be called instead of the current
spansion_quad_enable(). This new function adds the very same test on the Quad
Enable bit as your patch does.

If you want to test the SFDP patch, you will need to apply the whole series
which introduces some improvement on QSPI memory support:
http://lists.infradead.org/pipermail/linux-mtd/2016-October/069554.html

I'm just cautious with Spansion memories: I tested one sample, and I guess
it was a S25FL127S, which claimed to be compliant with JESD216 rev B (minor 6)
but words after the 9th one were all 0xffffffff.
JESD216 (minor 0) describes only 9 DWORDs in the Basic Flash Parameter Table
JESD216 rev A (minor 5) introduces 7 new DWORDS, hence 16 DWORDS in the (BFPT).
the 15th DWORD provides the Quad Enable Requirements, which describes the
procedure to set the Quad Enable bit.

If the BFPT of your S25FL127S is incomplete but the memory still claiming to be
JESD216 rev B compliant, neither spansion_quad_enable() nor
spansion_new_quad_enable() would be called. Since the Quad Enable bit is
non-volatile on Spansion memories, it will work if the bit as already been set
before.


Best regards,

Cyrille

> +	if (ret < 0) {
> +		dev_err(nor->dev, "error %d reading CR\n", ret);
> +		return ret;
> +	} 
> +	if (ret & CR_QUAD_EN_SPAN) {
> +		/* quad enable bit is already set */
> +		return 0;
> +	}
> +
> +	/* set SR & CR, enable quad I/O */
>  	write_enable(nor);
>  
>  	ret = write_sr_cr(nor, quad_en);
>  	if (ret < 0) {
> -		dev_err(nor->dev,
> -			"error while writing configuration register\n");
> +		dev_err(nor->dev, "error while writing SR and CR registers\n");
>  		return -EINVAL;
>  	}
>  
> -	/* read back and check it */
> +	ret = spi_nor_wait_till_ready(nor);
> +	if (ret)
> +		return ret;
> +	
> +	/* read CR and check it */
>  	ret = read_cr(nor);
> -	if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
> +	if (ret < 0) {
> +		dev_err(nor->dev, "error %d reading CR\n", ret);
> +		return ret;
> +	}
> +	if (!(ret & CR_QUAD_EN_SPAN)) {
>  		dev_err(nor->dev, "Spansion Quad bit not set\n");
>  		return -EINVAL;
>  	}
> 



From maxime.ripard at free-electrons.com  Thu Oct 20 10:06:02 2016
From: maxime.ripard at free-electrons.com (Maxime Ripard)
Date: Thu, 20 Oct 2016 19:06:02 +0200
Subject: [PATCH 3/8] ARM: gr8: Add the UART3
In-Reply-To: <CAGb2v65iR=mZyCQrF64HOku5Sq7fNKGhV=Yy3zUFYzB=4ozkWg@mail.gmail.com>
References: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
 <b62c8661eb3c2d72e61511794a3ab1b43f005805.1476951078.git-series.maxime.ripard@free-electrons.com>
 <CAGb2v65iR=mZyCQrF64HOku5Sq7fNKGhV=Yy3zUFYzB=4ozkWg@mail.gmail.com>
Message-ID: <20161020170602.mkk3cp2om2xbtmen@lukather>

On Thu, Oct 20, 2016 at 10:06:47PM +0800, Chen-Yu Tsai wrote:
> On Thu, Oct 20, 2016 at 4:12 PM, Maxime Ripard
> <maxime.ripard at free-electrons.com> wrote:
> > The GR8 has access to the UART3 controller, which was missing in the
> > DTSI. Add it.
> >
> > Signed-off-by: Maxime Ripard <maxime.ripard at free-electrons.com>
> 
> Acked-by: Chen-Yu Tsai <wens at csie.org>

Applied.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20161020/9ecfcb79/attachment.sig>

From maxime.ripard at free-electrons.com  Thu Oct 20 10:06:21 2016
From: maxime.ripard at free-electrons.com (Maxime Ripard)
Date: Thu, 20 Oct 2016 19:06:21 +0200
Subject: [PATCH 4/8] ARM: gr8: Fix typo in the i2s mclk pin group
In-Reply-To: <CAGb2v65P6WEZCy8AXCk5mV4gWgiWuZJiDZzJnEgr+sj9qf8ORA@mail.gmail.com>
References: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
 <f1c79380c34fcc2a1c1ff75ca91177de3b7380a9.1476951078.git-series.maxime.ripard@free-electrons.com>
 <CAGb2v65P6WEZCy8AXCk5mV4gWgiWuZJiDZzJnEgr+sj9qf8ORA@mail.gmail.com>
Message-ID: <20161020170621.wlwd3hv3py2sme5s@lukather>

On Thu, Oct 20, 2016 at 10:07:46PM +0800, Chen-Yu Tsai wrote:
> On Thu, Oct 20, 2016 at 4:12 PM, Maxime Ripard
> <maxime.ripard at free-electrons.com> wrote:
> > There was a dumb copy and paste mistake here, fix it.
> >
> > Signed-off-by: Maxime Ripard <maxime.ripard at free-electrons.com>
> 
> Acked-by: Chen-Yu Tsai <wens at csie.org>

Applied.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20161020/a2f2fddd/attachment-0001.sig>

From maxime.ripard at free-electrons.com  Thu Oct 20 10:07:39 2016
From: maxime.ripard at free-electrons.com (Maxime Ripard)
Date: Thu, 20 Oct 2016 19:07:39 +0200
Subject: [PATCH 5/8] ARM: gr8: Add missing pwm channel 1 pin
In-Reply-To: <CAGb2v66w0sTzn_SWH4rrpWKOosSxALV8ot3CBQbGhwLxvX1vxw@mail.gmail.com>
References: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
 <0df42247c3348e7f6aed945e5669cec87f96f7ac.1476951078.git-series.maxime.ripard@free-electrons.com>
 <CAGb2v66w0sTzn_SWH4rrpWKOosSxALV8ot3CBQbGhwLxvX1vxw@mail.gmail.com>
Message-ID: <20161020170739.lgt2ywm346vm47zd@lukather>

On Thu, Oct 20, 2016 at 10:10:03PM +0800, Chen-Yu Tsai wrote:
> On Thu, Oct 20, 2016 at 4:12 PM, Maxime Ripard
> <maxime.ripard at free-electrons.com> wrote:
> > The PWM controller has two different channels, but only the first pin was
> > exposed in the DTSI. Add the other one.
> >
> > Signed-off-by: Maxime Ripard <maxime.ripard at free-electrons.com>
> 
> Acked-by: Chen-Yu Tsai <wens at csie.org>
> 
> > ---
> >  arch/arm/boot/dts/ntc-gr8.dtsi | 7 +++++++
> >  1 file changed, 7 insertions(+), 0 deletions(-)
> >
> > diff --git a/arch/arm/boot/dts/ntc-gr8.dtsi b/arch/arm/boot/dts/ntc-gr8.dtsi
> > index 74aff795e723..fad7381630f3 100644
> > --- a/arch/arm/boot/dts/ntc-gr8.dtsi
> > +++ b/arch/arm/boot/dts/ntc-gr8.dtsi
> > @@ -854,6 +854,13 @@
> >                                 allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
> >                         };
> >
> > +                       pwm1_pins_a: pwm1 at 0 {
> 
> Nit: really don't need "_a" and "@0" here.

Fixed and applied.

Thanks!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20161020/8e9d5601/attachment.sig>

From maxime.ripard at free-electrons.com  Thu Oct 20 10:08:02 2016
From: maxime.ripard at free-electrons.com (Maxime Ripard)
Date: Thu, 20 Oct 2016 19:08:02 +0200
Subject: [PATCH 6/8] ARM: gr8: Add UART2 pins
In-Reply-To: <CAGb2v641SWJTG=3AmHE3zAypuoq7fL7gFLBXwfXpmCYw7K0Guw@mail.gmail.com>
References: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
 <0c1f98755c7dd1764dcd89a599f182a0face286f.1476951078.git-series.maxime.ripard@free-electrons.com>
 <CAGb2v641SWJTG=3AmHE3zAypuoq7fL7gFLBXwfXpmCYw7K0Guw@mail.gmail.com>
Message-ID: <20161020170802.36yohn7mtrvdphhh@lukather>

On Thu, Oct 20, 2016 at 10:14:09PM +0800, Chen-Yu Tsai wrote:
> On Thu, Oct 20, 2016 at 4:12 PM, Maxime Ripard
> <maxime.ripard at free-electrons.com> wrote:
> > The UART2 pins were missing from the DTSI. Add them.
> >
> > Signed-off-by: Maxime Ripard <maxime.ripard at free-electrons.com>
> 
> Acked-by: Chen-Yu Tsai <wens at csie.org>

Applied.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20161020/2ea1e28b/attachment.sig>

From maxime.ripard at free-electrons.com  Thu Oct 20 10:08:26 2016
From: maxime.ripard at free-electrons.com (Maxime Ripard)
Date: Thu, 20 Oct 2016 19:08:26 +0200
Subject: [PATCH 7/8] ARM: gr8: Add UART3 pins
In-Reply-To: <CAGb2v65OXss+_jKMSJD-KUDeK2iH96mmvDvPEzgW60PUXoS90g@mail.gmail.com>
References: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
 <cc81030de43c26dfc15ad9a9e525188ad8fb8ec9.1476951078.git-series.maxime.ripard@free-electrons.com>
 <CAGb2v65OXss+_jKMSJD-KUDeK2iH96mmvDvPEzgW60PUXoS90g@mail.gmail.com>
Message-ID: <20161020170826.wdhgn2uozowmkx5u@lukather>

On Thu, Oct 20, 2016 at 10:16:11PM +0800, Chen-Yu Tsai wrote:
> On Thu, Oct 20, 2016 at 4:12 PM, Maxime Ripard
> <maxime.ripard at free-electrons.com> wrote:
> > The UART3 pins were missing from the DTSI. Add them.
> >
> > Signed-off-by: Maxime Ripard <maxime.ripard at free-electrons.com>
> 
> Acked-by: Chen-Yu Tsai <wens at csie.org>

Applied

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20161020/35b9f488/attachment.sig>

From maxime.ripard at free-electrons.com  Thu Oct 20 10:08:44 2016
From: maxime.ripard at free-electrons.com (Maxime Ripard)
Date: Thu, 20 Oct 2016 19:08:44 +0200
Subject: [PATCH 8/8] ARM: gr8: Add CHIP Pro support
In-Reply-To: <CAGb2v67S8rK6Hdkvkgtfz6hDtiR4a4yUUqB01AnQ4sJ3-SQc0A@mail.gmail.com>
References: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
 <d3f91b731f944fe0e23b4532f6e83a1c2fc345f0.1476951078.git-series.maxime.ripard@free-electrons.com>
 <CAGb2v67S8rK6Hdkvkgtfz6hDtiR4a4yUUqB01AnQ4sJ3-SQc0A@mail.gmail.com>
Message-ID: <20161020170844.a2e3mglefgawwr6p@lukather>

On Thu, Oct 20, 2016 at 10:26:09PM +0800, Chen-Yu Tsai wrote:
> On Thu, Oct 20, 2016 at 4:12 PM, Maxime Ripard
> <maxime.ripard at free-electrons.com> wrote:
> > The CHIP Pro is a small embeddable board. It features a GR8, an AXP209
> > PMIC, a 512MB SLC NAND and a WiFi/BT chip.
> >
> > Signed-off-by: Maxime Ripard <maxime.ripard at free-electrons.com>
> 
> Acked-by: Chen-Yu Tsai <wens at csie.org>

Applied. Thanks for reviewing!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20161020/554a8cfd/attachment.sig>

From sandragomes at amplanet.com.br  Thu Oct 20 06:28:52 2016
From: sandragomes at amplanet.com.br (Google)
Date: Thu, 20 Oct 2016 06:28:52 -0700
Subject: Powered By Google
Message-ID: <20161020132925.0171F260A5@ispconfig.amplanet.com.br>

Dear Google User,

You have been selected as a winner for using Google services. Find attached
email with more details.

Congratulations,

Matt Brittin.
CEO Google UK.

?2016 Google - Terms & Privacy
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Google.jpg
Type: image/jpeg
Size: 761578 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20161020/f63d455d/attachment-0001.jpg>

From krzk at kernel.org  Thu Oct 20 10:50:27 2016
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 20 Oct 2016 20:50:27 +0300
Subject: [PATCH v2 2/3] dt-bindings: mtd: add DT binding for s3c2410
 flash controller
In-Reply-To: <1476906725-22613-3-git-send-email-sergio.prado@e-labworks.com>
References: <1476906725-22613-1-git-send-email-sergio.prado@e-labworks.com>
 <1476906725-22613-3-git-send-email-sergio.prado@e-labworks.com>
Message-ID: <20161020175027.GA7119@kozik-lap>

On Wed, Oct 19, 2016 at 05:52:04PM -0200, Sergio Prado wrote:
> Adds the device tree bindings description for Samsung S3C2410 and
> compatible NAND flash controller.
> 
> Signed-off-by: Sergio Prado <sergio.prado at e-labworks.com>
> ---
>  .../devicetree/bindings/mtd/samsung-s3c2410.txt    | 56 ++++++++++++++++++++++
>  1 file changed, 56 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt
>

Acked-by: Krzysztof Kozlowski <krzk at kernel.org>

Best regards,
Krzysztof



From krzk at kernel.org  Thu Oct 20 10:55:02 2016
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 20 Oct 2016 20:55:02 +0300
Subject: [PATCH v2 1/3] mtd: s3c2410: make ecc mode configurable via
 platform data
In-Reply-To: <1476906725-22613-2-git-send-email-sergio.prado@e-labworks.com>
References: <1476906725-22613-1-git-send-email-sergio.prado@e-labworks.com>
 <1476906725-22613-2-git-send-email-sergio.prado@e-labworks.com>
Message-ID: <20161020175502.GB7119@kozik-lap>

On Wed, Oct 19, 2016 at 05:52:03PM -0200, Sergio Prado wrote:
> Removing CONFIG_MTD_NAND_S3C2410_HWECC option and adding a ecc_mode
> field in the drivers's platform data structure so it can be selectable
> via platform data.
> 
> Also setting this field to NAND_ECC_SOFT in all boards using this
> driver since none of them had CONFIG_MTD_NAND_S3C2410_HWECC enabled.
> 
> Signed-off-by: Sergio Prado <sergio.prado at e-labworks.com>
> ---
>  arch/arm/mach-s3c24xx/common-smdk.c            |   1 +
>  arch/arm/mach-s3c24xx/mach-anubis.c            |   1 +
>  arch/arm/mach-s3c24xx/mach-at2440evb.c         |   1 +
>  arch/arm/mach-s3c24xx/mach-bast.c              |   1 +
>  arch/arm/mach-s3c24xx/mach-gta02.c             |   1 +
>  arch/arm/mach-s3c24xx/mach-jive.c              |   1 +
>  arch/arm/mach-s3c24xx/mach-mini2440.c          |   1 +
>  arch/arm/mach-s3c24xx/mach-osiris.c            |   1 +
>  arch/arm/mach-s3c24xx/mach-qt2410.c            |   1 +
>  arch/arm/mach-s3c24xx/mach-rx1950.c            |   1 +
>  arch/arm/mach-s3c24xx/mach-rx3715.c            |   1 +
>  arch/arm/mach-s3c24xx/mach-vstms.c             |   1 +
>  arch/arm/mach-s3c64xx/mach-hmt.c               |   1 +
>  arch/arm/mach-s3c64xx/mach-mini6410.c          |   1 +
>  arch/arm/mach-s3c64xx/mach-real6410.c          |   1 +

You missed cc-ing Samsung Soc maintainers on v2 and these files belong
to this tree. Please, don't forget next time.

The change itself looks atomic so I guess these files cannot go through
separate tree. In that case:

Acked-by: Krzysztof Kozlowski <krzk at kernel.org>

Best regards,
Krzysztof


>  drivers/mtd/nand/Kconfig                       |   9 --
>  drivers/mtd/nand/s3c2410.c                     | 119 +++++++++++++------------
>  include/linux/platform_data/mtd-nand-s3c2410.h |   6 +-
>  18 files changed, 79 insertions(+), 70 deletions(-)
> 
> diff --git a/arch/arm/mach-s3c24xx/common-smdk.c b/arch/arm/mach-s3c24xx/common-smdk.c
> index e9fbcc91c5c0..9e0bc46e90ec 100644
> --- a/arch/arm/mach-s3c24xx/common-smdk.c
> +++ b/arch/arm/mach-s3c24xx/common-smdk.c
> @@ -171,6 +171,7 @@
>  	.twrph1		= 20,
>  	.nr_sets	= ARRAY_SIZE(smdk_nand_sets),
>  	.sets		= smdk_nand_sets,
> +	.ecc_mode       = NAND_ECC_SOFT,
>  };
>  
>  /* devices we initialise */
> diff --git a/arch/arm/mach-s3c24xx/mach-anubis.c b/arch/arm/mach-s3c24xx/mach-anubis.c
> index d03df0df01fa..029ef1b58925 100644
> --- a/arch/arm/mach-s3c24xx/mach-anubis.c
> +++ b/arch/arm/mach-s3c24xx/mach-anubis.c
> @@ -223,6 +223,7 @@ static void anubis_nand_select(struct s3c2410_nand_set *set, int slot)
>  	.nr_sets	= ARRAY_SIZE(anubis_nand_sets),
>  	.sets		= anubis_nand_sets,
>  	.select_chip	= anubis_nand_select,
> +	.ecc_mode       = NAND_ECC_SOFT,
>  };
>  
>  /* IDE channels */
> diff --git a/arch/arm/mach-s3c24xx/mach-at2440evb.c b/arch/arm/mach-s3c24xx/mach-at2440evb.c
> index 9ae170fef2a7..7b28eb623fc1 100644
> --- a/arch/arm/mach-s3c24xx/mach-at2440evb.c
> +++ b/arch/arm/mach-s3c24xx/mach-at2440evb.c
> @@ -114,6 +114,7 @@
>  	.twrph1		= 40,
>  	.nr_sets	= ARRAY_SIZE(at2440evb_nand_sets),
>  	.sets		= at2440evb_nand_sets,
> +	.ecc_mode       = NAND_ECC_SOFT,
>  };
>  
>  /* DM9000AEP 10/100 ethernet controller */
> diff --git a/arch/arm/mach-s3c24xx/mach-bast.c b/arch/arm/mach-s3c24xx/mach-bast.c
> index ed07cf392d4b..5185036765db 100644
> --- a/arch/arm/mach-s3c24xx/mach-bast.c
> +++ b/arch/arm/mach-s3c24xx/mach-bast.c
> @@ -299,6 +299,7 @@ static void bast_nand_select(struct s3c2410_nand_set *set, int slot)
>  	.nr_sets	= ARRAY_SIZE(bast_nand_sets),
>  	.sets		= bast_nand_sets,
>  	.select_chip	= bast_nand_select,
> +	.ecc_mode       = NAND_ECC_SOFT,
>  };
>  
>  /* DM9000 */
> diff --git a/arch/arm/mach-s3c24xx/mach-gta02.c b/arch/arm/mach-s3c24xx/mach-gta02.c
> index 27ae6877550f..b0ed401da3a3 100644
> --- a/arch/arm/mach-s3c24xx/mach-gta02.c
> +++ b/arch/arm/mach-s3c24xx/mach-gta02.c
> @@ -443,6 +443,7 @@ static void gta02_udc_vbus_draw(unsigned int ma)
>  	.twrph1		= 15,
>  	.nr_sets	= ARRAY_SIZE(gta02_nand_sets),
>  	.sets		= gta02_nand_sets,
> +	.ecc_mode       = NAND_ECC_SOFT,
>  };
>  
>  
> diff --git a/arch/arm/mach-s3c24xx/mach-jive.c b/arch/arm/mach-s3c24xx/mach-jive.c
> index 7d99fe8f6157..895aca225952 100644
> --- a/arch/arm/mach-s3c24xx/mach-jive.c
> +++ b/arch/arm/mach-s3c24xx/mach-jive.c
> @@ -232,6 +232,7 @@
>  	.twrph1		= 40,
>  	.sets		= jive_nand_sets,
>  	.nr_sets	= ARRAY_SIZE(jive_nand_sets),
> +	.ecc_mode       = NAND_ECC_SOFT,
>  };
>  
>  static int __init jive_mtdset(char *options)
> diff --git a/arch/arm/mach-s3c24xx/mach-mini2440.c b/arch/arm/mach-s3c24xx/mach-mini2440.c
> index ec60bd4a1646..71af8d2fd320 100644
> --- a/arch/arm/mach-s3c24xx/mach-mini2440.c
> +++ b/arch/arm/mach-s3c24xx/mach-mini2440.c
> @@ -287,6 +287,7 @@
>  	.nr_sets	= ARRAY_SIZE(mini2440_nand_sets),
>  	.sets		= mini2440_nand_sets,
>  	.ignore_unset_ecc = 1,
> +	.ecc_mode       = NAND_ECC_SOFT,
>  };
>  
>  /* DM9000AEP 10/100 ethernet controller */
> diff --git a/arch/arm/mach-s3c24xx/mach-osiris.c b/arch/arm/mach-s3c24xx/mach-osiris.c
> index 2f6fdc326835..70b0eb7d3134 100644
> --- a/arch/arm/mach-s3c24xx/mach-osiris.c
> +++ b/arch/arm/mach-s3c24xx/mach-osiris.c
> @@ -238,6 +238,7 @@ static void osiris_nand_select(struct s3c2410_nand_set *set, int slot)
>  	.nr_sets	= ARRAY_SIZE(osiris_nand_sets),
>  	.sets		= osiris_nand_sets,
>  	.select_chip	= osiris_nand_select,
> +	.ecc_mode       = NAND_ECC_SOFT,
>  };
>  
>  /* PCMCIA control and configuration */
> diff --git a/arch/arm/mach-s3c24xx/mach-qt2410.c b/arch/arm/mach-s3c24xx/mach-qt2410.c
> index 984516e8307a..868c82087403 100644
> --- a/arch/arm/mach-s3c24xx/mach-qt2410.c
> +++ b/arch/arm/mach-s3c24xx/mach-qt2410.c
> @@ -284,6 +284,7 @@
>  	.twrph1		= 20,
>  	.nr_sets	= ARRAY_SIZE(qt2410_nand_sets),
>  	.sets		= qt2410_nand_sets,
> +	.ecc_mode       = NAND_ECC_SOFT,
>  };
>  
>  /* UDC */
> diff --git a/arch/arm/mach-s3c24xx/mach-rx1950.c b/arch/arm/mach-s3c24xx/mach-rx1950.c
> index 25a139bb9826..e86ad6a68a0b 100644
> --- a/arch/arm/mach-s3c24xx/mach-rx1950.c
> +++ b/arch/arm/mach-s3c24xx/mach-rx1950.c
> @@ -611,6 +611,7 @@ static void rx1950_set_mmc_power(unsigned char power_mode, unsigned short vdd)
>  	.twrph1 = 15,
>  	.nr_sets = ARRAY_SIZE(rx1950_nand_sets),
>  	.sets = rx1950_nand_sets,
> +	.ecc_mode = NAND_ECC_SOFT,
>  };
>  
>  static struct s3c2410_udc_mach_info rx1950_udc_cfg __initdata = {
> diff --git a/arch/arm/mach-s3c24xx/mach-rx3715.c b/arch/arm/mach-s3c24xx/mach-rx3715.c
> index cf55196f89ca..a39fb9780dd3 100644
> --- a/arch/arm/mach-s3c24xx/mach-rx3715.c
> +++ b/arch/arm/mach-s3c24xx/mach-rx3715.c
> @@ -164,6 +164,7 @@
>  	.twrph1		= 15,
>  	.nr_sets	= ARRAY_SIZE(rx3715_nand_sets),
>  	.sets		= rx3715_nand_sets,
> +	.ecc_mode       = NAND_ECC_SOFT,
>  };
>  
>  static struct platform_device *rx3715_devices[] __initdata = {
> diff --git a/arch/arm/mach-s3c24xx/mach-vstms.c b/arch/arm/mach-s3c24xx/mach-vstms.c
> index b4460d5f7011..f5e6322145fa 100644
> --- a/arch/arm/mach-s3c24xx/mach-vstms.c
> +++ b/arch/arm/mach-s3c24xx/mach-vstms.c
> @@ -117,6 +117,7 @@
>  	.twrph1		= 20,
>  	.nr_sets	= ARRAY_SIZE(vstms_nand_sets),
>  	.sets		= vstms_nand_sets,
> +	.ecc_mode       = NAND_ECC_SOFT,
>  };
>  
>  static struct platform_device *vstms_devices[] __initdata = {
> diff --git a/arch/arm/mach-s3c64xx/mach-hmt.c b/arch/arm/mach-s3c64xx/mach-hmt.c
> index bc7dc1fcbf7d..59b5531f1987 100644
> --- a/arch/arm/mach-s3c64xx/mach-hmt.c
> +++ b/arch/arm/mach-s3c64xx/mach-hmt.c
> @@ -204,6 +204,7 @@ static void hmt_bl_exit(struct device *dev)
>  	.twrph1		= 40,
>  	.nr_sets	= ARRAY_SIZE(hmt_nand_sets),
>  	.sets		= hmt_nand_sets,
> +	.ecc_mode       = NAND_ECC_SOFT,
>  };
>  
>  static struct gpio_led hmt_leds[] = {
> diff --git a/arch/arm/mach-s3c64xx/mach-mini6410.c b/arch/arm/mach-s3c64xx/mach-mini6410.c
> index ae999fb3fe6d..a3e3e25728b4 100644
> --- a/arch/arm/mach-s3c64xx/mach-mini6410.c
> +++ b/arch/arm/mach-s3c64xx/mach-mini6410.c
> @@ -142,6 +142,7 @@
>  	.twrph1		= 40,
>  	.nr_sets	= ARRAY_SIZE(mini6410_nand_sets),
>  	.sets		= mini6410_nand_sets,
> +	.ecc_mode       = NAND_ECC_SOFT,
>  };
>  
>  static struct s3c_fb_pd_win mini6410_lcd_type0_fb_win = {
> diff --git a/arch/arm/mach-s3c64xx/mach-real6410.c b/arch/arm/mach-s3c64xx/mach-real6410.c
> index 4e240ffa7ac7..d6b3ffd7704b 100644
> --- a/arch/arm/mach-s3c64xx/mach-real6410.c
> +++ b/arch/arm/mach-s3c64xx/mach-real6410.c
> @@ -194,6 +194,7 @@
>  	.twrph1		= 40,
>  	.nr_sets	= ARRAY_SIZE(real6410_nand_sets),
>  	.sets		= real6410_nand_sets,
> +	.ecc_mode       = NAND_ECC_SOFT,
>  };
>  
>  static struct platform_device *real6410_devices[] __initdata = {
> diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
> index 7b7a887b4709..9748f3580d4b 100644
> --- a/drivers/mtd/nand/Kconfig
> +++ b/drivers/mtd/nand/Kconfig
> @@ -179,15 +179,6 @@ config MTD_NAND_S3C2410_DEBUG
>  	help
>  	  Enable debugging of the S3C NAND driver
>  
> -config MTD_NAND_S3C2410_HWECC
> -	bool "Samsung S3C NAND Hardware ECC"
> -	depends on MTD_NAND_S3C2410
> -	help
> -	  Enable the use of the controller's internal ECC generator when
> -	  using NAND. Early versions of the chips have had problems with
> -	  incorrect ECC generation, and if using these, the default of
> -	  software ECC is preferable.
> -
>  config MTD_NAND_NDFC
>  	tristate "NDFC NanD Flash Controller"
>  	depends on 4xx
> diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
> index d459c19d78de..371db0d48135 100644
> --- a/drivers/mtd/nand/s3c2410.c
> +++ b/drivers/mtd/nand/s3c2410.c
> @@ -497,7 +497,6 @@ static int s3c2412_nand_devready(struct mtd_info *mtd)
>  
>  /* ECC handling functions */
>  
> -#ifdef CONFIG_MTD_NAND_S3C2410_HWECC
>  static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
>  				     u_char *read_ecc, u_char *calc_ecc)
>  {
> @@ -649,7 +648,6 @@ static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
>  
>  	return 0;
>  }
> -#endif
>  
>  /* over-ride the standard functions for a little more speed. We can
>   * use read/write block to move the data buffers to/from the controller
> @@ -858,50 +856,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
>  	nmtd->info	   = info;
>  	nmtd->set	   = set;
>  
> -#ifdef CONFIG_MTD_NAND_S3C2410_HWECC
> -	chip->ecc.calculate = s3c2410_nand_calculate_ecc;
> -	chip->ecc.correct   = s3c2410_nand_correct_data;
> -	chip->ecc.mode	    = NAND_ECC_HW;
> -	chip->ecc.strength  = 1;
> -
> -	switch (info->cpu_type) {
> -	case TYPE_S3C2410:
> -		chip->ecc.hwctl	    = s3c2410_nand_enable_hwecc;
> -		chip->ecc.calculate = s3c2410_nand_calculate_ecc;
> -		break;
> -
> -	case TYPE_S3C2412:
> -		chip->ecc.hwctl     = s3c2412_nand_enable_hwecc;
> -		chip->ecc.calculate = s3c2412_nand_calculate_ecc;
> -		break;
> -
> -	case TYPE_S3C2440:
> -		chip->ecc.hwctl     = s3c2440_nand_enable_hwecc;
> -		chip->ecc.calculate = s3c2440_nand_calculate_ecc;
> -		break;
> -	}
> -#else
> -	chip->ecc.mode	    = NAND_ECC_SOFT;
> -	chip->ecc.algo	= NAND_ECC_HAMMING;
> -#endif
> -
> -	if (set->disable_ecc)
> -		chip->ecc.mode	= NAND_ECC_NONE;
> -
> -	switch (chip->ecc.mode) {
> -	case NAND_ECC_NONE:
> -		dev_info(info->device, "NAND ECC disabled\n");
> -		break;
> -	case NAND_ECC_SOFT:
> -		dev_info(info->device, "NAND soft ECC\n");
> -		break;
> -	case NAND_ECC_HW:
> -		dev_info(info->device, "NAND hardware ECC\n");
> -		break;
> -	default:
> -		dev_info(info->device, "NAND ECC UNKNOWN\n");
> -		break;
> -	}
> +	chip->ecc.mode = info->platform->ecc_mode;
>  
>  	/* If you use u-boot BBT creation code, specifying this flag will
>  	 * let the kernel fish out the BBT from the NAND, and also skip the
> @@ -923,28 +878,72 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
>   *
>   * The internal state is currently limited to the ECC state information.
>  */
> -static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
> +static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
>  				     struct s3c2410_nand_mtd *nmtd)
>  {
>  	struct nand_chip *chip = &nmtd->chip;
>  
> -	dev_dbg(info->device, "chip %p => page shift %d\n",
> -		chip, chip->page_shift);
> +	switch (chip->ecc.mode) {
>  
> -	if (chip->ecc.mode != NAND_ECC_HW)
> -		return;
> +	case NAND_ECC_NONE:
> +		dev_info(info->device, "ECC disabled\n");
> +		break;
> +
> +	case NAND_ECC_SOFT:
> +		/*
> +		 * This driver expects Hamming based ECC when ecc_mode is set
> +		 * to NAND_ECC_SOFT. Force ecc.algo to NAND_ECC_HAMMING to
> +		 * avoid adding an extra ecc_algo field to s3c2410_platform_nand.
> +		 */
> +		chip->ecc.algo = NAND_ECC_HAMMING;
> +		dev_info(info->device, "soft ECC\n");
> +		break;
> +
> +	case NAND_ECC_HW:
> +		chip->ecc.calculate = s3c2410_nand_calculate_ecc;
> +		chip->ecc.correct   = s3c2410_nand_correct_data;
> +		chip->ecc.strength  = 1;
> +
> +		switch (info->cpu_type) {
> +		case TYPE_S3C2410:
> +			chip->ecc.hwctl	    = s3c2410_nand_enable_hwecc;
> +			chip->ecc.calculate = s3c2410_nand_calculate_ecc;
> +			break;
> +
> +		case TYPE_S3C2412:
> +			chip->ecc.hwctl     = s3c2412_nand_enable_hwecc;
> +			chip->ecc.calculate = s3c2412_nand_calculate_ecc;
> +			break;
> +
> +		case TYPE_S3C2440:
> +			chip->ecc.hwctl     = s3c2440_nand_enable_hwecc;
> +			chip->ecc.calculate = s3c2440_nand_calculate_ecc;
> +			break;
> +		}
> +
> +		dev_dbg(info->device, "chip %p => page shift %d\n",
> +			chip, chip->page_shift);
>  
>  		/* change the behaviour depending on whether we are using
>  		 * the large or small page nand device */
> +		if (chip->page_shift > 10) {
> +			chip->ecc.size	    = 256;
> +			chip->ecc.bytes	    = 3;
> +		} else {
> +			chip->ecc.size	    = 512;
> +			chip->ecc.bytes	    = 3;
> +			mtd_set_ooblayout(nand_to_mtd(chip), &s3c2410_ooblayout_ops);
> +		}
>  
> -	if (chip->page_shift > 10) {
> -		chip->ecc.size	    = 256;
> -		chip->ecc.bytes	    = 3;
> -	} else {
> -		chip->ecc.size	    = 512;
> -		chip->ecc.bytes	    = 3;
> -		mtd_set_ooblayout(nand_to_mtd(chip), &s3c2410_ooblayout_ops);
> +		dev_info(info->device, "hardware ECC\n");
> +		break;
> +
> +	default:
> +		dev_err(info->device, "invalid ECC mode!\n");
> +		return -EINVAL;
>  	}
> +
> +	return 0;
>  }
>  
>  /* s3c24xx_nand_probe
> @@ -1046,7 +1045,9 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
>  						 NULL);
>  
>  		if (nmtd->scan_res == 0) {
> -			s3c2410_nand_update_chip(info, nmtd);
> +			err = s3c2410_nand_update_chip(info, nmtd);
> +			if (err < 0)
> +				goto exit_error;
>  			nand_scan_tail(mtd);
>  			s3c2410_nand_add_partition(info, nmtd, sets);
>  		}
> diff --git a/include/linux/platform_data/mtd-nand-s3c2410.h b/include/linux/platform_data/mtd-nand-s3c2410.h
> index c55e42ee57fa..729af13d1773 100644
> --- a/include/linux/platform_data/mtd-nand-s3c2410.h
> +++ b/include/linux/platform_data/mtd-nand-s3c2410.h
> @@ -12,9 +12,10 @@
>  #ifndef __MTD_NAND_S3C2410_H
>  #define __MTD_NAND_S3C2410_H
>  
> +#include <linux/mtd/nand.h>
> +
>  /**
>   * struct s3c2410_nand_set - define a set of one or more nand chips
> - * @disable_ecc:	Entirely disable ECC - Dangerous
>   * @flash_bbt: 		Openmoko u-boot can create a Bad Block Table
>   *			Setting this flag will allow the kernel to
>   *			look for it at boot time and also skip the NAND
> @@ -31,7 +32,6 @@
>   * a warning at boot time.
>   */
>  struct s3c2410_nand_set {
> -	unsigned int		disable_ecc:1;
>  	unsigned int		flash_bbt:1;
>  
>  	unsigned int		options;
> @@ -51,6 +51,8 @@ struct s3c2410_platform_nand {
>  
>  	unsigned int	ignore_unset_ecc:1;
>  
> +	nand_ecc_modes_t	ecc_mode;
> +
>  	int			nr_sets;
>  	struct s3c2410_nand_set *sets;
>  
> -- 
> 1.9.1
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel


From krzk at kernel.org  Thu Oct 20 10:57:45 2016
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 20 Oct 2016 20:57:45 +0300
Subject: [PATCH v2 3/3] mtd: s3c2410: parse the device configuration from
 OF node
In-Reply-To: <1476906725-22613-4-git-send-email-sergio.prado@e-labworks.com>
References: <1476906725-22613-1-git-send-email-sergio.prado@e-labworks.com>
 <1476906725-22613-4-git-send-email-sergio.prado@e-labworks.com>
Message-ID: <20161020175745.GC7119@kozik-lap>

On Wed, Oct 19, 2016 at 05:52:05PM -0200, Sergio Prado wrote:
> Allows configuring Samsung's s3c2410 memory controller using a
> devicetree.
> 
> Signed-off-by: Sergio Prado <sergio.prado at e-labworks.com>
> ---
>  drivers/mtd/nand/s3c2410.c                     | 155 ++++++++++++++++++++++---
>  include/linux/platform_data/mtd-nand-s3c2410.h |   1 +
>  2 files changed, 140 insertions(+), 16 deletions(-)
>


Acked-by: Krzysztof Kozlowski <krzk at kernel.org>

Best regards,
Krzysztof



From sergio.prado at e-labworks.com  Thu Oct 20 14:42:43 2016
From: sergio.prado at e-labworks.com (Sergio Prado)
Date: Thu, 20 Oct 2016 19:42:43 -0200
Subject: [PATCH v3 0/3] mtd: s3c2410: add device tree support
Message-ID: <1476999766-32526-1-git-send-email-sergio.prado@e-labworks.com>

This series adds support for configuring Samsung's s3c2410 and
compatible flash memory controller via devicetree.

Tested on FriendlyARM mini2440, based on s3c2440 SoC.

Patch 3 depends on patch 1.

Changes since v2:
- conditionally assign chip->setup_data_interface to
  s3c2410_nand_setup_data_interface if booting via device tree

Changes since v1:
- automate timing selection when booting with a device tree
- make s3c24XX_nand_devtype_data structs "static const"
- removing samsung,s3c6400-nand compatible since it is equivalent to
  samsung,s3c2412-nand

Changes since initial version:
- patch converted to a patch series
- read timings from nand_sdr_timings when booting with a device tree
- naming improvements in the device tree binding
  (s/nand/nand-controller/, s/_/-, s/children/child)
- dropped property samsung,ignore_unset_ecc
- remove @0 from nand device node
- checking pdev->dev.of_node instead of using ifdef CONFIG_OF_MTD
- preventing from parsing device tree properties twice
- increment the nand controller child node refcount, since we
  maintain a reference to it and its name field
- using of_device_get_match_data() instead of of_match_device()
  to make the code simpler
- remove CONFIG_MTD_NAND_S3C2410_HWECC compile option so we can
  select ECC mode using nand-ecc-mode property in the device tree

Sergio Prado (3):
  mtd: s3c2410: make ecc mode configurable via platform data
  dt-bindings: mtd: add DT binding for s3c2410 flash controller
  mtd: s3c2410: parse the device configuration from OF node

 .../devicetree/bindings/mtd/samsung-s3c2410.txt    |  56 +++++
 arch/arm/mach-s3c24xx/common-smdk.c                |   1 +
 arch/arm/mach-s3c24xx/mach-anubis.c                |   1 +
 arch/arm/mach-s3c24xx/mach-at2440evb.c             |   1 +
 arch/arm/mach-s3c24xx/mach-bast.c                  |   1 +
 arch/arm/mach-s3c24xx/mach-gta02.c                 |   1 +
 arch/arm/mach-s3c24xx/mach-jive.c                  |   1 +
 arch/arm/mach-s3c24xx/mach-mini2440.c              |   1 +
 arch/arm/mach-s3c24xx/mach-osiris.c                |   1 +
 arch/arm/mach-s3c24xx/mach-qt2410.c                |   1 +
 arch/arm/mach-s3c24xx/mach-rx1950.c                |   1 +
 arch/arm/mach-s3c24xx/mach-rx3715.c                |   1 +
 arch/arm/mach-s3c24xx/mach-vstms.c                 |   1 +
 arch/arm/mach-s3c64xx/mach-hmt.c                   |   1 +
 arch/arm/mach-s3c64xx/mach-mini6410.c              |   1 +
 arch/arm/mach-s3c64xx/mach-real6410.c              |   1 +
 drivers/mtd/nand/Kconfig                           |   9 -
 drivers/mtd/nand/s3c2410.c                         | 277 +++++++++++++++------
 include/linux/platform_data/mtd-nand-s3c2410.h     |   7 +-
 19 files changed, 278 insertions(+), 86 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt

-- 
1.9.1



From sergio.prado at e-labworks.com  Thu Oct 20 14:42:44 2016
From: sergio.prado at e-labworks.com (Sergio Prado)
Date: Thu, 20 Oct 2016 19:42:44 -0200
Subject: [PATCH v3 1/3] mtd: s3c2410: make ecc mode configurable via platform
 data
In-Reply-To: <1476999766-32526-1-git-send-email-sergio.prado@e-labworks.com>
References: <1476999766-32526-1-git-send-email-sergio.prado@e-labworks.com>
Message-ID: <1476999766-32526-2-git-send-email-sergio.prado@e-labworks.com>

Removing CONFIG_MTD_NAND_S3C2410_HWECC option and adding a ecc_mode
field in the drivers's platform data structure so it can be selectable
via platform data.

Also setting this field to NAND_ECC_SOFT in all boards using this
driver since none of them had CONFIG_MTD_NAND_S3C2410_HWECC enabled.

Signed-off-by: Sergio Prado <sergio.prado at e-labworks.com>
---
 arch/arm/mach-s3c24xx/common-smdk.c            |   1 +
 arch/arm/mach-s3c24xx/mach-anubis.c            |   1 +
 arch/arm/mach-s3c24xx/mach-at2440evb.c         |   1 +
 arch/arm/mach-s3c24xx/mach-bast.c              |   1 +
 arch/arm/mach-s3c24xx/mach-gta02.c             |   1 +
 arch/arm/mach-s3c24xx/mach-jive.c              |   1 +
 arch/arm/mach-s3c24xx/mach-mini2440.c          |   1 +
 arch/arm/mach-s3c24xx/mach-osiris.c            |   1 +
 arch/arm/mach-s3c24xx/mach-qt2410.c            |   1 +
 arch/arm/mach-s3c24xx/mach-rx1950.c            |   1 +
 arch/arm/mach-s3c24xx/mach-rx3715.c            |   1 +
 arch/arm/mach-s3c24xx/mach-vstms.c             |   1 +
 arch/arm/mach-s3c64xx/mach-hmt.c               |   1 +
 arch/arm/mach-s3c64xx/mach-mini6410.c          |   1 +
 arch/arm/mach-s3c64xx/mach-real6410.c          |   1 +
 drivers/mtd/nand/Kconfig                       |   9 --
 drivers/mtd/nand/s3c2410.c                     | 119 +++++++++++++------------
 include/linux/platform_data/mtd-nand-s3c2410.h |   6 +-
 18 files changed, 79 insertions(+), 70 deletions(-)

diff --git a/arch/arm/mach-s3c24xx/common-smdk.c b/arch/arm/mach-s3c24xx/common-smdk.c
index e9fbcc91c5c0..9e0bc46e90ec 100644
--- a/arch/arm/mach-s3c24xx/common-smdk.c
+++ b/arch/arm/mach-s3c24xx/common-smdk.c
@@ -171,6 +171,7 @@
 	.twrph1		= 20,
 	.nr_sets	= ARRAY_SIZE(smdk_nand_sets),
 	.sets		= smdk_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* devices we initialise */
diff --git a/arch/arm/mach-s3c24xx/mach-anubis.c b/arch/arm/mach-s3c24xx/mach-anubis.c
index d03df0df01fa..029ef1b58925 100644
--- a/arch/arm/mach-s3c24xx/mach-anubis.c
+++ b/arch/arm/mach-s3c24xx/mach-anubis.c
@@ -223,6 +223,7 @@ static void anubis_nand_select(struct s3c2410_nand_set *set, int slot)
 	.nr_sets	= ARRAY_SIZE(anubis_nand_sets),
 	.sets		= anubis_nand_sets,
 	.select_chip	= anubis_nand_select,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* IDE channels */
diff --git a/arch/arm/mach-s3c24xx/mach-at2440evb.c b/arch/arm/mach-s3c24xx/mach-at2440evb.c
index 9ae170fef2a7..7b28eb623fc1 100644
--- a/arch/arm/mach-s3c24xx/mach-at2440evb.c
+++ b/arch/arm/mach-s3c24xx/mach-at2440evb.c
@@ -114,6 +114,7 @@
 	.twrph1		= 40,
 	.nr_sets	= ARRAY_SIZE(at2440evb_nand_sets),
 	.sets		= at2440evb_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* DM9000AEP 10/100 ethernet controller */
diff --git a/arch/arm/mach-s3c24xx/mach-bast.c b/arch/arm/mach-s3c24xx/mach-bast.c
index ed07cf392d4b..5185036765db 100644
--- a/arch/arm/mach-s3c24xx/mach-bast.c
+++ b/arch/arm/mach-s3c24xx/mach-bast.c
@@ -299,6 +299,7 @@ static void bast_nand_select(struct s3c2410_nand_set *set, int slot)
 	.nr_sets	= ARRAY_SIZE(bast_nand_sets),
 	.sets		= bast_nand_sets,
 	.select_chip	= bast_nand_select,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* DM9000 */
diff --git a/arch/arm/mach-s3c24xx/mach-gta02.c b/arch/arm/mach-s3c24xx/mach-gta02.c
index 27ae6877550f..b0ed401da3a3 100644
--- a/arch/arm/mach-s3c24xx/mach-gta02.c
+++ b/arch/arm/mach-s3c24xx/mach-gta02.c
@@ -443,6 +443,7 @@ static void gta02_udc_vbus_draw(unsigned int ma)
 	.twrph1		= 15,
 	.nr_sets	= ARRAY_SIZE(gta02_nand_sets),
 	.sets		= gta02_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 
diff --git a/arch/arm/mach-s3c24xx/mach-jive.c b/arch/arm/mach-s3c24xx/mach-jive.c
index 7d99fe8f6157..895aca225952 100644
--- a/arch/arm/mach-s3c24xx/mach-jive.c
+++ b/arch/arm/mach-s3c24xx/mach-jive.c
@@ -232,6 +232,7 @@
 	.twrph1		= 40,
 	.sets		= jive_nand_sets,
 	.nr_sets	= ARRAY_SIZE(jive_nand_sets),
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 static int __init jive_mtdset(char *options)
diff --git a/arch/arm/mach-s3c24xx/mach-mini2440.c b/arch/arm/mach-s3c24xx/mach-mini2440.c
index ec60bd4a1646..71af8d2fd320 100644
--- a/arch/arm/mach-s3c24xx/mach-mini2440.c
+++ b/arch/arm/mach-s3c24xx/mach-mini2440.c
@@ -287,6 +287,7 @@
 	.nr_sets	= ARRAY_SIZE(mini2440_nand_sets),
 	.sets		= mini2440_nand_sets,
 	.ignore_unset_ecc = 1,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* DM9000AEP 10/100 ethernet controller */
diff --git a/arch/arm/mach-s3c24xx/mach-osiris.c b/arch/arm/mach-s3c24xx/mach-osiris.c
index 2f6fdc326835..70b0eb7d3134 100644
--- a/arch/arm/mach-s3c24xx/mach-osiris.c
+++ b/arch/arm/mach-s3c24xx/mach-osiris.c
@@ -238,6 +238,7 @@ static void osiris_nand_select(struct s3c2410_nand_set *set, int slot)
 	.nr_sets	= ARRAY_SIZE(osiris_nand_sets),
 	.sets		= osiris_nand_sets,
 	.select_chip	= osiris_nand_select,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* PCMCIA control and configuration */
diff --git a/arch/arm/mach-s3c24xx/mach-qt2410.c b/arch/arm/mach-s3c24xx/mach-qt2410.c
index 984516e8307a..868c82087403 100644
--- a/arch/arm/mach-s3c24xx/mach-qt2410.c
+++ b/arch/arm/mach-s3c24xx/mach-qt2410.c
@@ -284,6 +284,7 @@
 	.twrph1		= 20,
 	.nr_sets	= ARRAY_SIZE(qt2410_nand_sets),
 	.sets		= qt2410_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* UDC */
diff --git a/arch/arm/mach-s3c24xx/mach-rx1950.c b/arch/arm/mach-s3c24xx/mach-rx1950.c
index 25a139bb9826..e86ad6a68a0b 100644
--- a/arch/arm/mach-s3c24xx/mach-rx1950.c
+++ b/arch/arm/mach-s3c24xx/mach-rx1950.c
@@ -611,6 +611,7 @@ static void rx1950_set_mmc_power(unsigned char power_mode, unsigned short vdd)
 	.twrph1 = 15,
 	.nr_sets = ARRAY_SIZE(rx1950_nand_sets),
 	.sets = rx1950_nand_sets,
+	.ecc_mode = NAND_ECC_SOFT,
 };
 
 static struct s3c2410_udc_mach_info rx1950_udc_cfg __initdata = {
diff --git a/arch/arm/mach-s3c24xx/mach-rx3715.c b/arch/arm/mach-s3c24xx/mach-rx3715.c
index cf55196f89ca..a39fb9780dd3 100644
--- a/arch/arm/mach-s3c24xx/mach-rx3715.c
+++ b/arch/arm/mach-s3c24xx/mach-rx3715.c
@@ -164,6 +164,7 @@
 	.twrph1		= 15,
 	.nr_sets	= ARRAY_SIZE(rx3715_nand_sets),
 	.sets		= rx3715_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 static struct platform_device *rx3715_devices[] __initdata = {
diff --git a/arch/arm/mach-s3c24xx/mach-vstms.c b/arch/arm/mach-s3c24xx/mach-vstms.c
index b4460d5f7011..f5e6322145fa 100644
--- a/arch/arm/mach-s3c24xx/mach-vstms.c
+++ b/arch/arm/mach-s3c24xx/mach-vstms.c
@@ -117,6 +117,7 @@
 	.twrph1		= 20,
 	.nr_sets	= ARRAY_SIZE(vstms_nand_sets),
 	.sets		= vstms_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 static struct platform_device *vstms_devices[] __initdata = {
diff --git a/arch/arm/mach-s3c64xx/mach-hmt.c b/arch/arm/mach-s3c64xx/mach-hmt.c
index bc7dc1fcbf7d..59b5531f1987 100644
--- a/arch/arm/mach-s3c64xx/mach-hmt.c
+++ b/arch/arm/mach-s3c64xx/mach-hmt.c
@@ -204,6 +204,7 @@ static void hmt_bl_exit(struct device *dev)
 	.twrph1		= 40,
 	.nr_sets	= ARRAY_SIZE(hmt_nand_sets),
 	.sets		= hmt_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 static struct gpio_led hmt_leds[] = {
diff --git a/arch/arm/mach-s3c64xx/mach-mini6410.c b/arch/arm/mach-s3c64xx/mach-mini6410.c
index ae999fb3fe6d..a3e3e25728b4 100644
--- a/arch/arm/mach-s3c64xx/mach-mini6410.c
+++ b/arch/arm/mach-s3c64xx/mach-mini6410.c
@@ -142,6 +142,7 @@
 	.twrph1		= 40,
 	.nr_sets	= ARRAY_SIZE(mini6410_nand_sets),
 	.sets		= mini6410_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 static struct s3c_fb_pd_win mini6410_lcd_type0_fb_win = {
diff --git a/arch/arm/mach-s3c64xx/mach-real6410.c b/arch/arm/mach-s3c64xx/mach-real6410.c
index 4e240ffa7ac7..d6b3ffd7704b 100644
--- a/arch/arm/mach-s3c64xx/mach-real6410.c
+++ b/arch/arm/mach-s3c64xx/mach-real6410.c
@@ -194,6 +194,7 @@
 	.twrph1		= 40,
 	.nr_sets	= ARRAY_SIZE(real6410_nand_sets),
 	.sets		= real6410_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 static struct platform_device *real6410_devices[] __initdata = {
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 7b7a887b4709..9748f3580d4b 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -179,15 +179,6 @@ config MTD_NAND_S3C2410_DEBUG
 	help
 	  Enable debugging of the S3C NAND driver
 
-config MTD_NAND_S3C2410_HWECC
-	bool "Samsung S3C NAND Hardware ECC"
-	depends on MTD_NAND_S3C2410
-	help
-	  Enable the use of the controller's internal ECC generator when
-	  using NAND. Early versions of the chips have had problems with
-	  incorrect ECC generation, and if using these, the default of
-	  software ECC is preferable.
-
 config MTD_NAND_NDFC
 	tristate "NDFC NanD Flash Controller"
 	depends on 4xx
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index d459c19d78de..371db0d48135 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -497,7 +497,6 @@ static int s3c2412_nand_devready(struct mtd_info *mtd)
 
 /* ECC handling functions */
 
-#ifdef CONFIG_MTD_NAND_S3C2410_HWECC
 static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
 				     u_char *read_ecc, u_char *calc_ecc)
 {
@@ -649,7 +648,6 @@ static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
 
 	return 0;
 }
-#endif
 
 /* over-ride the standard functions for a little more speed. We can
  * use read/write block to move the data buffers to/from the controller
@@ -858,50 +856,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
 	nmtd->info	   = info;
 	nmtd->set	   = set;
 
-#ifdef CONFIG_MTD_NAND_S3C2410_HWECC
-	chip->ecc.calculate = s3c2410_nand_calculate_ecc;
-	chip->ecc.correct   = s3c2410_nand_correct_data;
-	chip->ecc.mode	    = NAND_ECC_HW;
-	chip->ecc.strength  = 1;
-
-	switch (info->cpu_type) {
-	case TYPE_S3C2410:
-		chip->ecc.hwctl	    = s3c2410_nand_enable_hwecc;
-		chip->ecc.calculate = s3c2410_nand_calculate_ecc;
-		break;
-
-	case TYPE_S3C2412:
-		chip->ecc.hwctl     = s3c2412_nand_enable_hwecc;
-		chip->ecc.calculate = s3c2412_nand_calculate_ecc;
-		break;
-
-	case TYPE_S3C2440:
-		chip->ecc.hwctl     = s3c2440_nand_enable_hwecc;
-		chip->ecc.calculate = s3c2440_nand_calculate_ecc;
-		break;
-	}
-#else
-	chip->ecc.mode	    = NAND_ECC_SOFT;
-	chip->ecc.algo	= NAND_ECC_HAMMING;
-#endif
-
-	if (set->disable_ecc)
-		chip->ecc.mode	= NAND_ECC_NONE;
-
-	switch (chip->ecc.mode) {
-	case NAND_ECC_NONE:
-		dev_info(info->device, "NAND ECC disabled\n");
-		break;
-	case NAND_ECC_SOFT:
-		dev_info(info->device, "NAND soft ECC\n");
-		break;
-	case NAND_ECC_HW:
-		dev_info(info->device, "NAND hardware ECC\n");
-		break;
-	default:
-		dev_info(info->device, "NAND ECC UNKNOWN\n");
-		break;
-	}
+	chip->ecc.mode = info->platform->ecc_mode;
 
 	/* If you use u-boot BBT creation code, specifying this flag will
 	 * let the kernel fish out the BBT from the NAND, and also skip the
@@ -923,28 +878,72 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
  *
  * The internal state is currently limited to the ECC state information.
 */
-static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
+static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
 				     struct s3c2410_nand_mtd *nmtd)
 {
 	struct nand_chip *chip = &nmtd->chip;
 
-	dev_dbg(info->device, "chip %p => page shift %d\n",
-		chip, chip->page_shift);
+	switch (chip->ecc.mode) {
 
-	if (chip->ecc.mode != NAND_ECC_HW)
-		return;
+	case NAND_ECC_NONE:
+		dev_info(info->device, "ECC disabled\n");
+		break;
+
+	case NAND_ECC_SOFT:
+		/*
+		 * This driver expects Hamming based ECC when ecc_mode is set
+		 * to NAND_ECC_SOFT. Force ecc.algo to NAND_ECC_HAMMING to
+		 * avoid adding an extra ecc_algo field to s3c2410_platform_nand.
+		 */
+		chip->ecc.algo = NAND_ECC_HAMMING;
+		dev_info(info->device, "soft ECC\n");
+		break;
+
+	case NAND_ECC_HW:
+		chip->ecc.calculate = s3c2410_nand_calculate_ecc;
+		chip->ecc.correct   = s3c2410_nand_correct_data;
+		chip->ecc.strength  = 1;
+
+		switch (info->cpu_type) {
+		case TYPE_S3C2410:
+			chip->ecc.hwctl	    = s3c2410_nand_enable_hwecc;
+			chip->ecc.calculate = s3c2410_nand_calculate_ecc;
+			break;
+
+		case TYPE_S3C2412:
+			chip->ecc.hwctl     = s3c2412_nand_enable_hwecc;
+			chip->ecc.calculate = s3c2412_nand_calculate_ecc;
+			break;
+
+		case TYPE_S3C2440:
+			chip->ecc.hwctl     = s3c2440_nand_enable_hwecc;
+			chip->ecc.calculate = s3c2440_nand_calculate_ecc;
+			break;
+		}
+
+		dev_dbg(info->device, "chip %p => page shift %d\n",
+			chip, chip->page_shift);
 
 		/* change the behaviour depending on whether we are using
 		 * the large or small page nand device */
+		if (chip->page_shift > 10) {
+			chip->ecc.size	    = 256;
+			chip->ecc.bytes	    = 3;
+		} else {
+			chip->ecc.size	    = 512;
+			chip->ecc.bytes	    = 3;
+			mtd_set_ooblayout(nand_to_mtd(chip), &s3c2410_ooblayout_ops);
+		}
 
-	if (chip->page_shift > 10) {
-		chip->ecc.size	    = 256;
-		chip->ecc.bytes	    = 3;
-	} else {
-		chip->ecc.size	    = 512;
-		chip->ecc.bytes	    = 3;
-		mtd_set_ooblayout(nand_to_mtd(chip), &s3c2410_ooblayout_ops);
+		dev_info(info->device, "hardware ECC\n");
+		break;
+
+	default:
+		dev_err(info->device, "invalid ECC mode!\n");
+		return -EINVAL;
 	}
+
+	return 0;
 }
 
 /* s3c24xx_nand_probe
@@ -1046,7 +1045,9 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 						 NULL);
 
 		if (nmtd->scan_res == 0) {
-			s3c2410_nand_update_chip(info, nmtd);
+			err = s3c2410_nand_update_chip(info, nmtd);
+			if (err < 0)
+				goto exit_error;
 			nand_scan_tail(mtd);
 			s3c2410_nand_add_partition(info, nmtd, sets);
 		}
diff --git a/include/linux/platform_data/mtd-nand-s3c2410.h b/include/linux/platform_data/mtd-nand-s3c2410.h
index c55e42ee57fa..729af13d1773 100644
--- a/include/linux/platform_data/mtd-nand-s3c2410.h
+++ b/include/linux/platform_data/mtd-nand-s3c2410.h
@@ -12,9 +12,10 @@
 #ifndef __MTD_NAND_S3C2410_H
 #define __MTD_NAND_S3C2410_H
 
+#include <linux/mtd/nand.h>
+
 /**
  * struct s3c2410_nand_set - define a set of one or more nand chips
- * @disable_ecc:	Entirely disable ECC - Dangerous
  * @flash_bbt: 		Openmoko u-boot can create a Bad Block Table
  *			Setting this flag will allow the kernel to
  *			look for it at boot time and also skip the NAND
@@ -31,7 +32,6 @@
  * a warning at boot time.
  */
 struct s3c2410_nand_set {
-	unsigned int		disable_ecc:1;
 	unsigned int		flash_bbt:1;
 
 	unsigned int		options;
@@ -51,6 +51,8 @@ struct s3c2410_platform_nand {
 
 	unsigned int	ignore_unset_ecc:1;
 
+	nand_ecc_modes_t	ecc_mode;
+
 	int			nr_sets;
 	struct s3c2410_nand_set *sets;
 
-- 
1.9.1



From sergio.prado at e-labworks.com  Thu Oct 20 14:42:46 2016
From: sergio.prado at e-labworks.com (Sergio Prado)
Date: Thu, 20 Oct 2016 19:42:46 -0200
Subject: [PATCH v3 3/3] mtd: s3c2410: parse the device configuration from OF
 node
In-Reply-To: <1476999766-32526-1-git-send-email-sergio.prado@e-labworks.com>
References: <1476999766-32526-1-git-send-email-sergio.prado@e-labworks.com>
Message-ID: <1476999766-32526-4-git-send-email-sergio.prado@e-labworks.com>

Allows configuring Samsung's s3c2410 memory controller using a
devicetree.

Signed-off-by: Sergio Prado <sergio.prado at e-labworks.com>
---
 drivers/mtd/nand/s3c2410.c                     | 158 ++++++++++++++++++++++---
 include/linux/platform_data/mtd-nand-s3c2410.h |   1 +
 2 files changed, 143 insertions(+), 16 deletions(-)

diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index 371db0d48135..ec170be881bc 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -39,6 +39,8 @@
 #include <linux/slab.h>
 #include <linux/clk.h>
 #include <linux/cpufreq.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
@@ -185,6 +187,22 @@ struct s3c2410_nand_info {
 #endif
 };
 
+struct s3c24XX_nand_devtype_data {
+	enum s3c_cpu_type type;
+};
+
+static const struct s3c24XX_nand_devtype_data s3c2410_nand_devtype_data = {
+	.type = TYPE_S3C2410,
+};
+
+static const struct s3c24XX_nand_devtype_data s3c2412_nand_devtype_data = {
+	.type = TYPE_S3C2412,
+};
+
+static const struct s3c24XX_nand_devtype_data s3c2440_nand_devtype_data = {
+	.type = TYPE_S3C2440,
+};
+
 /* conversion functions */
 
 static struct s3c2410_nand_mtd *s3c2410_nand_mtd_toours(struct mtd_info *mtd)
@@ -794,6 +812,30 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
 	return -ENODEV;
 }
 
+static int s3c2410_nand_setup_data_interface(struct mtd_info *mtd,
+					     const struct nand_data_interface *conf,
+					     bool check_only)
+{
+	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+	struct s3c2410_platform_nand *pdata = info->platform;
+	const struct nand_sdr_timings *timings;
+	int tacls;
+
+	timings = nand_get_sdr_timings(conf);
+	if (IS_ERR(timings))
+		return -ENOTSUPP;
+
+	tacls = timings->tCLS_min - timings->tWP_min;
+	if (tacls < 0)
+		tacls = 0;
+
+	pdata->tacls  = DIV_ROUND_UP(tacls, 1000);
+	pdata->twrph0 = DIV_ROUND_UP(timings->tWP_min, 1000);
+	pdata->twrph1 = DIV_ROUND_UP(timings->tCLH_min, 1000);
+
+	return 0;
+}
+
 /**
  * s3c2410_nand_init_chip - initialise a single instance of an chip
  * @info: The base NAND controller the chip is on.
@@ -808,9 +850,12 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
 				   struct s3c2410_nand_mtd *nmtd,
 				   struct s3c2410_nand_set *set)
 {
+	struct device_node *np = info->device->of_node;
 	struct nand_chip *chip = &nmtd->chip;
 	void __iomem *regs = info->regs;
 
+	nand_set_flash_node(chip, set->of_node);
+
 	chip->write_buf    = s3c2410_nand_write_buf;
 	chip->read_buf     = s3c2410_nand_read_buf;
 	chip->select_chip  = s3c2410_nand_select_chip;
@@ -819,6 +864,13 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
 	chip->options	   = set->options;
 	chip->controller   = &info->controller;
 
+	/*
+	 * let's keep behavior unchanged for legacy boards booting via pdata and
+	 * auto-detect timings only when booting with a device tree.
+	 */
+	if (np)
+		chip->setup_data_interface = s3c2410_nand_setup_data_interface;
+
 	switch (info->cpu_type) {
 	case TYPE_S3C2410:
 		chip->IO_ADDR_W = regs + S3C2410_NFDATA;
@@ -859,12 +911,9 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
 	chip->ecc.mode = info->platform->ecc_mode;
 
 	/* If you use u-boot BBT creation code, specifying this flag will
-	 * let the kernel fish out the BBT from the NAND, and also skip the
-	 * full NAND scan that can take 1/2s or so. Little things... */
-	if (set->flash_bbt) {
+	 * let the kernel fish out the BBT from the NAND */
+	if (set->flash_bbt)
 		chip->bbt_options |= NAND_BBT_USE_FLASH;
-		chip->options |= NAND_SKIP_BBTSCAN;
-	}
 }
 
 /**
@@ -943,6 +992,77 @@ static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
 		return -EINVAL;
 	}
 
+	if (chip->bbt_options & NAND_BBT_USE_FLASH)
+		chip->options |= NAND_SKIP_BBTSCAN;
+
+	return 0;
+}
+
+static const struct of_device_id s3c24xx_nand_dt_ids[] = {
+	{
+		.compatible = "samsung,s3c2410-nand",
+		.data = &s3c2410_nand_devtype_data,
+	}, {
+		.compatible = "samsung,s3c2412-nand", /* also compatible with s3c6400 */
+		.data = &s3c2412_nand_devtype_data,
+	}, {
+		.compatible = "samsung,s3c2440-nand",
+		.data = &s3c2440_nand_devtype_data,
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, s3c24xx_nand_dt_ids);
+
+static int s3c24xx_nand_probe_dt(struct platform_device *pdev)
+{
+	const struct s3c24XX_nand_devtype_data *devtype_data;
+	struct s3c2410_platform_nand *pdata;
+	struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
+	struct device_node *np = pdev->dev.of_node, *child;
+	struct s3c2410_nand_set *sets;
+
+	devtype_data = of_device_get_match_data(&pdev->dev);
+	if (!devtype_data)
+		return -ENODEV;
+
+	info->cpu_type = devtype_data->type;
+
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	pdev->dev.platform_data = pdata;
+
+	pdata->nr_sets = of_get_child_count(np);
+	if (!pdata->nr_sets)
+		return 0;
+
+	sets = devm_kzalloc(&pdev->dev, sizeof(*sets) * pdata->nr_sets, GFP_KERNEL);
+	if (!sets)
+		return -ENOMEM;
+
+	pdata->sets = sets;
+
+	for_each_available_child_of_node(np, child) {
+
+		sets->name = (char *)child->name;
+		sets->of_node = child;
+		sets->nr_chips = 1;
+
+		of_node_get(child);
+
+		sets++;
+	}
+
+	return 0;
+}
+
+static int s3c24xx_nand_probe_pdata(struct platform_device *pdev)
+{
+	struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
+
+	info->cpu_type = platform_get_device_id(pdev)->driver_data;
+
 	return 0;
 }
 
@@ -955,8 +1075,7 @@ static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
 */
 static int s3c24xx_nand_probe(struct platform_device *pdev)
 {
-	struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
-	enum s3c_cpu_type cpu_type;
+	struct s3c2410_platform_nand *plat;
 	struct s3c2410_nand_info *info;
 	struct s3c2410_nand_mtd *nmtd;
 	struct s3c2410_nand_set *sets;
@@ -966,8 +1085,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 	int nr_sets;
 	int setno;
 
-	cpu_type = platform_get_device_id(pdev)->driver_data;
-
 	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
 	if (info == NULL) {
 		err = -ENOMEM;
@@ -989,6 +1106,16 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 
 	s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
 
+	if (pdev->dev.of_node)
+		err = s3c24xx_nand_probe_dt(pdev);
+	else
+		err = s3c24xx_nand_probe_pdata(pdev);
+
+	if (err)
+		goto exit_error;
+
+	plat = to_nand_plat(pdev);
+
 	/* allocate and map the resource */
 
 	/* currently we assume we have the one resource */
@@ -997,7 +1124,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 
 	info->device	= &pdev->dev;
 	info->platform	= plat;
-	info->cpu_type	= cpu_type;
 
 	info->regs = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(info->regs)) {
@@ -1007,12 +1133,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 
 	dev_dbg(&pdev->dev, "mapped registers at %p\n", info->regs);
 
-	/* initialise the hardware */
-
-	err = s3c2410_nand_inithw(info);
-	if (err != 0)
-		goto exit_error;
-
 	sets = (plat != NULL) ? plat->sets : NULL;
 	nr_sets = (plat != NULL) ? plat->nr_sets : 1;
 
@@ -1056,6 +1176,11 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 			sets++;
 	}
 
+	/* initialise the hardware */
+	err = s3c2410_nand_inithw(info);
+	if (err != 0)
+		goto exit_error;
+
 	err = s3c2410_nand_cpufreq_register(info);
 	if (err < 0) {
 		dev_err(&pdev->dev, "failed to init cpufreq support\n");
@@ -1156,6 +1281,7 @@ static int s3c24xx_nand_resume(struct platform_device *dev)
 	.id_table	= s3c24xx_driver_ids,
 	.driver		= {
 		.name	= "s3c24xx-nand",
+		.of_match_table = s3c24xx_nand_dt_ids,
 	},
 };
 
diff --git a/include/linux/platform_data/mtd-nand-s3c2410.h b/include/linux/platform_data/mtd-nand-s3c2410.h
index 729af13d1773..f01659026b26 100644
--- a/include/linux/platform_data/mtd-nand-s3c2410.h
+++ b/include/linux/platform_data/mtd-nand-s3c2410.h
@@ -40,6 +40,7 @@ struct s3c2410_nand_set {
 	char			*name;
 	int			*nr_map;
 	struct mtd_partition	*partitions;
+	struct device_node	*of_node;
 };
 
 struct s3c2410_platform_nand {
-- 
1.9.1



From sergio.prado at e-labworks.com  Thu Oct 20 14:42:45 2016
From: sergio.prado at e-labworks.com (Sergio Prado)
Date: Thu, 20 Oct 2016 19:42:45 -0200
Subject: [PATCH v3 2/3] dt-bindings: mtd: add DT binding for s3c2410 flash
 controller
In-Reply-To: <1476999766-32526-1-git-send-email-sergio.prado@e-labworks.com>
References: <1476999766-32526-1-git-send-email-sergio.prado@e-labworks.com>
Message-ID: <1476999766-32526-3-git-send-email-sergio.prado@e-labworks.com>

Adds the device tree bindings description for Samsung S3C2410 and
compatible NAND flash controller.

Signed-off-by: Sergio Prado <sergio.prado at e-labworks.com>
---
 .../devicetree/bindings/mtd/samsung-s3c2410.txt    | 56 ++++++++++++++++++++++
 1 file changed, 56 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt

diff --git a/Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt b/Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt
new file mode 100644
index 000000000000..0040eb8895e0
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt
@@ -0,0 +1,56 @@
+* Samsung S3C2410 and compatible NAND flash controller
+
+Required properties:
+- compatible : The possible values are:
+	"samsung,s3c2410-nand"
+	"samsung,s3c2412-nand"
+	"samsung,s3c2440-nand"
+- reg : register's location and length.
+- #address-cells, #size-cells : see nand.txt
+- clocks : phandle to the nand controller clock
+- clock-names : must contain "nand"
+
+Optional child nodes:
+Child nodes representing the available nand chips.
+
+Optional child properties:
+- nand-ecc-mode : see nand.txt
+- nand-on-flash-bbt : see nand.txt
+
+Each child device node may optionally contain a 'partitions' sub-node,
+which further contains sub-nodes describing the flash partition mapping.
+See partition.txt for more detail.
+
+Example:
+
+nand-controller at 4e000000 {
+	compatible = "samsung,s3c2440-nand";
+	reg = <0x4e000000 0x40>;
+
+	#address-cells = <1>;
+        #size-cells = <0>;
+
+	clocks = <&clocks HCLK_NAND>;
+	clock-names = "nand";
+
+	nand {
+		nand-ecc-mode = "soft";
+		nand-on-flash-bbt;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition at 0 {
+				label = "u-boot";
+				reg = <0 0x040000>;
+			};
+
+			partition at 40000 {
+				label = "kernel";
+				reg = <0x040000 0x500000>;
+			};
+		};
+	};
+};
-- 
1.9.1



From linus.walleij at linaro.org  Thu Oct 20 15:24:42 2016
From: linus.walleij at linaro.org (Linus Walleij)
Date: Fri, 21 Oct 2016 00:24:42 +0200
Subject: [PATCH 07/10] gpio: ptxpmb-cpld: Add support for PTXPMB CPLD's
 GPIO
In-Reply-To: <1475853451-22121-8-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
 <1475853451-22121-8-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <CACRpkdaYVgwBS_QR+S4CafP0jFrn8jw-Ewc_m8LDXUK5sMMwTw@mail.gmail.com>

On Fri, Oct 7, 2016 at 5:17 PM, Pantelis Antoniou
<pantelis.antoniou at konsulko.com> wrote:

> From: Guenter Roeck <groeck at juniper.net>
>
> Support the GPIO block which is located in PTXPMB CPLDs
> on relevant Juniper platforms.
>
> Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
> Signed-off-by: Guenter Roeck <groeck at juniper.net>
> Signed-off-by: Rajat Jain <rajatjain at juniper.net>
> [Ported from Juniper kernel]
> Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>

Nice with preserved credits.

> +config GPIO_PTXPMB_CPLD
> +       tristate "PTXPMB CPLD GPIO"
> +       depends on MFD_JUNIPER_CPLD
> +       default y if MFD_JUNIPER_CPLD

Can't you do something like

default MFD_JUNIPER_CPLD

so it will become a module if the MFD driver is a module
and compiled-in if the MFD driver is compiled in?

Please check if that works.

> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/pci.h>
> +#include <linux/gpio.h>

Just:
#include <linux/gpio/driver.h>

Should work.

> +#include <linux/errno.h>
> +#include <linux/of_device.h>
> +#include <linux/of_platform.h>
> +#include <linux/of_gpio.h>

Strange that a PCI driver need so much OF stuff.
Really? But OK, do you really use all these includes?

> +#include <linux/io.h>
> +#include <linux/module.h>
> +
> +#include <linux/mfd/ptxpmb_cpld.h>

Is this include deserving a separate whitespace in
front of it?

> +static u8 *ptxpmb_cpld_gpio_get_addr(struct pmb_boot_cpld *cpld,
> +                                    unsigned int nr)
> +{
> +       if (nr < 8)                     /* 0..7: reset                  */
> +               return &cpld->reset;
> +       else if (nr < 16)               /* 8..15: control               */
> +               return &cpld->control;
> +       else if (nr < 24)               /* 16..23: gpio1                */
> +               return &cpld->gpio_1;
> +       else if (nr < 32)               /* 24..31: gpio2                */
> +               return &cpld->gpio_2;
> +       else if (nr < 40)               /* 32..39: gp_reset1            */
> +               return &cpld->gp_reset1;
> +       return &cpld->thermal_status;   /* 40..41: thermal status       */
> +}

Reset, control, gp_reset and *especially* thermal status
does not seem to be GPIO at all. Rather these seem to be
special purpose lines rather than general purpose.

Can you explain why the GPIO driver should even poke at them?

It seems other subdrivers should use these registers...

> +static void ptxpmb_cpld_gpio_set(struct gpio_chip *gpio, unsigned int nr,
> +                                int val)
> +{
> +       u32 reg;
> +       u8 bit = 1 << (nr & 7);

Use this:

#include <linux/bitops.h>

Then inline BIT() instead of making a local variable like this.
See below...

> +       struct ptxpmb_cpld_gpio *chip =
> +         container_of(gpio, struct ptxpmb_cpld_gpio, gpio);

Use:
struct ptxpmb_cpld_gpio *cpldg = gpiochip_get_data(gpio);

Please don't name it "chip" it is confusing with the gpio chip
proper.

> +       u8 *addr = ptxpmb_cpld_gpio_get_addr(chip->base, nr);
> +
> +       mutex_lock(&chip->lock);
> +       reg = ioread8(addr);
> +       if (val)
> +               reg |= bit;
> +       else
> +               reg &= ~bit;

So instead:
if (val)
    reg |= BIT(nr);
else
    reg &= ~BIT(nr);

> +static int ptxpmb_cpld_gpio_get(struct gpio_chip *gpio, unsigned int nr)
> +{
> +       struct ptxpmb_cpld_gpio *chip = container_of(gpio,
> +                                                    struct ptxpmb_cpld_gpio,
> +                                                    gpio);

Same comment as before.

> +       u8 *addr = ptxpmb_cpld_gpio_get_addr(chip->base, nr);
> +       u8 bit = 1 << (nr & 7);
> +
> +       return !!(ioread8(addr) & bit);

Same comment on using BIT()

> +static int ptxpmb_cpld_gpio_direction_output(struct gpio_chip *gpio,
> +                                            unsigned int nr, int val)
> +{
> +       return 0;
> +}
> +
> +static int ptxpmb_cpld_gpio_direction_input(struct gpio_chip *gpio,
> +                                           unsigned int nr)
> +{
> +       return 0;
> +}

Oh yeah? Can you explain how this works electronically?

If these lines are open drain you should also implement
.set_single_ended().

> +static void ptxpmb_cpld_gpio_setup(struct ptxpmb_cpld_gpio *chip)

Again rename from chip.

> +static int ptxpmb_cpld_gpio_probe(struct platform_device *pdev)
> +{
> +       int ret;
> +       struct ptxpmb_cpld_gpio *chip;

Rename from chip.

> +       struct resource *res;
> +       struct device *dev = &pdev->dev;
> +
> +       chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
> +       if (chip == NULL)
> +               return -ENOMEM;
> +
> +       chip->dev = dev;
> +       platform_set_drvdata(pdev, chip);
> +
> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       if (!res)
> +               return -ENODEV;
> +
> +       chip->base = devm_ioremap_nocache(dev, res->start, resource_size(res));
> +       if (!chip->base)
> +               return -ENOMEM;
> +
> +       mutex_init(&chip->lock);
> +       ptxpmb_cpld_gpio_setup(chip);
> +       ret = gpiochip_add(&chip->gpio);

Use devm_gpiochip_add_data() so you can use gpiochip_get_data() in the
callbacks and get rid of container_of().

> +       if (ret) {
> +               dev_err(dev, "CPLD gpio: Failed to register GPIO\n");
> +               return ret;
> +       }
> +       return 0;
> +}
> +
> +static int ptxpmb_cpld_gpio_remove(struct platform_device *pdev)
> +{
> +       struct ptxpmb_cpld_gpio *chip = platform_get_drvdata(pdev);
> +
> +       gpiochip_remove(&chip->gpio);
> +
> +       return 0;
> +}

If you use devm_gpiochip_add_data() I don't think this function is
even needed.

Yours,
Linus Walleij


From linus.walleij at linaro.org  Thu Oct 20 16:06:40 2016
From: linus.walleij at linaro.org (Linus Walleij)
Date: Fri, 21 Oct 2016 01:06:40 +0200
Subject: [PATCH 05/10] gpio: Introduce SAM gpio driver
In-Reply-To: <1475853518-22264-6-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853518-22264-1-git-send-email-pantelis.antoniou@konsulko.com>
 <1475853518-22264-6-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <CACRpkdZa9OdV3j7X4ptczhEOCBZfd=KKbp3jizQYSQP-xoTmCg@mail.gmail.com>

n Fri, Oct 7, 2016 at 5:18 PM, Pantelis Antoniou
<pantelis.antoniou at konsulko.com> wrote:

> From: Guenter Roeck <groeck at juniper.net>
>
> The SAM GPIO IP block is present in the Juniper PTX series
> of routers as part of the SAM FPGA.
>
> Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
> Signed-off-by: Guenter Roeck <groeck at juniper.net>
> Signed-off-by: Rajat Jain <rajatjain at juniper.net>
> [Ported from Juniper kernel]
> Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>

First copy/paste my other review comments on the previous driver
I reviewed, this seems to have pretty much all the same issues.

> +config GPIO_SAM
> +       tristate "SAM FPGA GPIO"
> +       depends on MFD_JUNIPER_SAM
> +       default y if MFD_JUNIPER_SAM

I suspect this should use
select GPIOLIB_IRQCHIP

> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/pci.h>
> +#include <linux/gpio.h>

<linux/gpio/driver.h>

> +#include <linux/interrupt.h>
> +#include <linux/irqdomain.h>

Not needed with GPIOLIB_IRQCHIP

> +#include <linux/errno.h>
> +#include <linux/of_device.h>
> +#include <linux/of_platform.h>
> +#include <linux/of_gpio.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/sched.h>

Why?

> +#include <linux/mfd/sam.h>
> +
> +/* gpio status/configuration */
> +#define SAM_GPIO_NEG_EDGE      (1 << 8)
> +#define SAM_GPIO_NEG_EDGE_EN   (1 << 7)
> +#define SAM_GPIO_POS_EDGE      (1 << 6)
> +#define SAM_GPIO_POS_EDGE_EN   (1 << 5)

Interrupt triggers I suppose.

> +#define SAM_GPIO_BLINK         (1 << 4)

Cool, we don't support that in gpiolib as of now.
Maybe we should.

> +#define SAM_GPIO_OUT           (1 << 3)
> +#define SAM_GPIO_OUT_TS                (1 << 2)

OUT_TS ... what does TS mean here?

> +#define SAM_GPIO_DEBOUNCE_EN   (1 << 1)
> +#define SAM_GPIO_IN            (1 << 0)
> +
> +#define SAM_GPIO_BASE          0x1000

Base into what, and why is this not coming from PCI
or the device tree?

> +#define SAM_MAX_NGPIO          512

Why do we need to know this and what does it really mean?
That is the max number the GPIO subsystem can handle by
the way.

> +#define SAM_GPIO_ADDR(addr, nr)        ((addr) + SAM_GPIO_BASE + (nr) * sizeof(u32))

Why can't we just offset the address earlier, ah well it's OK.

> +struct sam_gpio_irq_group {
> +       int start;              /* 1st gpio pin */
> +       int count;              /* # of pins in group */
> +       int num_enabled;        /* # of enabled interrupts */
> +};
> +
> +/**
> + * struct sam_gpio - GPIO private data structure.
> + * @base:                      PCI base address of Memory mapped I/O register.
> + * @dev:                       Pointer to device structure.
> + * @gpio:                      Data for GPIO infrastructure.
> + * @gpio_base:                 1st gpio pin
> + * @gpio_count:                        # of gpio pins
> + * @irq_lock:                  Lock used by interrupt subsystem
> + * @domain:                    Pointer to interrupt domain
> + * @irq:                       Interrupt # from parent
> + * @irq_high:                  Second interrupt # from parent
> + *                             (currently unused)
> + * @irq_group:                 Interrupt group descriptions
> + *                             (one group per interrupt bit)
> + * @irq_type:                  The interrupt type for each gpio pin
> + */

Why do you need to keep all of this around? Is is all really
used? gpio_base makes me nervous we generally use dynamic
allocation of GPIO numbers these days.

> +struct sam_gpio {
> +       void __iomem *base;
> +       struct device *dev;
> +       struct gpio_chip gpio;
> +       int gpio_base;
> +       int gpio_count;
> +       struct mutex irq_lock;
> +       struct irq_domain *domain;
> +       int irq;
> +       int irq_high;
> +       struct sam_gpio_irq_group irq_group[18];
> +       u8 irq_type[SAM_MAX_NGPIO];
> +       struct sam_platform_data *pdata;
> +       const char **names;
> +       u32 *export_flags;
> +};
> +#define to_sam(chip)   container_of((chip), struct sam_gpio, gpio)

Instead of this use gpiochip_get_data(). Applies everywhere.

> +static void sam_gpio_bitop(struct sam_gpio *sam, unsigned int nr,
> +                          u32 bit, bool set)
> +{
> +       u32 reg;
> +
> +       reg = ioread32(SAM_GPIO_ADDR(sam->base, nr));
> +       if (set)
> +               reg |= bit;
> +       else
> +               reg &= ~bit;
> +       iowrite32(reg, SAM_GPIO_ADDR(sam->base, nr));
> +       ioread32(SAM_GPIO_ADDR(sam->base, nr));
> +}

Does that rally need a helper function?

Use BIT() and inline like I explained in the previous patch.

> +static void sam_gpio_setup(struct sam_gpio *sam)
> +{
> +       struct gpio_chip *chip = &sam->gpio;
> +
> +       chip->parent = sam->dev;
> +       chip->label = dev_name(sam->dev);
> +       chip->owner = THIS_MODULE;
> +       chip->direction_input = sam_gpio_direction_input;
> +       chip->get = sam_gpio_get;
> +       chip->direction_output = sam_gpio_direction_output;

Implement also chip->get_direction

> +       chip->set = sam_gpio_set;
> +       chip->set_debounce = sam_gpio_debounce;
> +       chip->dbg_show = NULL;
> +       chip->base = sam->gpio_base;

Oh no, why. Use -1 please and let gpiolib decide...

> +       chip->ngpio = sam->gpio_count;
> +#ifdef CONFIG_OF_GPIO
> +       chip->of_node = sam->dev->of_node;
> +#endif

I doubt this #ifdef actually. If the driver needs CONFIG_OF_GPIO to
work it should just depend on it in Kconfig.

> +static int sam_of_get_exports(struct device *dev, struct sam_gpio *sam)
> +{
> +       struct device_node *child, *exports;
> +       int err = 0;
> +
> +       if (dev->of_node == NULL)
> +               return 0;       /* No FDT node, we are done */
> +
> +       exports = of_get_child_by_name(dev->of_node, "gpio-exports");
> +       if (exports == NULL)
> +               return 0;       /* No exports, we are done */
> +
> +       if (of_get_child_count(exports) == 0)
> +               return 0;       /* No children, we are done */
> +
> +       sam->names = devm_kzalloc(dev, sizeof(char *) * sam->gpio_count,
> +                                 GFP_KERNEL);
> +       if (sam->names == NULL) {
> +               err = -ENOMEM;
> +               goto error;
> +       }
> +       sam->export_flags =
> +               devm_kzalloc(dev, sizeof(u32) * sam->gpio_count, GFP_KERNEL);
> +       if (sam->export_flags == NULL) {
> +               err = -ENOMEM;
> +               goto error;
> +       }
> +       for_each_child_of_node(exports, child) {
> +               const char *label;
> +               u32 pin, flags;
> +
> +               label = of_get_property(child, "label", NULL) ? : child->name;
> +               err = of_property_read_u32_index(child, "pin", 0, &pin);
> +               if (err)
> +                       break;
> +               if (pin >= sam->gpio_count) {
> +                       err = -EINVAL;
> +                       break;
> +               }
> +               err = of_property_read_u32_index(child, "pin", 1, &flags);
> +               if (err)
> +                       break;
> +               /*
> +                * flags:
> +                * GPIOF_DIR_IN                 bit 0=1
> +                * GPIOF_DIR_OUT                bit 0=0
> +                *      GPIOF_INIT_HIGH         bit 1=1
> +                * GPIOF_ACTIVE_LOW             bit 2=1
> +                * GPIOF_OPEN_DRAIN             bit 3=1
> +                * GPIOF_OPEN_SOURCE            bit 4=1
> +                * GPIOF_EXPORT                 bit 5=1
> +                * GPIOF_EXPORT_CHANGEABLE      bit 6=1
> +                */
> +               sam->names[pin] = label;
> +               sam->export_flags[pin] = flags;
> +       }
> +error:
> +       of_node_put(exports);
> +       return err;
> +}

What? NAK never in my life. This looks like an old hack to
export stuff to userspace. We don't do that. The kernel supports
gpio-line-names to name lines in the device tree, and you can use
the new chardev ABI to access it from userspace, sysfs is dead.

Delete this function entirely.

> +static int sam_gpio_of_init(struct device *dev, struct sam_gpio *sam)
> +{
> +       int err;
> +       u32 val;
> +       const u32 *igroup;
> +       u32 group, start, count;
> +       int i, iglen, ngpio;
> +
> +       if (of_have_populated_dt() && !dev->of_node) {
> +               dev_err(dev, "No device node\n");
> +               return -ENODEV;
> +       }

So obviously this driver Kconfig should depend on OF_GPIO.

> +
> +       err = of_property_read_u32(dev->of_node, "gpio-base", &val);
> +       if (err)
> +               val = -1;
> +       sam->gpio_base = val;

NAK, No Linux bases in the device tree. Only use -1.

> +       err = of_property_read_u32(dev->of_node, "gpio-count", &val);
> +       if (!err) {
> +               if (val > SAM_MAX_NGPIO)
> +                       val = SAM_MAX_NGPIO;
> +               sam->gpio_count = val;
> +       }

As described in the generic bindings, use "ngpios" for this if you need it.

> +       igroup = of_get_property(dev->of_node, "gpio-interrupts", &iglen);

NAK on that binding.

> +       if (igroup) {
> +               iglen /= sizeof(u32);
> +               if (iglen < 3 || iglen % 3)
> +                       return -EINVAL;
> +               iglen /= 3;
> +               for (i = 0; i < iglen; i++) {
> +                       group = be32_to_cpu(igroup[i * 3]);
> +                       if (group >= ARRAY_SIZE(sam->irq_group))
> +                               return -EINVAL;
> +                       start = be32_to_cpu(igroup[i * 3 + 1]);
> +                       count = be32_to_cpu(igroup[i * 3 + 2]);
> +                       if (start >= sam->gpio_count || count == 0 ||
> +                           start + count > sam->gpio_count)
> +                               return -EINVAL;
> +                       sam->irq_group[group].start = start;
> +                       sam->irq_group[group].count = count;
> +               }
> +       }

Do not invent custom interrupt bindings like this. Use the
standard device tree mechanism to resolve IRQs from the parent
controller. Maybe you also need to use hierarchical irqdomain
in Linux.

> +static int sam_gpio_pin_to_irq_bit(struct sam_gpio *sam, int pin)
> +{
> +       int bit;
> +
> +       for (bit = 0; bit < ARRAY_SIZE(sam->irq_group); bit++) {
> +               struct sam_gpio_irq_group *irq_group = &sam->irq_group[bit];
> +
> +               if (irq_group->count &&
> +                   pin >= irq_group->start &&
> +                   pin <= irq_group->start + irq_group->count)
> +                       return bit;
> +       }
> +       return -EINVAL;
> +}
> +
> +static bool sam_gpio_irq_handle_group(struct sam_gpio *sam,
> +                                     struct sam_gpio_irq_group *irq_group)
> +{
> +       unsigned int virq = 0;
> +       bool handled = false;
> +       bool repeat;
> +       int i;
> +
> +       /* no irq_group for the interrupt bit */
> +       if (!irq_group->count)
> +               return false;
> +
> +       WARN_ON(irq_group->num_enabled == 0);
> +       do {
> +               repeat = false;
> +               for (i = 0; i < irq_group->count; i++) {
> +                       int pin = irq_group->start + i;
> +                       bool low, high;
> +                       u32 regval;
> +                       u8 type;
> +
> +                       regval = ioread32(SAM_GPIO_ADDR(sam->base, pin));
> +                       /*
> +                        * write back status to clear POS_EDGE and NEG_EDGE
> +                        * status for this GPIO pin (status bits are
> +                        * clear-on-one). This is necessary to clear the
> +                        * high level interrupt status.
> +                        * Also consider the interrupt to be handled in that
> +                        * case, even if there is no taker.
> +                        */
> +                       if (regval & (SAM_GPIO_POS_EDGE | SAM_GPIO_NEG_EDGE)) {
> +                               iowrite32(regval,
> +                                         SAM_GPIO_ADDR(sam->base, pin));
> +                               ioread32(SAM_GPIO_ADDR(sam->base, pin));
> +                               handled = true;
> +                       }
> +
> +                       /*
> +                        * Check if the pin changed its state.
> +                        * If it did, and if the expected condition applies,
> +                        * generate a virtual interrupt.
> +                        * A pin can only generate an interrupt if
> +                        * - interrupts are enabled for it
> +                        * - it is configured as input
> +                        */
> +
> +                       if (!sam->irq_type[pin])
> +                               continue;
> +                       if (!(regval & SAM_GPIO_OUT_TS))
> +                               continue;
> +
> +                       high = regval & (SAM_GPIO_IN | SAM_GPIO_POS_EDGE);
> +                       low = !(regval & SAM_GPIO_IN) ||
> +                               (regval & SAM_GPIO_NEG_EDGE);
> +                       type = sam->irq_type[pin];
> +                       if (((type & IRQ_TYPE_EDGE_RISING) &&
> +                            (regval & SAM_GPIO_POS_EDGE)) ||
> +                           ((type & IRQ_TYPE_EDGE_FALLING) &&
> +                            (regval & SAM_GPIO_NEG_EDGE)) ||
> +                           ((type & IRQ_TYPE_LEVEL_LOW) && low) ||
> +                           ((type & IRQ_TYPE_LEVEL_HIGH) && high)) {


This if() clause does not look sane, you have to see that.
If you think this is proper then explain with detailed comments
what is going on.

> +                               virq = irq_find_mapping(sam->domain, pin);
> +                               handle_nested_irq(virq);
> +                               if (type & (IRQ_TYPE_LEVEL_LOW
> +                                           | IRQ_TYPE_LEVEL_HIGH))
> +                                       repeat = true;
> +                       }
> +               }
> +               schedule();

Why? Voluntary preemption? Just use a threaded interrupt handler
instead.

> +       } while (repeat);
> +
> +       return handled;
> +}
> +
> +static irqreturn_t sam_gpio_irq_handler(int irq, void *data)
> +{
> +       struct sam_gpio *sam = data;
> +       struct sam_platform_data *pdata = sam->pdata;
> +       irqreturn_t ret = IRQ_NONE;
> +       bool handled;
> +       u32 status;
> +
> +       do {
> +               handled = false;
> +               status = pdata->irq_status(sam->dev->parent, SAM_IRQ_GPIO,
> +                                          sam->irq);
> +               pdata->irq_status_clear(sam->dev->parent, SAM_IRQ_GPIO,
> +                                       sam->irq, status);
> +               while (status) {
> +                       unsigned int bit;
> +
> +                       bit = __ffs(status);
> +                       status &= ~(1 << bit);
> +                       handled =
> +                         sam_gpio_irq_handle_group(sam, &sam->irq_group[bit]);
> +                       if (handled)
> +                               ret = IRQ_HANDLED;
> +               }
> +       } while (handled);

This handled business looks fragile. But OK.

It is a simple IRQ handler, this driver should definately use
GPIOLIB_IRQCHIP. Please look at other drivers doing that
for inspiration. It is also well described in
Documenation/gpio/driver.txt

> +static int sam_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
> +{
> +       struct sam_gpio *sam = to_sam(chip);
> +
> +       return irq_create_mapping(sam->domain, offset);
> +}

With GPIOLIB_IRQCHIP you do not need to implement .to_irq()

> +static void sam_irq_mask(struct irq_data *data)
> +{
> +       struct sam_gpio *sam = irq_data_get_irq_chip_data(data);
> +       struct sam_platform_data *pdata = sam->pdata;
> +       int bit = sam_gpio_pin_to_irq_bit(sam, data->hwirq);
> +
> +       if (bit < 0)
> +               return;
> +
> +       if (--sam->irq_group[bit].num_enabled <= 0) {
> +               pdata->disable_irq(sam->dev->parent, SAM_IRQ_GPIO, sam->irq,
> +                                  1 << bit);

Just BIT(bit)

> +static void sam_irq_unmask(struct irq_data *data)
> +{
> +       struct sam_gpio *sam = irq_data_get_irq_chip_data(data);
> +       struct sam_platform_data *pdata = sam->pdata;
> +       int bit = sam_gpio_pin_to_irq_bit(sam, data->hwirq);
> +
> +       if (bit < 0)
> +               return;

Do you expect this to happen a lot? Else just delete the check or print
an error message.

> +
> +       sam->irq_group[bit].num_enabled++;
> +       pdata->enable_irq(sam->dev->parent, SAM_IRQ_GPIO, sam->irq, 1 << bit);

Dito.

> +static int sam_irq_set_type(struct irq_data *data, unsigned int type)
> +{
> +       struct sam_gpio *sam = irq_data_get_irq_chip_data(data);
> +       int bit = sam_gpio_pin_to_irq_bit(sam, data->hwirq);
> +
> +       if (bit < 0)
> +               return bit;
> +
> +       sam->irq_type[data->hwirq] = type & 0x0f;


Why storing this and going to all that trouble?

> +       sam_gpio_bitop(sam, data->hwirq, SAM_GPIO_OUT_TS, true);
> +       sam_gpio_bitop(sam, data->hwirq, SAM_GPIO_DEBOUNCE_EN, type & 0x10);
> +       sam_gpio_bitop(sam, data->hwirq,
> +                      SAM_GPIO_POS_EDGE_EN | SAM_GPIO_POS_EDGE,
> +                      type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH));
> +       sam_gpio_bitop(sam, data->hwirq,
> +                      SAM_GPIO_NEG_EDGE_EN | SAM_GPIO_NEG_EDGE,
> +                      type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW));
> +
> +       return 0;
> +}

Just set up different handlers depending on edge. This likely simplifies your
IRQ handler code as well, as a special function (.irq_ack()) gets called for
edge IRQs.

Look how drivers/gpio/gpio-pl061.c does it.

> +static void sam_irq_bus_lock(struct irq_data *data)
> +{
> +       struct sam_gpio *sam = irq_data_get_irq_chip_data(data);
> +
> +       mutex_lock(&sam->irq_lock);
> +}
> +
> +static void sam_irq_bus_unlock(struct irq_data *data)
> +{
> +       struct sam_gpio *sam = irq_data_get_irq_chip_data(data);
> +
> +       /* Synchronize interrupts to chip */
> +
> +       mutex_unlock(&sam->irq_lock);
> +}

Aha OK if it's necessary then we need to do this.

> +static struct irq_chip sam_irq_chip = {
> +       .name = "gpio-sam",

Maybe this should have an instance number or something.
Just an idea no requirement.

> +       .irq_mask = sam_irq_mask,
> +       .irq_unmask = sam_irq_unmask,

So I think this needs .irq_ack() to solve the mess above in
the interrupt handler.

> +       .irq_set_type = sam_irq_set_type,
> +       .irq_bus_lock = sam_irq_bus_lock,
> +       .irq_bus_sync_unlock = sam_irq_bus_unlock,
> +};
> +
> +static int sam_gpio_irq_map(struct irq_domain *domain, unsigned int irq,
> +                           irq_hw_number_t hwirq)
> +{
> +       irq_set_chip_data(irq, domain->host_data);
> +       irq_set_chip(irq, &sam_irq_chip);
> +       irq_set_nested_thread(irq, true);
> +
> +       irq_set_noprobe(irq);
> +
> +       return 0;
> +}

This will not be needed if you use GPIOLIB_IRQCHIP

> +static const struct irq_domain_ops sam_gpio_irq_domain_ops = {
> +       .map = sam_gpio_irq_map,
> +       .xlate = irq_domain_xlate_twocell,
> +};

Nor this.

> +static int sam_gpio_irq_setup(struct device *dev, struct sam_gpio *sam)
> +{
> +       int ret;
> +
> +       sam->domain = irq_domain_add_linear(dev->of_node,
> +                                           sam->gpio_count,
> +                                           &sam_gpio_irq_domain_ops,
> +                                           sam);
> +       if (sam->domain == NULL)
> +               return -ENOMEM;

Nor this.

> +       ret = devm_request_threaded_irq(dev, sam->irq, NULL,
> +                                       sam_gpio_irq_handler,
> +                                       IRQF_ONESHOT,
> +                                       dev_name(dev), sam);
> +       if (ret)
> +               goto out_remove_domain;

Are you not setting .can_sleep on the gpiochip?

> +
> +       sam->gpio.to_irq = sam_gpio_to_irq;
> +
> +       if (!try_module_get(dev->parent->driver->owner)) {
> +               ret = -EINVAL;
> +               goto out_remove_domain;
> +       }

Why? Is that the MFD device? Isn't the device core
handling this?

> +static int sam_gpio_unexport(struct sam_gpio *sam)
> +{
> +       int i;
> +
> +       if (!sam->export_flags)
> +               return 0;
> +
> +       /* un-export all auto-exported pins */
> +       for (i = 0; i < sam->gpio_count; i++) {
> +               struct gpio_desc *desc = gpio_to_desc(sam->gpio.base + i);
> +
> +               if (desc == NULL)
> +                       continue;
> +
> +               if (sam->export_flags[i] & GPIOF_EXPORT)
> +                       gpiochip_free_own_desc(desc);
> +       }
> +       return 0;
> +}
> +
> +static int sam_gpio_export(struct sam_gpio *sam)
> +{
> +       int i, ret;
> +
> +       if (!sam->export_flags)
> +               return 0;
> +
> +       /* auto-export pins as requested */
> +
> +       for (i = 0; i < sam->gpio_count; i++) {
> +               u32 flags = sam->export_flags[i];
> +               struct gpio_desc *desc;
> +
> +               /* request and initialize exported pins */
> +               if (!(flags & GPIOF_EXPORT))
> +                       continue;
> +
> +               desc  = gpiochip_request_own_desc(&sam->gpio, i, "sam-export");
> +               if (IS_ERR(desc)) {
> +                       ret = PTR_ERR(desc);
> +                       goto error;
> +               }
> +               if (flags & GPIOF_DIR_IN) {
> +                       ret = gpiod_direction_input(desc);
> +                       if (ret)
> +                               goto error;
> +               } else {
> +                       ret = gpiod_direction_output(desc, flags &
> +                                                   (GPIOF_OUT_INIT_HIGH |
> +                                                    GPIOF_ACTIVE_LOW));
> +                       if (ret)
> +                               goto error;
> +               }
> +               ret = gpiod_export(desc, flags & GPIOF_EXPORT_CHANGEABLE);
> +
> +               if (ret)
> +                       goto error;
> +       }
> +       return 0;
> +
> +error:
> +       sam_gpio_unexport(sam);
> +       return ret;
> +}

Just delete this. Use the new chardev ABI to access GPIOs from
userspace as explained earlier.

> +static int sam_gpio_probe(struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct sam_gpio *sam;
> +       struct resource *res;
> +       int ret;
> +       struct sam_platform_data *pdata = dev_get_platdata(&pdev->dev);
> +
> +       sam = devm_kzalloc(dev, sizeof(*sam), GFP_KERNEL);
> +       if (sam == NULL)
> +               return -ENOMEM;

if (!sam)
  return -ENOMEM;

> +       sam->dev = dev;
> +       sam->pdata = pdata;
> +       platform_set_drvdata(pdev, sam);
> +
> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       if (!res)
> +               return -ENODEV;
> +
> +       sam->irq = platform_get_irq(pdev, 0);
> +       sam->irq_high = platform_get_irq(pdev, 1);
> +
> +       sam->base = devm_ioremap_nocache(dev, res->start, resource_size(res));
> +       if (!sam->base)
> +               return -ENOMEM;
> +
> +       mutex_init(&sam->irq_lock);
> +
> +       ret = sam_gpio_of_init(dev, sam);
> +       if (ret)
> +               return ret;
> +
> +       sam_gpio_setup(sam);
> +
> +       if (pdata && sam->irq >= 0 && of_find_property(dev->of_node,
> +                                             "interrupt-controller", NULL)) {
> +               ret = sam_gpio_irq_setup(dev, sam);
> +               if (ret < 0)
> +                       return ret;
> +       }

This is fair, but do it after adding the gpiochip and use GPIOLIB_IRQCHIP
accessors gpiochip_irqchip_add() and gpiochip_set_chained_irqchip().

Yours,
Linus Walleij


From linus.walleij at linaro.org  Fri Oct 21 01:39:43 2016
From: linus.walleij at linaro.org (Linus Walleij)
Date: Fri, 21 Oct 2016 10:39:43 +0200
Subject: [PATCH 3/4] gpio: ptxpmb-ext-cpld: Add driver for Juniper's
 PTXPMB extended CPLD
In-Reply-To: <1475853574-22339-4-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853574-22339-1-git-send-email-pantelis.antoniou@konsulko.com>
 <1475853574-22339-4-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <CACRpkdY681yE+zo51BSrBjvhFPQV3KkhM9QH600uiqLfP8G=fw@mail.gmail.com>

On Fri, Oct 7, 2016 at 5:19 PM, Pantelis Antoniou
<pantelis.antoniou at konsulko.com> wrote:

> From: Guenter Roeck <groeck at juniper.net>
>
> This IP block is present in the PTXPMB extended CPLD present on
> Junipers PTX series of routers and provides SIB connector status pins
> as GPIO pins for use with other drivers.
>
> Signed-off-by: Guenter Roeck <groeck at juniper.net>
> Signed-off-by: JawaharBalaji Thirumalaisamy <jawaharb at juniper.net>
> [Ported from Juniper kernel]
> Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>

This driver has pretty much the same issues as the two others
I reviewed yesterday. Please address the same comments
and repost and I will look at it again!

Yours,
Linus Walleij


From naga.sureshkumar.relli at xilinx.com  Fri Oct 21 02:21:03 2016
From: naga.sureshkumar.relli at xilinx.com (Naga Sureshkumar Relli)
Date: Fri, 21 Oct 2016 09:21:03 +0000
Subject: UBIFS with dma on 4.6 kernel is not working
Message-ID: <DA6901612C71B84D91459DE817C418AE26DF0F2B@XAP-PVEXMBX01.xlnx.xilinx.com>

Hi,

This is regarding UBIFS on 4.6 kernel.
We have tested UBIFS on our ZynqMP SOC QSPI Controller, the UBIFS is not working with dma on this kernel.
Controller driver: https://github.com/torvalds/linux/commits/master/drivers/spi/spi-zynqmp-gqspi.c
If I replace all vmalloc allocations in fs/ubifs/ to kmalloc then UBIFS with dma is working fine.
But whereas kernel before 4.6 without changing vmalloc to kmalloc, UBIFS is working fine with dma.
So is there any change in UBIFS in 4.6 kernel that to dma related?

May I know some info regarding this?
Why UBIFS on kernels before 4.6 is working with dma but not with 4.6?
Now a days, most of QSPI controllers have internal dmas.

Could you please provide some info regrading this dma issue?
We can change our controller driver to operate in IO mode (doesn't use dma) but performance wise it's not a preferred one.

Thanks,
Naga Sureshkumar Relli



From ville.michael.baillie at gmail.com  Fri Oct 21 02:26:05 2016
From: ville.michael.baillie at gmail.com (Ville Michael Baillie)
Date: Fri, 21 Oct 2016 10:26:05 +0100
Subject: [PATCH] mtd: nand: davinci: Fix unaligned 16-bit NAND read
Message-ID: <20161021092605.GA14609@gmail.com>

This patch fixes a rare bug when reading from 16-bit NAND flashes, by
not allowing 8-bit read accesses within nand_davinci_read_buf().

In certain situations, an non 16-bit aligned buffer is passed to
nand_davinci_read_buf(), which causes 8-bit accesses to be performed.
However, the NAND will be returning 16-bit words, and half of these will
be discarded.

This was observed when running mtd_stresstest.ko, which would report ECC
errors when reading from a non 16-bit aligned offset into a page, and
reading at least one subsequent page in the same read.

Signed-off-by: Ville Michael Baillie <ville.michael.baillie at gmail.com>
---
 drivers/mtd/nand/davinci_nand.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c
index 27fa8b8..ed9cd0d 100644
--- a/drivers/mtd/nand/davinci_nand.c
+++ b/drivers/mtd/nand/davinci_nand.c
@@ -442,12 +442,24 @@ static int nand_davinci_correct_4bit(struct mtd_info *mtd,
 static void nand_davinci_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 {
 	struct nand_chip *chip = mtd_to_nand(mtd);
+	u16 tmp;
 
 	if ((0x03 & ((unsigned)buf)) == 0 && (0x03 & len) == 0)
 		ioread32_rep(chip->IO_ADDR_R, buf, len >> 2);
 	else if ((0x01 & ((unsigned)buf)) == 0 && (0x01 & len) == 0)
 		ioread16_rep(chip->IO_ADDR_R, buf, len >> 1);
-	else
+	else if (chip->options & NAND_BUSWIDTH_16) {
+		/*
+		 * if NAND buswidth is 16 then 8 bit accesses
+		 * will silently discard half the data
+		 */
+		len /= 2;
+		while (len--) {
+			tmp = ioread16(chip->IO_ADDR_R);
+			memcpy(buf, &tmp, sizeof(u16));
+			buf += sizeof(u16);
+		}
+	} else
 		ioread8_rep(chip->IO_ADDR_R, buf, len);
 }
 
-- 
2.1.4



From richard at nod.at  Fri Oct 21 02:29:16 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 11:29:16 +0200
Subject: UBIFS with dma on 4.6 kernel is not working
In-Reply-To: <DA6901612C71B84D91459DE817C418AE26DF0F2B@XAP-PVEXMBX01.xlnx.xilinx.com>
References: <DA6901612C71B84D91459DE817C418AE26DF0F2B@XAP-PVEXMBX01.xlnx.xilinx.com>
Message-ID: <519a83bf-1244-5151-b873-bb8e1f2db3c6@nod.at>

Hi!

On 21.10.2016 11:21, Naga Sureshkumar Relli wrote:
> Hi,
> 
> This is regarding UBIFS on 4.6 kernel.
> We have tested UBIFS on our ZynqMP SOC QSPI Controller, the UBIFS is not working with dma on this kernel.
> Controller driver: https://github.com/torvalds/linux/commits/master/drivers/spi/spi-zynqmp-gqspi.c
> If I replace all vmalloc allocations in fs/ubifs/ to kmalloc then UBIFS with dma is working fine.

No, it will sooner or later OOM. Both UBI and UBIFS need rather large buffers, that's why we have to use
vmalloc().

> But whereas kernel before 4.6 without changing vmalloc to kmalloc, UBIFS is working fine with dma.
> So is there any change in UBIFS in 4.6 kernel that to dma related?

I'm not aware of such one.
Do you see this with vanilla kernels? Maybe some other internal stuff has changed.
git bisect can help.

DMA to vmalloced memory not good, it may work by chance if you transfer less than PAGE_SIZE.
Especially on ARM.

> May I know some info regarding this?
> Why UBIFS on kernels before 4.6 is working with dma but not with 4.6?
> Now a days, most of QSPI controllers have internal dmas.
> 
> Could you please provide some info regrading this dma issue?
> We can change our controller driver to operate in IO mode (doesn't use dma) but performance wise it's not a preferred one.

Most MTD drivers use a bounce buffer.
How much does your performance degrade?

Thanks,
//richard


From Joel.Esponde at Honeywell.com  Fri Oct 21 03:37:35 2016
From: Joel.Esponde at Honeywell.com (Esponde, Joel)
Date: Fri, 21 Oct 2016 10:37:35 +0000
Subject: [PATCH] mtd: spi-nor: fixed spansion quad enable
In-Reply-To: <56670303-e8e8-fb2c-e043-035c566f347c@atmel.com>
References: <1476971026-9665-1-git-send-email-joel.esponde@honeywell.com>
 <56670303-e8e8-fb2c-e043-035c566f347c@atmel.com>
Message-ID: <F6CD090A69E64C4289DC608E1C5D20242544AEF1@DE08W1305.global.ds.honeywell.com>

Hi Cyrille,

First, thanks for your comments !
Please, see below mines.

> -----Message d'origine-----
> De?: Cyrille Pitchen [mailto:cyrille.pitchen at atmel.com]
> Envoy??: jeudi 20 octobre 2016 17:23
> ??: Esponde, Joel <Joel.Esponde at Honeywell.com>; linux-
> mtd at lists.infradead.org
> Objet?: Re: [PATCH] mtd: spi-nor: fixed spansion quad enable
> 
> Hi Jo?l,
> 
> Le 20/10/2016 ? 15:43, Jo?l Esponde a ?crit :
> > With the S25FL127S nor flash part, each writing to the configuration register
> takes hundreds of ms. During that  time, no more accesses to the flash
> should be done (even reads).
> >
> > This commit adds:
> > - a pre check of the quad enable bit to avoid a useless and time
> > consuming writing to the flash,
> > - a wait loop after the register writing until the flash finishes its work.
> >
> > This issue could make rootfs mounting fail when the latter was done too
> much closely to this quad enable bit setting step. And in this case, a driver as
> UBIFS may try to recover the filesystem and may broke it completely.
> > ---
> >  drivers/mtd/spi-nor/spi-nor.c | 31 +++++++++++++++++++++++++++----
> >  1 file changed, 27 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/mtd/spi-nor/spi-nor.c
> > b/drivers/mtd/spi-nor/spi-nor.c index d0fc165..df43cd7 100644
> > --- a/drivers/mtd/spi-nor/spi-nor.c
> > +++ b/drivers/mtd/spi-nor/spi-nor.c
> > @@ -1246,18 +1246,41 @@ static int spansion_quad_enable(struct spi_nor
> *nor)
> >  	int ret;
> >  	int quad_en = CR_QUAD_EN_SPAN << 8;
> >
> > +	/* check quad enable bit
> > +	 * as S25FL127S takes 200 ms to execute each write of SR & CR
> > +	 * registers even if data is the same, write step will be shorted
> > +	 * if not needed
> > +	 */
> > +	ret = read_cr(nor);
> 
> Sorry but the Read Configuration Register (35h) command is not supported
> by all Spansion (or Spansion-like) memories.

I have a doubt here, if this is really the case, why read_cr() is already called at the end of the current implementation of the spansion_quad_enable() function to check that quad enable bit is set? 

> For more details, please refer to the JEDEC JESD216B specification, especially
> the part dealing with the "Quad Enable Requirements". An extract of this
> specification can also be found in this patch:
> https://patchwork.ozlabs.org/patch/678408/
> 
> Please have a look at values 001b, 100b and 101b for the bits[22:20] of the
> 15th DWORD.
> 
> I think your patch is likely to introduce a regression on some old memory
> parts.
> 
> However, *if* your S25FL127S memory implements the SFDP tables
> correctly, bits[22:20] of the 15th DWORD should be set to 101b, hence using
> SFDP patch above should fix the issue:
> spansion_new_quad_enable() will be called instead of the current
> spansion_quad_enable(). This new function adds the very same test on the
> Quad Enable bit as your patch does.
> 
> If you want to test the SFDP patch, you will need to apply the whole series
> which introduces some improvement on QSPI memory support:
> http://lists.infradead.org/pipermail/linux-mtd/2016-October/069554.html

Your patch using SFDP to dynamically manage memories seems really great (from a feature point of view, I am not yet able to have an opinion on the implementation...).

> 
> I'm just cautious with Spansion memories: I tested one sample, and I guess it
> was a S25FL127S, which claimed to be compliant with JESD216 rev B (minor 6)
> but words after the 9th one were all 0xffffffff.
> JESD216 (minor 0) describes only 9 DWORDs in the Basic Flash Parameter
> Table
> JESD216 rev A (minor 5) introduces 7 new DWORDS, hence 16 DWORDS in the
> (BFPT).
> the 15th DWORD provides the Quad Enable Requirements, which describes
> the procedure to set the Quad Enable bit.
> 
> If the BFPT of your S25FL127S is incomplete but the memory still claiming to
> be
> JESD216 rev B compliant, neither spansion_quad_enable() nor
> spansion_new_quad_enable() would be called. Since the Quad Enable bit is
> non-volatile on Spansion memories, it will work if the bit as already been set
> before.
> 

See below for code that should be IMO added because of the non-volatibility of spansion memories.

> > +	if (ret < 0) {
> > +		dev_err(nor->dev, "error %d reading CR\n", ret);
> > +		return ret;
> > +	}
> > +	if (ret & CR_QUAD_EN_SPAN) {
> > +		/* quad enable bit is already set */
> > +		return 0;
> > +	}
> > +
> > +	/* set SR & CR, enable quad I/O */
> >  	write_enable(nor);
> >
> >  	ret = write_sr_cr(nor, quad_en);
> >  	if (ret < 0) {
> > -		dev_err(nor->dev,
> > -			"error while writing configuration register\n");
> > +		dev_err(nor->dev, "error while writing SR and CR
> registers\n");
> >  		return -EINVAL;
> >  	}
> >
> > -	/* read back and check it */
> > +	ret = spi_nor_wait_till_ready(nor);
> > +	if (ret)
> > +		return ret;
> > +

I think that this wait is required with every memories that store Quad Enable bit in a non-volatile way.
I am using today a stripped down kernel with a rootfs based on UBIFS.
When this bit is set, UBIFS will start reading the memory 100ms after.
As this bit writing step takes up to 200ms, spansion memory is not ready and UBIFS will fail when trying to read the content of the partition.
As UBIFS has a recovery mechanism, it will even broke the file system.

> > +	/* read CR and check it */
> >  	ret = read_cr(nor);
> > -	if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
> > +	if (ret < 0) {
> > +		dev_err(nor->dev, "error %d reading CR\n", ret);
> > +		return ret;
> > +	}

This test on the validity of the returned data may also be useful.
When negative errors are returned, it is likely that the CR_QUAD_EN_SPAN bit is set, and so, next test may be meaningless...

> > +	if (!(ret & CR_QUAD_EN_SPAN)) {
> >  		dev_err(nor->dev, "Spansion Quad bit not set\n");
> >  		return -EINVAL;
> >  	}
> >

Best regards,
Jo?l


From clg at kaod.org  Fri Oct 21 04:25:21 2016
From: clg at kaod.org (=?UTF-8?Q?C=c3=a9dric_Le_Goater?=)
Date: Fri, 21 Oct 2016 13:25:21 +0200
Subject: [PATCH] mtd/spi-nor: Add SPI memory controllers for Aspeed SoCs
In-Reply-To: <420eece6-277d-6c8f-70ed-ba2a1c42d5d5@atmel.com>
References: <1476723427-13243-1-git-send-email-clg@kaod.org>
 <6964c1fd-3ac1-a28f-7b73-8113f0837e75@atmel.com>
 <f5074ac1-e536-5817-377a-e39514c8ca97@kaod.org>
 <420eece6-277d-6c8f-70ed-ba2a1c42d5d5@atmel.com>
Message-ID: <6d956d82-5966-c760-9332-7f9889ac17ff@kaod.org>

Hello Cyrille,

On 10/20/2016 04:33 PM, Cyrille Pitchen wrote:
> Hi C?dric,
> 
> Le 20/10/2016 ? 11:17, C?dric Le Goater a ?crit :
>> Hello Cyrille,
>>
>> Thanks for taking a look, some answers and more questions below.
>>
>> On 10/19/2016 07:06 PM, Cyrille Pitchen wrote:
>>> Hi C?dric,
>>>
>>> Le 17/10/2016 ? 18:57, C?dric Le Goater a ?crit :
>>>> This driver adds mtd support for spi-nor attached to either or both of
>>>> the Firmware Memory Controller or the SPI Flash Controller (AST2400
>>>> only).
>>>>
>>>> The SMC controllers on the Aspeed AST2500 SoC are very similar to the
>>>> ones found on the AST2400. The differences are on the number of
>>>> supported flash modules and their default mappings in the SoC address
>>>> space.
>>>>
>>>> The Aspeed AST2500 has one SPI controller for the BMC firmware and two
>>>> for the host firmware. All controllers have now the same set of
>>>> registers compatible with the AST2400 FMC controller and the legacy
>>>> 'SMC' controller is fully gone.
>>>>
>>>> Based on previous work from Milton D. Miller II <miltonm at us.ibm.com>
>>>>
>>>> Signed-off-by: C?dric Le Goater <clg at kaod.org>
>>>> ---
>>> [...]
>>>> +
>>>> +static void aspeed_smc_send_cmd_addr(struct spi_nor *nor, u8 cmd, u32 addr)
>>>> +{
>>>> +	struct aspeed_smc_chip *chip = nor->priv;
>>>> +	__be32 temp;
>>>> +	u32 cmdaddr;
>>>> +
>>>> +	switch (nor->addr_width) {
>>>> +	default:
>>>> +		WARN_ONCE(1, "Unexpected address width %u, defaulting to 3\n",
>>>> +			  nor->addr_width);
>>>> +		/* FALLTHROUGH */
>>>> +	case 3:
>>>> +		cmdaddr = addr & 0xFFFFFF;
>>>> +
>>>> +		cmdaddr |= (u32)cmd << 24;
>>>> +
>>>> +		temp = cpu_to_be32(cmdaddr);
>>>> +		aspeed_smc_to_fifo(chip->base, &temp, 4);
>>>> +		break;
>>>> +	case 4:
>>>> +		temp = cpu_to_be32(addr);
>>>> +		aspeed_smc_to_fifo(chip->base, &cmd, 1);
>>>> +		aspeed_smc_to_fifo(chip->base, &temp, 4);
>>>> +		break;
>>>> +	}
>>>> +}
>>>> +
>>>> +static ssize_t aspeed_smc_read_user(struct spi_nor *nor, loff_t from, size_t len,
>>>> +				    u_char *read_buf)
>>>> +{
>>>> +	struct aspeed_smc_chip *chip = nor->priv;
>>>> +
>>>> +	mutex_lock(&chip->controller->mutex);
>>>> +
>>>> +	aspeed_smc_start_user(nor);
>>
>> I think this section of code lock+start_user should be in a prepare handler 
>> if I am correct ? and I could get rid of the lock in that case to rely on
>> the one of the spi nor.
>>
> 
> For the mutex, looking at your driver, you lock it at the beginning then unlock
> at the end of the four handlers:
> - nor->read()
> - nor->write()
> - nor->read_reg()
> - nor->write_reg()
> 
> If this is the only purpose of this mutex, yes, you can remove it and relie on
> the internal spi-nor one (nor->lock), which is locked from
> spi_nor_lock_and_prep() hence at the beginning of spi_nor_erase(),
> spi_nor_read() and spi_nor_write() calls.
> 
> However, about moving the call of aspeed_smc_start_user() into a new prepare
> handler, I don't know whether it would actually fit your needs: for sure, 
> aspeed_smc_start_user() would be no longer called at some points.
> 
> 2 examples:
> 
> A - spi_nor_write() calls:
> 1 - spi_nor_lock_and_prep() -> nor->prepare()
> 2 - write_enable() -> nor->write_reg()
> 3 - nor->write()
> 4 - spi_nor_wait_till_ready() -> nor->read_reg()
> 5 - spi_nor_unlock_and_unprep() -> nor->unprepare()
> 
> With your current driver, aspeed_smc_start_user()/aspeed_smc_stop_user() are
> called 3 times, indeed each time a command is sent on the SPI bus:
> WRITE ENABLE, PAGE PROGRAM, READ STATUS
> 
> Then if you move then into spi_nor_[un]lock_and_[un]prep(), those two functions
> would only be called once each.
> 
> 
> B - spi_nor_scan() calls:
> 1 - spi_nor_read_id() -> nor->read_reg()
> 
> but spi_nor_lock_and_prep() is not called before, so if you nead to call
> aspeed_smc_start_user() before sending any command on the SPI bus, it won't
> work.

ok. So I need to keep it for now as the driver only supports the 
'User mode' of the controller.

In 'User mode', the controller sends commands to the module doing 
writes at the base address where the module is mapped and gets 
the results doing reads. So whatever is done, we need to make sure
this mode is enforced.

There is another mode called 'Command Mode' in the specs (the naming
is rather confusing) in which you can access the contents of the 
flash doing memory accesses in the memory window in which the module 
is mapped. The controller uses the setting in the CE control register
to generate the commands. This is not supported yet.

> I don't know how your SPI controller works but maybe using the nor->prepare()
> handler is not what you want!

Thanks a lot for the analysis.

>>>> +	aspeed_smc_send_cmd_addr(nor, nor->read_opcode, from);
>>>
>>> I guess the dummy cycles are missing between address cycles and data cycles!
>>> Check nor->read_dummy ;)
>>
>> ah yes, I meant to and I forgot to add it ... will do in v2. I suppose 
>> we are doing fine with the driver now because we only use normal speed.
>>
> 
> Indeed, the legacy READ (03h) command has no dummy cycles as opposed to all
> other FAST READ commands. Of course, the READ command is far much slower.
> 
>>> Or maybe this controller can really only perform READ operations but no FAST
>>> READ commands. Hence the "spi_nor_scan(&chip->nor, NULL, SPI_NOR_NORMAL)"
>>> below.
>>
>> yes it can. I suppose the driver should also call spi_nor_set_flash_node() 
>> for module supporting it. that brings another question I would like 
>> to discuss for possible followups patches. 
>>
> 
> Calling spi_nor_set_flash_node() with the relevant parameter tells
> spi_nor_scan() which DT node to parse to tune some settings.
> For instance, you could add the "m25p,fast-read" DT property so spi_nor_scan()
> would select Fast Read operations rather than Read operations.

Yes. That is something I will try pretty soon on the boards we have.

>> The controller can be fine tuned for a particular chip module. The 
>> CE0 control register has a few bits to set the spi clock, the dummy 
>> cycles, the CS inactive width and there is also a register to setup 
>> read timings delay.
>>  
>> So you need to loop on these different settings to find a correct one
>> and for that, you use a gold image captured at low speed as reference.
>>
>> But you need to know which chip module you are dealing with. would it 
>> be possible to expose the jedec to the controller for this purpose ? 
>> and then do the training to build the timing settings in the driver. 
>> This is a similar approach taken by some nand controllers.
>>
> 
> I'm not sure to fully understand your needs.
> The spi clock is often provided in the device tree, on the controller or memory
> node, with the "spi-max-frequency" DT property.

yes but it is possible also to discover what is the best timing at runtime 
depending on the chip model found and not rely on the DT for that. That is 
what I am trying to explain poorly. 

> The number of dummy cycles is set in nor->read_dummy by spi_nor_scan()
> according to the actual memory model and the selected (Fast) Read op code.
> For chip-select timings, those settings aren't currently handled by
> spi_nor_scan() but might be supported inside the SPI controller driver 
> through DT properties if needed.
>
> I don't know why your SPI controller driver needs to know the exact memory
> model to work. Aren't the pieces of information provided by spi-nor.c enough?
> Actually, for this point I don't quite exactly understand your needs! :)

he. Let's start with a non optimized version, then I will check the fast 
read op with the different boards/modules we have. Timings will come later, 
DMA also.

Thanks for the review.

C. 


> 
> Best regards,
> 
> Cyrille
> 
> 
>> Thanks,
>>
>> C.
>>
>>  
>>>> +	aspeed_smc_from_fifo(read_buf, chip->base, len);
>>>> +	aspeed_smc_stop_user(nor);
>>>> +
>>>> +	mutex_unlock(&chip->controller->mutex);
>>>> +
>>>> +	return len;
>>>> +}
>>> [...]
>>>
>>> Best regards,
>>>
>>> Cyrille
>>>
>>> ______________________________________________________
>>> Linux MTD discussion mailing list
>>> http://lists.infradead.org/mailman/listinfo/linux-mtd/
>>>
>>
> 



From cyrille.pitchen at atmel.com  Fri Oct 21 04:57:12 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Fri, 21 Oct 2016 13:57:12 +0200
Subject: UBIFS with dma on 4.6 kernel is not working
In-Reply-To: <519a83bf-1244-5151-b873-bb8e1f2db3c6@nod.at>
References: <DA6901612C71B84D91459DE817C418AE26DF0F2B@XAP-PVEXMBX01.xlnx.xilinx.com>
 <519a83bf-1244-5151-b873-bb8e1f2db3c6@nod.at>
Message-ID: <9a25ff8c-d988-4954-0141-eea08a01258e@atmel.com>

Hi all,

Le 21/10/2016 ? 11:29, Richard Weinberger a ?crit :
> Hi!
> 
> On 21.10.2016 11:21, Naga Sureshkumar Relli wrote:
>> Hi,
>>
>> This is regarding UBIFS on 4.6 kernel.
>> We have tested UBIFS on our ZynqMP SOC QSPI Controller, the UBIFS is not working with dma on this kernel.
>> Controller driver: https://github.com/torvalds/linux/commits/master/drivers/spi/spi-zynqmp-gqspi.c
>> If I replace all vmalloc allocations in fs/ubifs/ to kmalloc then UBIFS with dma is working fine.
> 
> No, it will sooner or later OOM. Both UBI and UBIFS need rather large buffers, that's why we have to use
> vmalloc().
> 
>> But whereas kernel before 4.6 without changing vmalloc to kmalloc, UBIFS is working fine with dma.
>> So is there any change in UBIFS in 4.6 kernel that to dma related?
> 
> I'm not aware of such one.
> Do you see this with vanilla kernels? Maybe some other internal stuff has changed.
> git bisect can help.
> 
> DMA to vmalloced memory not good, it may work by chance if you transfer less than PAGE_SIZE.
> Especially on ARM.
> 

Indeed we have the very same issue with Atmel SPI (not QSPI) controller driver
(drivers/spi/spi-atmel.c). Both the Atmel and Zynq drivers call dma_map_single()
on an address pointing inside the rx_buf or tx_buf members of the struct
spi_transfer.

dma_map_single() can only map *physically* contiguous memory pages. Memory
returned by kmalloc() is guaranteed to be physically contiguous so that's why
it worked when the memory was allocated with kmalloc() but since the memory
is allocated with vmalloc(), crashes have occurred: with vmalloc() there is no
guarantee that memory pages are physically contiguous.

I've have started to fix the Atmel SPI controller driver to get rid of the
dma_map_single() calls. To avoid the use a bounce buffer and the resulting
performance drop, I've tried to rely on the spi_map_msg() function from the SPI
framework. I've just implemented the master->can_dma() handler. Then the SPI
framework calls spi_map_msg() just before master->transfer_one() in
__spi_pump_messages(). spi_map_msg() calls __spi_map_msg(), which in turn calls
master->can_dma() and eventually spi_map_buf() to build a scatter-gather list
in xfer->tx_sg or xfer->rx_sg and map it with dma_map_sg().

For the few tests I ran till now, it works with a sama5d2. However I warn you
that there is a theoretical risk/limitation mapping vmalloc'ed memory for DMA
purpose. I've read that the DMA API doesn't handle cache aliases for memory
areas other than the DMA capable areas. vmalloc'ed memory falls into one
of those non DMA capable areas.
Hence, depending on the cache model (PIPT, VIPT or VIVT) you might expect cache
coherency issues if the same physical memory page is mapped to two or more
different virtual memory addresses. It is safe with a Physically Indexed
Physically Tagged cache model but unsafe with Virtually Indexed cache models.
As the name says, the cache line is indexed by the virtual address, so even
if the physical page is the same, each virtual address may have its own
cache line. Then when you call dma_map_sg() on the first virtual address, the
function is likely not to be aware of the second virtual address so would
not clean/invalidate the cache line associated with this second virtual
address.

This is theoretical, honestly I don't know whether there is a good reason to map
the same physical page twice in the virtual memory...
Anyway I'm not an expert in DMA and cache aliases so if anyone has a real
knowledge of the actual issues we may face using spi_map_msg(), it would be
nice to share with us! :)

Best regards,

Cyrille

>> May I know some info regarding this?
>> Why UBIFS on kernels before 4.6 is working with dma but not with 4.6?
>> Now a days, most of QSPI controllers have internal dmas.
>>
>> Could you please provide some info regrading this dma issue?
>> We can change our controller driver to operate in IO mode (doesn't use dma) but performance wise it's not a preferred one.
> 
> Most MTD drivers use a bounce buffer.
> How much does your performance degrade?
> 
> Thanks,
> //richard
> 
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/
> 



From richard at nod.at  Fri Oct 21 05:48:18 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 14:48:18 +0200
Subject: [PATCH 03/26] ubifs: Export ubifs_check_dir_empty()
In-Reply-To: <1477054121-10198-1-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
Message-ID: <1477054121-10198-4-git-send-email-richard@nod.at>

fscrypto will need this function too. Also get struct ubifs_info
from the provided inode. Not all callers will have a reference to
struct ubifs_info.

Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/ubifs/dir.c   | 8 ++++----
 fs/ubifs/ubifs.h | 1 +
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index 4b86d3a738e1..177343bce143 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -617,15 +617,15 @@ out_cancel:
 
 /**
  * check_dir_empty - check if a directory is empty or not.
- * @c: UBIFS file-system description object
  * @dir: VFS inode object of the directory to check
  *
  * This function checks if directory @dir is empty. Returns zero if the
  * directory is empty, %-ENOTEMPTY if it is not, and other negative error codes
  * in case of of errors.
  */
-static int check_dir_empty(struct ubifs_info *c, struct inode *dir)
+int ubifs_check_dir_empty(struct inode *dir)
 {
+	struct ubifs_info *c = dir->i_sb->s_fs_info;
 	struct qstr nm = { .name = NULL };
 	struct ubifs_dent_node *dent;
 	union ubifs_key key;
@@ -663,7 +663,7 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
 		inode->i_ino, dir->i_ino);
 	ubifs_assert(inode_is_locked(dir));
 	ubifs_assert(inode_is_locked(inode));
-	err = check_dir_empty(c, d_inode(dentry));
+	err = ubifs_check_dir_empty(d_inode(dentry));
 	if (err)
 		return err;
 
@@ -1003,7 +1003,7 @@ static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
 
 
 	if (unlink && is_dir) {
-		err = check_dir_empty(c, new_inode);
+		err = ubifs_check_dir_empty(new_inode);
 		if (err)
 			return err;
 	}
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 4617d459022a..f7d649eb61d5 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -1731,6 +1731,7 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
 			      umode_t mode);
 int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
 		  struct kstat *stat);
+int ubifs_check_dir_empty(struct inode *dir);
 
 /* xattr.c */
 extern const struct xattr_handler *ubifs_xattr_handlers[];
-- 
2.7.3



From richard at nod.at  Fri Oct 21 05:48:17 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 14:48:17 +0200
Subject: [PATCH 02/26] fscrypto: Constify struct inode pointer
In-Reply-To: <1477054121-10198-1-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
Message-ID: <1477054121-10198-3-git-send-email-richard@nod.at>

Some filesystems, such as UBIFS, maintain a const pointer
for struct inode.

Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/crypto/crypto.c       | 12 +++++++-----
 include/linux/fscrypto.h | 12 +++++++-----
 2 files changed, 14 insertions(+), 10 deletions(-)

diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c
index 1c2f9516b4be..8c59912feebb 100644
--- a/fs/crypto/crypto.c
+++ b/fs/crypto/crypto.c
@@ -147,7 +147,7 @@ typedef enum {
 	FS_ENCRYPT,
 } fscrypt_direction_t;
 
-static int do_crypto(struct inode *inode,
+static int do_crypto(const struct inode *inode,
 		     fscrypt_direction_t rw, pgoff_t index,
 		     struct scatterlist *src, struct scatterlist *dst,
 		     unsigned int cryptlen, gfp_t gfp_flags)
@@ -212,7 +212,7 @@ static int do_page_crypto(struct inode *inode,
 	return do_crypto(inode, rw, index, &src, &dst, PAGE_SIZE, gfp_flags);
 }
 
-static int do_buf_crypto(struct inode *inode,
+static int do_buf_crypto(const struct inode *inode,
 			 fscrypt_direction_t rw, pgoff_t index,
 			 const void *src_buf, const void *dst_buf,
 			 unsigned int buflen, gfp_t gfp_flags)
@@ -287,7 +287,7 @@ errout:
 }
 EXPORT_SYMBOL(fscrypt_encrypt_page);
 
-int fscrypt_encrypt_buffer(struct inode *inode, const void *plaintext_buf,
+int fscrypt_encrypt_buffer(const struct inode *inode, const void *plaintext_buf,
 			   const void *ciphertext_buf, unsigned int buflen,
 			   pgoff_t index, gfp_t gfp_flags)
 {
@@ -296,8 +296,10 @@ int fscrypt_encrypt_buffer(struct inode *inode, const void *plaintext_buf,
 }
 EXPORT_SYMBOL(fscrypt_encrypt_buffer);
 
-int fscrypt_decrypt_buffer(struct inode *inode, const void *ciphertext_buf,
-			   const void *plaintext_buf, unsigned int buflen,
+int fscrypt_decrypt_buffer(const struct inode *inode,
+			   const void *ciphertext_buf,
+			   const void *plaintext_buf,
+			   unsigned int buflen,
 			   pgoff_t index, gfp_t gfp_flags)
 {
 	return do_buf_crypto(inode, FS_DECRYPT, index, ciphertext_buf,
diff --git a/include/linux/fscrypto.h b/include/linux/fscrypto.h
index a9628b4882e7..d18ee29cf69a 100644
--- a/include/linux/fscrypto.h
+++ b/include/linux/fscrypto.h
@@ -273,11 +273,13 @@ extern void fscrypt_pullback_bio_page(struct page **, bool);
 extern void fscrypt_restore_control_page(struct page *);
 extern int fscrypt_zeroout_range(struct inode *, pgoff_t, sector_t,
 						unsigned int);
-int fscrypt_encrypt_buffer(struct inode *inode, const void *plaintext_buf,
+int fscrypt_encrypt_buffer(const struct inode *inode, const void *plaintext_buf,
 			   const void *ciphertext_buf, unsigned int buflen,
 			   pgoff_t index, gfp_t gfp_flags);
-int fscrypt_decrypt_buffer(struct inode *inode, const void *ciphertext_buf,
-			   const void *plaintext_buf, unsigned int buflen,
+int fscrypt_decrypt_buffer(const struct inode *inode,
+			   const void *ciphertext_buf,
+			   const void *plaintext_buf,
+			   unsigned int buflen,
 			   pgoff_t index, gfp_t gfp_flags);
 /* policy.c */
 extern int fscrypt_process_policy(struct file *, const struct fscrypt_policy *);
@@ -291,8 +293,8 @@ extern int fscrypt_get_encryption_info(struct inode *);
 extern void fscrypt_put_encryption_info(struct inode *, struct fscrypt_info *);
 
 /* fname.c */
-extern int fscrypt_setup_filename(struct inode *, const struct qstr *,
-				int lookup, struct fscrypt_name *);
+extern int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
+			   int lookup, struct fscrypt_name *fname);
 extern void fscrypt_free_filename(struct fscrypt_name *);
 extern u32 fscrypt_fname_encrypted_size(struct inode *, u32);
 extern int fscrypt_fname_alloc_buffer(struct inode *, u32,
-- 
2.7.3



From richard at nod.at  Fri Oct 21 05:48:16 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 14:48:16 +0200
Subject: [PATCH 01/26] fscrypto: Add buffer operations
In-Reply-To: <1477054121-10198-1-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
Message-ID: <1477054121-10198-2-git-send-email-richard@nod.at>

Not all filesystems operate on pages, therefore offer
operations to en/decrypt buffers.
Of course these buffers have to be allocated in a way such that
the kernel crypto framework can work with them.

Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/crypto/crypto.c       | 63 +++++++++++++++++++++++++++++++++++++++---------
 include/linux/fscrypto.h | 24 ++++++++++++++++++
 2 files changed, 76 insertions(+), 11 deletions(-)

diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c
index c502c116924c..1c2f9516b4be 100644
--- a/fs/crypto/crypto.c
+++ b/fs/crypto/crypto.c
@@ -147,15 +147,14 @@ typedef enum {
 	FS_ENCRYPT,
 } fscrypt_direction_t;
 
-static int do_page_crypto(struct inode *inode,
-			fscrypt_direction_t rw, pgoff_t index,
-			struct page *src_page, struct page *dest_page,
-			gfp_t gfp_flags)
+static int do_crypto(struct inode *inode,
+		     fscrypt_direction_t rw, pgoff_t index,
+		     struct scatterlist *src, struct scatterlist *dst,
+		     unsigned int cryptlen, gfp_t gfp_flags)
 {
 	u8 xts_tweak[FS_XTS_TWEAK_SIZE];
 	struct skcipher_request *req = NULL;
 	DECLARE_FS_COMPLETION_RESULT(ecr);
-	struct scatterlist dst, src;
 	struct fscrypt_info *ci = inode->i_crypt_info;
 	struct crypto_skcipher *tfm = ci->ci_ctfm;
 	int res = 0;
@@ -177,12 +176,8 @@ static int do_page_crypto(struct inode *inode,
 	memset(&xts_tweak[sizeof(index)], 0,
 			FS_XTS_TWEAK_SIZE - sizeof(index));
 
-	sg_init_table(&dst, 1);
-	sg_set_page(&dst, dest_page, PAGE_SIZE, 0);
-	sg_init_table(&src, 1);
-	sg_set_page(&src, src_page, PAGE_SIZE, 0);
-	skcipher_request_set_crypt(req, &src, &dst, PAGE_SIZE,
-					xts_tweak);
+	skcipher_request_set_crypt(req, src, dst, cryptlen,
+				   xts_tweak);
 	if (rw == FS_DECRYPT)
 		res = crypto_skcipher_decrypt(req);
 	else
@@ -202,6 +197,34 @@ static int do_page_crypto(struct inode *inode,
 	return 0;
 }
 
+static int do_page_crypto(struct inode *inode,
+			  fscrypt_direction_t rw, pgoff_t index,
+			  struct page *src_page, struct page *dst_page,
+			  gfp_t gfp_flags)
+{
+	struct scatterlist src, dst;
+
+	sg_init_table(&src, 1);
+	sg_set_page(&src, src_page, PAGE_SIZE, 0);
+	sg_init_table(&dst, 1);
+	sg_set_page(&dst, dst_page, PAGE_SIZE, 0);
+
+	return do_crypto(inode, rw, index, &src, &dst, PAGE_SIZE, gfp_flags);
+}
+
+static int do_buf_crypto(struct inode *inode,
+			 fscrypt_direction_t rw, pgoff_t index,
+			 const void *src_buf, const void *dst_buf,
+			 unsigned int buflen, gfp_t gfp_flags)
+{
+	struct scatterlist src, dst;
+
+	sg_init_one(&src, src_buf, buflen);
+	sg_init_one(&dst, dst_buf, buflen);
+
+	return do_crypto(inode, rw, index, &src, &dst, buflen, gfp_flags);
+}
+
 static struct page *alloc_bounce_page(struct fscrypt_ctx *ctx, gfp_t gfp_flags)
 {
 	ctx->w.bounce_page = mempool_alloc(fscrypt_bounce_page_pool, gfp_flags);
@@ -264,6 +287,24 @@ errout:
 }
 EXPORT_SYMBOL(fscrypt_encrypt_page);
 
+int fscrypt_encrypt_buffer(struct inode *inode, const void *plaintext_buf,
+			   const void *ciphertext_buf, unsigned int buflen,
+			   pgoff_t index, gfp_t gfp_flags)
+{
+	return do_buf_crypto(inode, FS_ENCRYPT, index, plaintext_buf,
+			     ciphertext_buf, buflen, gfp_flags);
+}
+EXPORT_SYMBOL(fscrypt_encrypt_buffer);
+
+int fscrypt_decrypt_buffer(struct inode *inode, const void *ciphertext_buf,
+			   const void *plaintext_buf, unsigned int buflen,
+			   pgoff_t index, gfp_t gfp_flags)
+{
+	return do_buf_crypto(inode, FS_DECRYPT, index, ciphertext_buf,
+			     plaintext_buf, buflen, gfp_flags);
+}
+EXPORT_SYMBOL(fscrypt_decrypt_buffer);
+
 /**
  * f2crypt_decrypt_page() - Decrypts a page in-place
  * @page: The page to decrypt. Must be locked.
diff --git a/include/linux/fscrypto.h b/include/linux/fscrypto.h
index 76cff18bb032..a9628b4882e7 100644
--- a/include/linux/fscrypto.h
+++ b/include/linux/fscrypto.h
@@ -273,6 +273,12 @@ extern void fscrypt_pullback_bio_page(struct page **, bool);
 extern void fscrypt_restore_control_page(struct page *);
 extern int fscrypt_zeroout_range(struct inode *, pgoff_t, sector_t,
 						unsigned int);
+int fscrypt_encrypt_buffer(struct inode *inode, const void *plaintext_buf,
+			   const void *ciphertext_buf, unsigned int buflen,
+			   pgoff_t index, gfp_t gfp_flags);
+int fscrypt_decrypt_buffer(struct inode *inode, const void *ciphertext_buf,
+			   const void *plaintext_buf, unsigned int buflen,
+			   pgoff_t index, gfp_t gfp_flags);
 /* policy.c */
 extern int fscrypt_process_policy(struct file *, const struct fscrypt_policy *);
 extern int fscrypt_get_policy(struct inode *, struct fscrypt_policy *);
@@ -418,6 +424,24 @@ static inline void fscrypt_notsupp_fname_free_buffer(struct fscrypt_str *c)
 	return;
 }
 
+static inline int fscrypt_notsupp_encrypt_buffer(const struct inode *inode,
+						 const void *plaintext_buf,
+						 const void *ciphertext_buf,
+						 unsigned int buflen,
+						 pgoff_t index, gfp_t gfp_flags)
+{
+	return -EOPNOTSUPP;
+}
+
+static inline int fscrypt_notsupp_decrypt_buffer(const struct inode *inode,
+						 const void *ciphertext_buf,
+						 const void *plaintext_buf,
+						 unsigned int buflen,
+						 pgoff_t index, gfp_t gfp_flags)
+{
+	return -EOPNOTSUPP;
+}
+
 static inline int fscrypt_notsupp_fname_disk_to_usr(struct inode *inode,
 			u32 hash, u32 minor_hash,
 			const struct fscrypt_str *iname,
-- 
2.7.3



From richard at nod.at  Fri Oct 21 05:48:19 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 14:48:19 +0200
Subject: [PATCH 04/26] ubifs: Export xattr get and set functions
In-Reply-To: <1477054121-10198-1-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
Message-ID: <1477054121-10198-5-git-send-email-richard@nod.at>

For fscrypto we need this function outside of xattr.c.

Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/ubifs/ubifs.h |  4 ++++
 fs/ubifs/xattr.c | 35 ++++++++++++++++++-----------------
 2 files changed, 22 insertions(+), 17 deletions(-)

diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index f7d649eb61d5..94c1f5563c01 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -1738,6 +1738,10 @@ extern const struct xattr_handler *ubifs_xattr_handlers[];
 ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size);
 int ubifs_init_security(struct inode *dentry, struct inode *inode,
 			const struct qstr *qstr);
+int ubifs_xattr_set(struct inode *host, const char *name, const void *value,
+		    size_t size, int flags);
+ssize_t ubifs_xattr_get(struct inode *host, const char *name, void *buf,
+			size_t size);
 
 /* super.c */
 struct inode *ubifs_iget(struct super_block *sb, unsigned long inum);
diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c
index 11a004114eba..ad4463752709 100644
--- a/fs/ubifs/xattr.c
+++ b/fs/ubifs/xattr.c
@@ -266,8 +266,8 @@ static struct inode *iget_xattr(struct ubifs_info *c, ino_t inum)
 	return ERR_PTR(-EINVAL);
 }
 
-static int __ubifs_setxattr(struct inode *host, const char *name,
-			    const void *value, size_t size, int flags)
+int ubifs_xattr_set(struct inode *host, const char *name, const void *value,
+		    size_t size, int flags)
 {
 	struct inode *inode;
 	struct ubifs_info *c = host->i_sb->s_fs_info;
@@ -326,8 +326,8 @@ out_free:
 	return err;
 }
 
-static ssize_t __ubifs_getxattr(struct inode *host, const char *name,
-				void *buf, size_t size)
+ssize_t ubifs_xattr_get(struct inode *host, const char *name, void *buf,
+			size_t size)
 {
 	struct inode *inode;
 	struct ubifs_info *c = host->i_sb->s_fs_info;
@@ -482,7 +482,7 @@ out_cancel:
 	return err;
 }
 
-static int __ubifs_removexattr(struct inode *host, const char *name)
+static int ubifs_xattr_remove(struct inode *host, const char *name)
 {
 	struct inode *inode;
 	struct ubifs_info *c = host->i_sb->s_fs_info;
@@ -544,7 +544,8 @@ static int init_xattrs(struct inode *inode, const struct xattr *xattr_array,
 		}
 		strcpy(name, XATTR_SECURITY_PREFIX);
 		strcpy(name + XATTR_SECURITY_PREFIX_LEN, xattr->name);
-		err = __ubifs_setxattr(inode, name, xattr->value, xattr->value_len, 0);
+		err = ubifs_xattr_set(inode, name, xattr->value,
+				      xattr->value_len, 0);
 		kfree(name);
 		if (err < 0)
 			break;
@@ -568,7 +569,7 @@ int ubifs_init_security(struct inode *dentry, struct inode *inode,
 	return err;
 }
 
-static int ubifs_xattr_get(const struct xattr_handler *handler,
+static int xattr_get(const struct xattr_handler *handler,
 			   struct dentry *dentry, struct inode *inode,
 			   const char *name, void *buffer, size_t size)
 {
@@ -576,10 +577,10 @@ static int ubifs_xattr_get(const struct xattr_handler *handler,
 		inode->i_ino, dentry, size);
 
 	name = xattr_full_name(handler, name);
-	return __ubifs_getxattr(inode, name, buffer, size);
+	return ubifs_xattr_get(inode, name, buffer, size);
 }
 
-static int ubifs_xattr_set(const struct xattr_handler *handler,
+static int xattr_set(const struct xattr_handler *handler,
 			   struct dentry *dentry, struct inode *inode,
 			   const char *name, const void *value,
 			   size_t size, int flags)
@@ -590,27 +591,27 @@ static int ubifs_xattr_set(const struct xattr_handler *handler,
 	name = xattr_full_name(handler, name);
 
 	if (value)
-		return __ubifs_setxattr(inode, name, value, size, flags);
+		return ubifs_xattr_set(inode, name, value, size, flags);
 	else
-		return __ubifs_removexattr(inode, name);
+		return ubifs_xattr_remove(inode, name);
 }
 
 static const struct xattr_handler ubifs_user_xattr_handler = {
 	.prefix = XATTR_USER_PREFIX,
-	.get = ubifs_xattr_get,
-	.set = ubifs_xattr_set,
+	.get = xattr_get,
+	.set = xattr_set,
 };
 
 static const struct xattr_handler ubifs_trusted_xattr_handler = {
 	.prefix = XATTR_TRUSTED_PREFIX,
-	.get = ubifs_xattr_get,
-	.set = ubifs_xattr_set,
+	.get = xattr_get,
+	.set = xattr_set,
 };
 
 static const struct xattr_handler ubifs_security_xattr_handler = {
 	.prefix = XATTR_SECURITY_PREFIX,
-	.get = ubifs_xattr_get,
-	.set = ubifs_xattr_set,
+	.get = xattr_get,
+	.set = xattr_set,
 };
 
 const struct xattr_handler *ubifs_xattr_handlers[] = {
-- 
2.7.3



From richard at nod.at  Fri Oct 21 05:48:15 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 14:48:15 +0200
Subject: [PATCH 00/26] UBIFS File Encryption
Message-ID: <1477054121-10198-1-git-send-email-richard@nod.at>

This patch series implements file level encryption for UBIFS.
It makes use of the generic fscrypto framework as used by ext4 and f2fs.
Among file contents also file names are encrypted,
for more details on fscrypto please see [0] and [1].

To support encrypted files in UBIFS multiple preparations were needed.
Patches 1/26 and 2/26 touch fscrypto code and add support to work on
buffers instead of pages.
UBIFS has a different IO model than ext4 and f2fs because it uses MTD
instead of the block layer. But the changes are small and non-invasive.
In UBIFS itself the biggest change was supporting hash lookups.
Now UBIFS is able to provide a 64bit cookie which can be used later
to locate a file. This change will also allow us implementing proper
NFS and telldir() support, but that will be a different patch series.
Because of these changes the UBIFS write version is now 5.

As userspace component I'm currently using e4crypt from e2fsprogs with
EXT2FS_KEY_DESC_PREFIX set to "fscrypt:" instead of "ext4:".
A common tool will hopefully emerge soon[2]. I don't want an UBIFS
specific tool in mtd-utils.

The series is based in 4.8-rc7, but will be rebased soon to 4.9-rcX.
I'm still sending the series now to get feedback as soon as possible.
It can be obtained from:
git://git.infradead.org/users/rw/linux.git ubifs_crypt_v0

[0] https://lwn.net/Articles/639427/
[1] https://docs.google.com/document/d/1ft26lUQyuSpiu6VleP70_npaWdRfXFoNnB8JYnykNTg/edit
[2] http://www.spinics.net/lists/linux-fsdevel/msg103107.html

Richard Weinberger (26):
  fscrypto: Add buffer operations
  fscrypto: Constify struct inode pointer
  ubifs: Export ubifs_check_dir_empty()
  ubifs: Export xattr get and set functions
  ubifs: Define UBIFS crypto context xattr
  ubifs: Add skeleton for fscrypto
  ubifs: Massage ubifs_listxattr() for encryption context
  ubifs: Implement directory open operation
  ubifs: Implement file open operation
  ubifs: Enforce crypto policy in ->link and ->rename
  ubifs: Preload crypto context in ->lookup()
  ubifs: Massage assert in ubifs_xattr_set() wrt. fscrypto
  ubifs: Enforce crypto policy in mmap
  ubifs: Introduce new data node field, compr_size
  ubifs: Implement encrypt/decrypt for all IO
  ubifs: Relax checks in ubifs_validate_entry()
  ubifs: Make r5 hash binary string aware
  ubifs: Constify struct inode pointer in ubifs_crypt_is_encrypted()
  ubifs: Implement encrypted filenames
  ubifs: Add support for encrypted symlinks
  ubifs: Rename tnc_read_node_nm
  ubifs: Add full hash lookup support
  ubifs: Use a random number for cookies
  ubifs: Implement UBIFS_FLG_DOUBLE_HASH
  ubifs: Implement UBIFS_FLG_ENCRYPTION
  ubifs: Raise write version to 5

 fs/crypto/crypto.c       |  65 +++++--
 fs/ubifs/Kconfig         |  11 ++
 fs/ubifs/Makefile        |   1 +
 fs/ubifs/crypto.c        |  45 +++++
 fs/ubifs/debug.c         |  14 +-
 fs/ubifs/dir.c           | 431 +++++++++++++++++++++++++++++++++++++++--------
 fs/ubifs/file.c          | 130 +++++++++++++-
 fs/ubifs/ioctl.c         |  40 +++++
 fs/ubifs/journal.c       | 202 ++++++++++++++--------
 fs/ubifs/key.h           |  21 +--
 fs/ubifs/replay.c        |  10 +-
 fs/ubifs/sb.c            |  59 +++++++
 fs/ubifs/super.c         |  17 +-
 fs/ubifs/tnc.c           | 168 ++++++++++++++----
 fs/ubifs/ubifs-media.h   |  29 +++-
 fs/ubifs/ubifs.h         |  82 ++++++++-
 fs/ubifs/xattr.c         | 112 +++++++-----
 include/linux/fscrypto.h |  30 +++-
 18 files changed, 1202 insertions(+), 265 deletions(-)
 create mode 100644 fs/ubifs/crypto.c

-- 
2.7.3



From richard at nod.at  Fri Oct 21 05:48:20 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 14:48:20 +0200
Subject: [PATCH 05/26] ubifs: Define UBIFS crypto context xattr
In-Reply-To: <1477054121-10198-1-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
Message-ID: <1477054121-10198-6-git-send-email-richard@nod.at>

Like ext4 UBIFS will store the crypto context in a xattr
attribute.

Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/ubifs/ubifs-media.h | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h
index e24380cf46ed..d47e9569b3de 100644
--- a/fs/ubifs/ubifs-media.h
+++ b/fs/ubifs/ubifs-media.h
@@ -301,6 +301,13 @@ enum {
 #define UBIFS_MAX_NODE_SZ UBIFS_MAX_INO_NODE_SZ
 
 /*
+ * xattr name of UBIFS encryption context, we don't use a prefix
+ * nor a long name to not waste space on the flash.
+ */
+#define UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT "c"
+
+
+/*
  * On-flash inode flags.
  *
  * UBIFS_COMPR_FL: use compression for this inode
-- 
2.7.3



From richard at nod.at  Fri Oct 21 05:48:26 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 14:48:26 +0200
Subject: [PATCH 11/26] ubifs: Preload crypto context in ->lookup()
In-Reply-To: <1477054121-10198-1-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
Message-ID: <1477054121-10198-12-git-send-email-richard@nod.at>

...and mark the dentry as encrypted.

Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/ubifs/dir.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index a77edc5ca5c9..7ee32768ba19 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -218,6 +218,21 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
 
 	dbg_gen("'%pd' in dir ino %lu", dentry, dir->i_ino);
 
+	if (ubifs_crypt_is_encrypted(dir)) {
+		err = fscrypt_get_encryption_info(dir);
+
+		/*
+		 * DCACHE_ENCRYPTED_WITH_KEY is set if the dentry is
+		 * created while the directory was encrypted and we
+		 * have access to the key.
+		 */
+		if (fscrypt_has_encryption_key(dir))
+			fscrypt_set_encrypted_dentry(dentry);
+		fscrypt_set_d_op(dentry);
+		if (err && err != -ENOKEY)
+			return ERR_PTR(err);
+	}
+
 	if (dentry->d_name.len > UBIFS_MAX_NLEN)
 		return ERR_PTR(-ENAMETOOLONG);
 
-- 
2.7.3



From richard at nod.at  Fri Oct 21 05:48:22 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 14:48:22 +0200
Subject: [PATCH 07/26] ubifs: Massage ubifs_listxattr() for encryption context
In-Reply-To: <1477054121-10198-1-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
Message-ID: <1477054121-10198-8-git-send-email-richard@nod.at>

We have to make sure that we don't expose our internal
crypto context to userspace.

Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/ubifs/xattr.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c
index b390902c48aa..54ec2b9fd506 100644
--- a/fs/ubifs/xattr.c
+++ b/fs/ubifs/xattr.c
@@ -394,6 +394,20 @@ out_unlock:
 	return err;
 }
 
+static bool xattr_visible(const char *name)
+{
+	/* File encryption related xattrs are for internal use only */
+	if (strcmp(name, UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT) == 0)
+		return false;
+
+	/* Show trusted namespace only for "power" users */
+	if (strncmp(name, XATTR_TRUSTED_PREFIX,
+		    XATTR_TRUSTED_PREFIX_LEN) == 0 && !capable(CAP_SYS_ADMIN))
+		return false;
+
+	return true;
+}
+
 ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size)
 {
 	union ubifs_key key;
@@ -429,10 +443,7 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size)
 		nm.name = xent->name;
 		nm.len = le16_to_cpu(xent->nlen);
 
-		/* Show trusted namespace only for "power" users */
-		if (strncmp(xent->name, XATTR_TRUSTED_PREFIX,
-			    XATTR_TRUSTED_PREFIX_LEN) ||
-		    capable(CAP_SYS_ADMIN)) {
+		if (xattr_visible(xent->name)) {
 			memcpy(buffer + written, nm.name, nm.len + 1);
 			written += nm.len + 1;
 		}
-- 
2.7.3



From richard at nod.at  Fri Oct 21 05:48:29 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 14:48:29 +0200
Subject: [PATCH 14/26] ubifs: Introduce new data node field, compr_size
In-Reply-To: <1477054121-10198-1-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
Message-ID: <1477054121-10198-15-git-send-email-richard@nod.at>

When data of a data node is compressed and encrypted
we need to store the size of the compressed data because
before encryption we may have to add padding bytes.

For the new field we consume the last two padding bytes
in struct ubifs_data_node. Two bytes are fine because
the data length is at most 4096.

Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/ubifs/journal.c     | 11 -----------
 fs/ubifs/ubifs-media.h |  6 ++----
 2 files changed, 2 insertions(+), 15 deletions(-)

diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c
index 0b9da5b6e0f9..a643de4e3d91 100644
--- a/fs/ubifs/journal.c
+++ b/fs/ubifs/journal.c
@@ -82,15 +82,6 @@ static inline void zero_dent_node_unused(struct ubifs_dent_node *dent)
 }
 
 /**
- * zero_data_node_unused - zero out unused fields of an on-flash data node.
- * @data: the data node to zero out
- */
-static inline void zero_data_node_unused(struct ubifs_data_node *data)
-{
-	memset(data->padding, 0, 2);
-}
-
-/**
  * zero_trun_node_unused - zero out unused fields of an on-flash truncation
  *                         node.
  * @trun: the truncation node to zero out
@@ -722,7 +713,6 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
 	data->ch.node_type = UBIFS_DATA_NODE;
 	key_write(c, key, &data->key);
 	data->size = cpu_to_le32(len);
-	zero_data_node_unused(data);
 
 	if (!(ui->flags & UBIFS_COMPR_FL))
 		/* Compression is disabled for this inode */
@@ -1199,7 +1189,6 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
 					dn->size = cpu_to_le32(dlen);
 					dlen += UBIFS_DATA_NODE_SZ;
 				}
-				zero_data_node_unused(dn);
 			}
 		}
 	}
diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h
index aa302b11aec8..e46331dcca4c 100644
--- a/fs/ubifs/ubifs-media.h
+++ b/fs/ubifs/ubifs-media.h
@@ -553,18 +553,16 @@ struct ubifs_dent_node {
  * @key: node key
  * @size: uncompressed data size in bytes
  * @compr_type: compression type (%UBIFS_COMPR_NONE, %UBIFS_COMPR_LZO, etc)
- * @padding: reserved for future, zeroes
+ * @compr_size: compressed data size in bytes, only valid when data is encrypted
  * @data: data
  *
- * Note, do not forget to amend 'zero_data_node_unused()' function when
- * changing the padding fields.
  */
 struct ubifs_data_node {
 	struct ubifs_ch ch;
 	__u8 key[UBIFS_MAX_KEY_LEN];
 	__le32 size;
 	__le16 compr_type;
-	__u8 padding[2]; /* Watch 'zero_data_node_unused()' if changing! */
+	__le16 compr_size;
 	__u8 data[];
 } __packed;
 
-- 
2.7.3



From richard at nod.at  Fri Oct 21 05:48:28 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 14:48:28 +0200
Subject: [PATCH 13/26] ubifs: Enforce crypto policy in mmap
In-Reply-To: <1477054121-10198-1-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
Message-ID: <1477054121-10198-14-git-send-email-richard@nod.at>

We need this extra check in mmap because a process could
gain an already opened fd.

Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/ubifs/file.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index fc79278969e5..bd0049788e24 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -1594,6 +1594,15 @@ static const struct vm_operations_struct ubifs_file_vm_ops = {
 static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	int err;
+	struct inode *inode = file->f_mapping->host;
+
+	if (ubifs_crypt_is_encrypted(inode)) {
+		err = fscrypt_get_encryption_info(inode);
+		if (err)
+			return -EACCES;
+		if (!fscrypt_has_encryption_key(inode))
+			return -ENOKEY;
+	}
 
 	err = generic_file_mmap(file, vma);
 	if (err)
-- 
2.7.3



From richard at nod.at  Fri Oct 21 05:48:24 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 14:48:24 +0200
Subject: [PATCH 09/26] ubifs: Implement file open operation
In-Reply-To: <1477054121-10198-1-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
Message-ID: <1477054121-10198-10-git-send-email-richard@nod.at>

We need ->open() for files to load the crypto key.
If the no key is present and the file is encrypted,
refuse to open.

Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/ubifs/file.c | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index 7bbf420d1289..fc79278969e5 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -1605,6 +1605,35 @@ static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma)
 	return 0;
 }
 
+static int ubifs_file_open(struct inode *inode, struct file *filp)
+{
+	int ret;
+	struct dentry *dir;
+	struct ubifs_info *c = inode->i_sb->s_fs_info;
+
+	if (ubifs_crypt_is_encrypted(inode)) {
+		ret = fscrypt_get_encryption_info(inode);
+		if (ret)
+			return -EACCES;
+		if (!fscrypt_has_encryption_key(inode))
+			return -ENOKEY;
+	}
+
+	dir = dget_parent(file_dentry(filp));
+	if (ubifs_crypt_is_encrypted(d_inode(dir)) &&
+			!fscrypt_has_permitted_context(d_inode(dir), inode)) {
+		ubifs_err(c, "Inconsistent encryption contexts: %lu/%lu",
+			  (unsigned long) d_inode(dir)->i_ino,
+			  (unsigned long) inode->i_ino);
+		dput(dir);
+		ubifs_ro_mode(c, -EPERM);
+		return -EPERM;
+	}
+	dput(dir);
+
+	return 0;
+}
+
 const struct address_space_operations ubifs_file_address_operations = {
 	.readpage       = ubifs_readpage,
 	.writepage      = ubifs_writepage,
@@ -1653,6 +1682,7 @@ const struct file_operations ubifs_file_operations = {
 	.unlocked_ioctl = ubifs_ioctl,
 	.splice_read	= generic_file_splice_read,
 	.splice_write	= iter_file_splice_write,
+	.open		= ubifs_file_open,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl   = ubifs_compat_ioctl,
 #endif
-- 
2.7.3



From richard at nod.at  Fri Oct 21 05:48:23 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 14:48:23 +0200
Subject: [PATCH 08/26] ubifs: Implement directory open operation
In-Reply-To: <1477054121-10198-1-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
Message-ID: <1477054121-10198-9-git-send-email-richard@nod.at>

We need the ->open() hook to load the crypto context
which is needed for all crypto operations within that
directory.

Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/ubifs/dir.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index 0e47127352ed..e80de3852c3e 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -1196,6 +1196,14 @@ int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
 	return 0;
 }
 
+static int ubifs_dir_open(struct inode *dir, struct file *file)
+{
+	if (ubifs_crypt_is_encrypted(dir))
+		return fscrypt_get_encryption_info(dir) ? -EACCES : 0;
+
+	return 0;
+}
+
 const struct inode_operations ubifs_dir_inode_operations = {
 	.lookup      = ubifs_lookup,
 	.create      = ubifs_create,
@@ -1224,6 +1232,7 @@ const struct file_operations ubifs_dir_operations = {
 	.iterate_shared = ubifs_readdir,
 	.fsync          = ubifs_fsync,
 	.unlocked_ioctl = ubifs_ioctl,
+	.open		= ubifs_dir_open,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl   = ubifs_compat_ioctl,
 #endif
-- 
2.7.3



From richard at nod.at  Fri Oct 21 05:48:25 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 14:48:25 +0200
Subject: [PATCH 10/26] ubifs: Enforce crypto policy in ->link and ->rename
In-Reply-To: <1477054121-10198-1-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
Message-ID: <1477054121-10198-11-git-send-email-richard@nod.at>

When a file is moved or linked into another directory
its current crypto policy has to be compatible with the
target policy.

Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/ubifs/dir.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index e80de3852c3e..a77edc5ca5c9 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -544,6 +544,10 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
 	ubifs_assert(inode_is_locked(dir));
 	ubifs_assert(inode_is_locked(inode));
 
+	if (ubifs_crypt_is_encrypted(dir) &&
+	    !fscrypt_has_permitted_context(dir, inode))
+		return -EPERM;
+
 	err = dbg_check_synced_i_size(c, inode);
 	if (err)
 		return err;
@@ -1027,6 +1031,11 @@ static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
 	if (unlink)
 		ubifs_assert(inode_is_locked(new_inode));
 
+	if (old_dir != new_dir) {
+		if (ubifs_crypt_is_encrypted(new_dir) &&
+		    !fscrypt_has_permitted_context(new_dir, old_inode))
+			return -EPERM;
+	}
 
 	if (unlink && is_dir) {
 		err = ubifs_check_dir_empty(new_inode);
-- 
2.7.3



From richard at nod.at  Fri Oct 21 05:48:27 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 14:48:27 +0200
Subject: [PATCH 12/26] ubifs: Massage assert in ubifs_xattr_set() wrt. fscrypto
In-Reply-To: <1477054121-10198-1-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
Message-ID: <1477054121-10198-13-git-send-email-richard@nod.at>

When we're creating a new inode in UBIFS the inode is not
yet exposed and fscrypto calls ubifs_xattr_set() without
holding the inode mutex. This is okay but ubifs_xattr_set()
has to know about this.

Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/ubifs/xattr.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c
index 54ec2b9fd506..d3b53c55ea39 100644
--- a/fs/ubifs/xattr.c
+++ b/fs/ubifs/xattr.c
@@ -286,7 +286,13 @@ int ubifs_xattr_set(struct inode *host, const char *name, const void *value,
 	union ubifs_key key;
 	int err;
 
-	ubifs_assert(inode_is_locked(host));
+	/*
+	 * Creating an encryption context is done unlocked since we
+	 * operate on a new inode which is not visible to other users
+	 * at this point.
+	 */
+	if (strcmp(name, UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT) != 0)
+		ubifs_assert(inode_is_locked(host));
 
 	if (size > UBIFS_MAX_INO_DATA)
 		return -ERANGE;
-- 
2.7.3



From richard at nod.at  Fri Oct 21 05:48:38 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 14:48:38 +0200
Subject: [PATCH 23/26] ubifs: Use a random number for cookies
In-Reply-To: <1477054121-10198-1-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
Message-ID: <1477054121-10198-24-git-send-email-richard@nod.at>

Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/ubifs/journal.c | 3 +++
 fs/ubifs/ubifs.h   | 1 +
 2 files changed, 4 insertions(+)

diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c
index 50696c6e0ae2..dcecfbfbf40e 100644
--- a/fs/ubifs/journal.c
+++ b/fs/ubifs/journal.c
@@ -589,6 +589,7 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
 	dent->nlen = cpu_to_le16(fname_len(nm));
 	memcpy(dent->name, fname_name(nm), fname_len(nm));
 	dent->name[fname_len(nm)] = '\0';
+	dent->cookie = prandom_u32();
 
 	zero_dent_node_unused(dent);
 	ubifs_prep_grp_node(c, dent, dlen, 0);
@@ -992,6 +993,7 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
 	dent->nlen = cpu_to_le16(fname_len(new_nm));
 	memcpy(dent->name, fname_name(new_nm), fname_len(new_nm));
 	dent->name[fname_len(new_nm)] = '\0';
+	dent->cookie = prandom_u32();
 	zero_dent_node_unused(dent);
 	ubifs_prep_grp_node(c, dent, dlen1, 0);
 
@@ -1004,6 +1006,7 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
 	dent2->nlen = cpu_to_le16(fname_len(old_nm));
 	memcpy(dent2->name, fname_name(old_nm), fname_len(old_nm));
 	dent2->name[fname_len(old_nm)] = '\0';
+	dent2->cookie = prandom_u32();
 	zero_dent_node_unused(dent2);
 	ubifs_prep_grp_node(c, dent2, dlen2, 0);
 
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 3f68b26b120f..294e4047bcc0 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -39,6 +39,7 @@
 #include <linux/security.h>
 #include <linux/xattr.h>
 #include <linux/fscrypto.h>
+#include <linux/random.h>
 #include "ubifs-media.h"
 
 /* Version of this UBIFS implementation */
-- 
2.7.3



From richard at nod.at  Fri Oct 21 05:48:21 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 14:48:21 +0200
Subject: [PATCH 06/26] ubifs: Add skeleton for fscrypto
In-Reply-To: <1477054121-10198-1-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
Message-ID: <1477054121-10198-7-git-send-email-richard@nod.at>

This is the first building block to provide file level
encryption on UBIFS.

Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/ubifs/Kconfig       | 11 +++++++++++
 fs/ubifs/Makefile      |  1 +
 fs/ubifs/crypto.c      | 45 +++++++++++++++++++++++++++++++++++++++++++++
 fs/ubifs/dir.c         | 28 +++++++++++++++++++++++++++-
 fs/ubifs/ioctl.c       | 35 +++++++++++++++++++++++++++++++++++
 fs/ubifs/super.c       | 10 ++++++++++
 fs/ubifs/ubifs-media.h |  2 ++
 fs/ubifs/ubifs.h       | 39 ++++++++++++++++++++++++++++++++++++++-
 fs/ubifs/xattr.c       | 10 ++++++++++
 9 files changed, 179 insertions(+), 2 deletions(-)
 create mode 100644 fs/ubifs/crypto.c

diff --git a/fs/ubifs/Kconfig b/fs/ubifs/Kconfig
index 7ff7712f284e..0a908ae7af13 100644
--- a/fs/ubifs/Kconfig
+++ b/fs/ubifs/Kconfig
@@ -50,3 +50,14 @@ config UBIFS_ATIME_SUPPORT
 	  strictatime is the "heavy", relatime is "lighter", etc.
 
 	  If unsure, say 'N'
+
+config UBIFS_FS_ENCRYPTION
+	bool "UBIFS Encryption"
+	depends on UBIFS_FS
+	select FS_ENCRYPTION
+	default n
+	help
+	  Enable encryption of UBIFS files and directories. This
+	  feature is similar to ecryptfs, but it is more memory
+	  efficient since it avoids caching the encrypted and
+	  decrypted pages in the page cache.
diff --git a/fs/ubifs/Makefile b/fs/ubifs/Makefile
index c54a24360f85..6f3251c2bf08 100644
--- a/fs/ubifs/Makefile
+++ b/fs/ubifs/Makefile
@@ -5,3 +5,4 @@ ubifs-y += tnc.o master.o scan.o replay.o log.o commit.o gc.o orphan.o
 ubifs-y += budget.o find.o tnc_commit.o compress.o lpt.o lprops.o
 ubifs-y += recovery.o ioctl.o lpt_commit.o tnc_misc.o xattr.o debug.o
 ubifs-y += misc.o
+ubifs-$(CONFIG_UBIFS_FS_ENCRYPTION) += crypto.o
diff --git a/fs/ubifs/crypto.c b/fs/ubifs/crypto.c
new file mode 100644
index 000000000000..160c31479e0c
--- /dev/null
+++ b/fs/ubifs/crypto.c
@@ -0,0 +1,45 @@
+#include "ubifs.h"
+
+static int ubifs_crypt_get_context(struct inode *inode, void *ctx, size_t len)
+{
+	return ubifs_xattr_get(inode, UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT,
+			       ctx, len);
+}
+
+static int ubifs_crypt_set_context(struct inode *inode, const void *ctx,
+				   size_t len, void *fs_data)
+{
+	return ubifs_xattr_set(inode, UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT,
+			       ctx, len, 0);
+}
+
+static bool ubifs_crypt_empty_dir(struct inode *inode)
+{
+	return ubifs_check_dir_empty(inode) == 0;
+}
+
+static unsigned int ubifs_crypt_max_namelen(struct inode *inode)
+{
+	if (S_ISLNK(inode->i_mode))
+		return UBIFS_MAX_INO_DATA;
+	else
+		return UBIFS_MAX_NLEN;
+}
+
+static int ubifs_key_prefix(struct inode *inode, u8 **key)
+{
+	static char prefix[] = "ubifs:";
+
+	*key = prefix;
+
+	return sizeof(prefix) - 1;
+}
+
+struct fscrypt_operations ubifs_crypt_operations = {
+	.get_context		= ubifs_crypt_get_context,
+	.set_context		= ubifs_crypt_set_context,
+	.is_encrypted		= ubifs_crypt_is_encrypted,
+	.empty_dir		= ubifs_crypt_empty_dir,
+	.max_namelen		= ubifs_crypt_max_namelen,
+	.key_prefix		= ubifs_key_prefix,
+};
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index 177343bce143..0e47127352ed 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -85,11 +85,26 @@ static int inherit_flags(const struct inode *dir, umode_t mode)
  * initializes it. Returns new inode in case of success and an error code in
  * case of failure.
  */
-struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
+struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
 			      umode_t mode)
 {
+	int err;
 	struct inode *inode;
 	struct ubifs_inode *ui;
+	bool encrypted = false;
+
+	if (ubifs_crypt_is_encrypted(dir)) {
+		err = fscrypt_get_encryption_info(dir);
+		if (err) {
+			ubifs_err(c, "fscrypt_get_encryption_info failed: %i", err);
+			return ERR_PTR(err);
+		}
+
+		if (!fscrypt_has_encryption_key(dir))
+			return ERR_PTR(-EPERM);
+
+		encrypted = true;
+	}
 
 	inode = new_inode(c->vfs_sb);
 	ui = ubifs_inode(inode);
@@ -165,6 +180,17 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
 	 */
 	ui->creat_sqnum = ++c->max_sqnum;
 	spin_unlock(&c->cnt_lock);
+
+	if (encrypted) {
+		err = fscrypt_inherit_context(dir, inode, &encrypted, true);
+		if (err) {
+			ubifs_err(c, "fscrypt_inherit_context failed: %i", err);
+			make_bad_inode(inode);
+			iput(inode);
+			return ERR_PTR(err);
+		}
+	}
+
 	return inode;
 }
 
diff --git a/fs/ubifs/ioctl.c b/fs/ubifs/ioctl.c
index 3c7b29de0ca7..6bb5b35050de 100644
--- a/fs/ubifs/ioctl.c
+++ b/fs/ubifs/ioctl.c
@@ -181,6 +181,41 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 		mnt_drop_write_file(file);
 		return err;
 	}
+	case FS_IOC_SET_ENCRYPTION_POLICY: {
+#ifdef CONFIG_UBIFS_FS_ENCRYPTION
+		struct fscrypt_policy policy;
+
+		if (copy_from_user(&policy,
+				   (struct fscrypt_policy __user *)arg,
+				   sizeof(policy)))
+			return -EFAULT;
+
+		err = fscrypt_process_policy(file, &policy);
+
+		return err;
+#else
+		return -EOPNOTSUPP;
+#endif
+	}
+	case FS_IOC_GET_ENCRYPTION_POLICY: {
+#ifdef CONFIG_UBIFS_FS_ENCRYPTION
+		struct fscrypt_policy policy;
+
+		if (!ubifs_crypt_is_encrypted(inode))
+			return -ENOENT;
+
+		err = fscrypt_get_policy(inode, &policy);
+		if (err)
+			return err;
+
+		if (copy_to_user((void __user *)arg, &policy, sizeof(policy)))
+			return -EFAULT;
+
+		return 0;
+#else
+		return -EOPNOTSUPP;
+#endif
+	}
 
 	default:
 		return -ENOTTY;
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 4ec051089186..a31222947265 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -380,6 +380,9 @@ out:
 	}
 done:
 	clear_inode(inode);
+#ifdef CONFIG_UBIFS_FS_ENCRYPTION
+	fscrypt_put_encryption_info(inode, NULL);
+#endif
 }
 
 static void ubifs_dirty_inode(struct inode *inode, int flags)
@@ -1995,6 +1998,12 @@ static struct ubifs_info *alloc_ubifs_info(struct ubi_volume_desc *ubi)
 	return c;
 }
 
+#ifndef CONFIG_UBIFS_FS_ENCRYPTION
+struct fscrypt_operations ubifs_crypt_operations = {
+	.is_encrypted		= __ubifs_crypt_is_encrypted,
+};
+#endif
+
 static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct ubifs_info *c = sb->s_fs_info;
@@ -2041,6 +2050,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
 		sb->s_maxbytes = c->max_inode_sz = MAX_LFS_FILESIZE;
 	sb->s_op = &ubifs_super_operations;
 	sb->s_xattr = ubifs_xattr_handlers;
+	sb->s_cop = &ubifs_crypt_operations;
 
 	mutex_lock(&c->umount_mutex);
 	err = mount_ubifs(c);
diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h
index d47e9569b3de..aa302b11aec8 100644
--- a/fs/ubifs/ubifs-media.h
+++ b/fs/ubifs/ubifs-media.h
@@ -316,6 +316,7 @@ enum {
  * UBIFS_APPEND_FL: writes to the inode may only append data
  * UBIFS_DIRSYNC_FL: I/O on this directory inode has to be synchronous
  * UBIFS_XATTR_FL: this inode is the inode for an extended attribute value
+ * UBIFS_CRYPT_FL: use encryption for this inode
  *
  * Note, these are on-flash flags which correspond to ioctl flags
  * (@FS_COMPR_FL, etc). They have the same values now, but generally, do not
@@ -328,6 +329,7 @@ enum {
 	UBIFS_APPEND_FL    = 0x08,
 	UBIFS_DIRSYNC_FL   = 0x10,
 	UBIFS_XATTR_FL     = 0x20,
+	UBIFS_CRYPT_FL     = 0x40,
 };
 
 /* Inode flag bits used by UBIFS */
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 94c1f5563c01..63dd027727ca 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -38,6 +38,7 @@
 #include <linux/backing-dev.h>
 #include <linux/security.h>
 #include <linux/xattr.h>
+#include <linux/fscrypto.h>
 #include "ubifs-media.h"
 
 /* Version of this UBIFS implementation */
@@ -1727,7 +1728,7 @@ int ubifs_update_time(struct inode *inode, struct timespec *time, int flags);
 #endif
 
 /* dir.c */
-struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
+struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
 			      umode_t mode);
 int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
 		  struct kstat *stat);
@@ -1776,10 +1777,46 @@ void ubifs_compress(const struct ubifs_info *c, const void *in_buf, int in_len,
 int ubifs_decompress(const struct ubifs_info *c, const void *buf, int len,
 		     void *out, int *out_len, int compr_type);
 
+extern struct fscrypt_operations ubifs_crypt_operations;
+
 #include "debug.h"
 #include "misc.h"
 #include "key.h"
 
+#ifndef CONFIG_UBIFS_FS_ENCRYPTION
+#define fscrypt_set_d_op(i)
+#define fscrypt_get_ctx                 fscrypt_notsupp_get_ctx
+#define fscrypt_release_ctx             fscrypt_notsupp_release_ctx
+#define fscrypt_encrypt_page            fscrypt_notsupp_encrypt_page
+#define fscrypt_decrypt_page            fscrypt_notsupp_decrypt_page
+#define fscrypt_encrypt_buffer          fscrypt_notsupp_encrypt_buffer
+#define fscrypt_decrypt_buffer          fscrypt_notsupp_decrypt_buffer
+#define fscrypt_decrypt_bio_pages       fscrypt_notsupp_decrypt_bio_pages
+#define fscrypt_pullback_bio_page       fscrypt_notsupp_pullback_bio_page
+#define fscrypt_restore_control_page    fscrypt_notsupp_restore_control_page
+#define fscrypt_zeroout_range           fscrypt_notsupp_zeroout_range
+#define fscrypt_process_policy          fscrypt_notsupp_process_policy
+#define fscrypt_get_policy              fscrypt_notsupp_get_policy
+#define fscrypt_has_permitted_context   fscrypt_notsupp_has_permitted_context
+#define fscrypt_inherit_context         fscrypt_notsupp_inherit_context
+#define fscrypt_get_encryption_info     fscrypt_notsupp_get_encryption_info
+#define fscrypt_put_encryption_info     fscrypt_notsupp_put_encryption_info
+#define fscrypt_setup_filename          fscrypt_notsupp_setup_filename
+#define fscrypt_free_filename           fscrypt_notsupp_free_filename
+#define fscrypt_fname_encrypted_size    fscrypt_notsupp_fname_encrypted_size
+#define fscrypt_fname_alloc_buffer      fscrypt_notsupp_fname_alloc_buffer
+#define fscrypt_fname_free_buffer       fscrypt_notsupp_fname_free_buffer
+#define fscrypt_fname_disk_to_usr       fscrypt_notsupp_fname_disk_to_usr
+#define fscrypt_fname_usr_to_disk       fscrypt_notsupp_fname_usr_to_disk
+#endif
+
+static inline bool ubifs_crypt_is_encrypted(struct inode *inode)
+{
+	struct ubifs_inode *ui = ubifs_inode(inode);
+
+	return ui->flags & UBIFS_CRYPT_FL;
+}
+
 /* Normal UBIFS messages */
 __printf(2, 3)
 void ubifs_msg(const struct ubifs_info *c, const char *fmt, ...);
diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c
index ad4463752709..b390902c48aa 100644
--- a/fs/ubifs/xattr.c
+++ b/fs/ubifs/xattr.c
@@ -158,6 +158,15 @@ static int create_xattr(struct ubifs_info *c, struct inode *host,
 	host_ui->xattr_size += CALC_XATTR_BYTES(size);
 	host_ui->xattr_names += nm->len;
 
+	/*
+	 * We handle UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT here because we
+	 * have to set the UBIFS_CRYPT_FL flag on the host inode.
+	 * To avoid multiple updates of the same inode in the same operation,
+	 * let's do it here.
+	 */
+	if (strcmp(nm->name, UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT) == 0)
+		host_ui->flags |= UBIFS_CRYPT_FL;
+
 	err = ubifs_jnl_update(c, host, nm, inode, 0, 1);
 	if (err)
 		goto out_cancel;
@@ -172,6 +181,7 @@ out_cancel:
 	host_ui->xattr_cnt -= 1;
 	host_ui->xattr_size -= CALC_DENT_SIZE(nm->len);
 	host_ui->xattr_size -= CALC_XATTR_BYTES(size);
+	host_ui->flags &= ~UBIFS_CRYPT_FL;
 	mutex_unlock(&host_ui->ui_mutex);
 out_free:
 	make_bad_inode(inode);
-- 
2.7.3



From richard at nod.at  Fri Oct 21 05:48:32 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 14:48:32 +0200
Subject: [PATCH 17/26] ubifs: Make r5 hash binary string aware
In-Reply-To: <1477054121-10198-1-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
Message-ID: <1477054121-10198-18-git-send-email-richard@nod.at>

As of now all filenames known by UBIFS are strings with a NUL
terminator. With encrypted filenames a filename can be any binary
string and the r5 function cannot search for the NUL terminator.
UBIFS always knows how long a filename is, therefore we can change
the hash function to iterate over the filename length to work
correctly with binary strings.

Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/ubifs/key.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/ubifs/key.h b/fs/ubifs/key.h
index c0a95e393347..ca4371fdfa7d 100644
--- a/fs/ubifs/key.h
+++ b/fs/ubifs/key.h
@@ -69,7 +69,7 @@ static inline uint32_t key_r5_hash(const char *s, int len)
 	uint32_t a = 0;
 	const signed char *str = (const signed char *)s;
 
-	while (*str) {
+	while (len--) {
 		a += *str << 4;
 		a += *str >> 4;
 		a *= 11;
-- 
2.7.3



From richard at nod.at  Fri Oct 21 05:48:35 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 14:48:35 +0200
Subject: [PATCH 20/26] ubifs: Add support for encrypted symlinks
In-Reply-To: <1477054121-10198-1-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
Message-ID: <1477054121-10198-21-git-send-email-richard@nod.at>

Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/ubifs/dir.c   | 81 +++++++++++++++++++++++++++++++++++++++++++++++++-------
 fs/ubifs/file.c  | 55 +++++++++++++++++++++++++++++++++++++-
 fs/ubifs/super.c |  1 -
 3 files changed, 125 insertions(+), 12 deletions(-)

diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index 723bae4dec30..2f33be5ca57c 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -1051,10 +1051,27 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
 	struct ubifs_inode *dir_ui = ubifs_inode(dir);
 	struct ubifs_info *c = dir->i_sb->s_fs_info;
 	int err, len = strlen(symname);
-	int sz_change = CALC_DENT_SIZE(dentry->d_name.len);
+	int sz_change = CALC_DENT_SIZE(len);
+	struct fscrypt_str disk_link = FSTR_INIT((char *)symname, len + 1);
+	struct fscrypt_symlink_data *sd = NULL;
 	struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
 					.new_ino_d = ALIGN(len, 8),
 					.dirtied_ino = 1 };
+	struct fscrypt_name nm;
+
+	if (ubifs_crypt_is_encrypted(dir)) {
+		err = fscrypt_get_encryption_info(dir);
+		if (err)
+			goto out_budg;
+
+		if (!fscrypt_has_encryption_key(dir)) {
+			err = -EPERM;
+			goto out_budg;
+		}
+
+		disk_link.len = (fscrypt_fname_encrypted_size(dir, len) +
+				sizeof(struct fscrypt_symlink_data));
+	}
 
 	/*
 	 * Budget request settings: new inode, new direntry and changing parent
@@ -1064,36 +1081,77 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
 	dbg_gen("dent '%pd', target '%s' in dir ino %lu", dentry,
 		symname, dir->i_ino);
 
-	if (len > UBIFS_MAX_INO_DATA)
+	if (disk_link.len > UBIFS_MAX_INO_DATA)
 		return -ENAMETOOLONG;
 
 	err = ubifs_budget_space(c, &req);
 	if (err)
 		return err;
 
+	err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm);
+	if (err)
+		goto out_budg;
+
 	inode = ubifs_new_inode(c, dir, S_IFLNK | S_IRWXUGO);
 	if (IS_ERR(inode)) {
 		err = PTR_ERR(inode);
-		goto out_budg;
+		goto out_fname;
 	}
 
 	ui = ubifs_inode(inode);
-	ui->data = kmalloc(len + 1, GFP_NOFS);
+	ui->data = kmalloc(disk_link.len, GFP_NOFS);
 	if (!ui->data) {
 		err = -ENOMEM;
 		goto out_inode;
 	}
 
-	memcpy(ui->data, symname, len);
-	((char *)ui->data)[len] = '\0';
-	inode->i_link = ui->data;
+	if (ubifs_crypt_is_encrypted(dir)) {
+		struct qstr istr = QSTR_INIT(symname, len);
+		struct fscrypt_str ostr;
+
+		sd = kzalloc(disk_link.len, GFP_NOFS);
+		if (!sd) {
+			err = -ENOMEM;
+			goto out_inode;
+		}
+
+		err = fscrypt_get_encryption_info(inode);
+		if (err) {
+			kfree(sd);
+			goto out_inode;
+		}
+
+		if (!fscrypt_has_encryption_key(inode)) {
+			kfree(sd);
+			err = -EPERM;
+			goto out_inode;
+		}
+
+		ostr.name = sd->encrypted_path;
+		ostr.len = disk_link.len;
+
+		err = fscrypt_fname_usr_to_disk(inode, &istr, &ostr);
+		if (err < 0) {
+			kfree(sd);
+			goto out_inode;
+		}
+
+		sd->len = cpu_to_le16(ostr.len);
+		disk_link.name = (char *)sd;
+	} else {
+		inode->i_link = ui->data;
+	}
+
+	memcpy(ui->data, disk_link.name, disk_link.len);
+	((char *)ui->data)[disk_link.len - 1] = '\0';
+
 	/*
 	 * The terminating zero byte is not written to the flash media and it
 	 * is put just to make later in-memory string processing simpler. Thus,
 	 * data length is @len, not @len + %1.
 	 */
-	ui->data_len = len;
-	inode->i_size = ubifs_inode(inode)->ui_size = len;
+	ui->data_len = disk_link.len - 1;
+	inode->i_size = ubifs_inode(inode)->ui_size = disk_link.len - 1;
 
 	err = ubifs_init_security(dir, inode, &dentry->d_name);
 	if (err)
@@ -1103,7 +1161,7 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
 	dir->i_size += sz_change;
 	dir_ui->ui_size = dir->i_size;
 	dir->i_mtime = dir->i_ctime = inode->i_ctime;
-	err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0);
+	err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0);
 	if (err)
 		goto out_cancel;
 	mutex_unlock(&dir_ui->ui_mutex);
@@ -1111,6 +1169,7 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
 	ubifs_release_budget(c, &req);
 	insert_inode_hash(inode);
 	d_instantiate(dentry, inode);
+	fscrypt_free_filename(&nm);
 	return 0;
 
 out_cancel:
@@ -1120,6 +1179,8 @@ out_cancel:
 out_inode:
 	make_bad_inode(inode);
 	iput(inode);
+out_fname:
+	fscrypt_free_filename(&nm);
 out_budg:
 	ubifs_release_budget(c, &req);
 	return err;
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index 60e089d50c82..ce168b3f61ca 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -1679,6 +1679,59 @@ static int ubifs_file_open(struct inode *inode, struct file *filp)
 	return 0;
 }
 
+static const char *ubifs_get_link(struct dentry *dentry,
+					    struct inode *inode,
+					    struct delayed_call *done)
+{
+	int err;
+	struct fscrypt_symlink_data *sd;
+	struct ubifs_inode *ui = ubifs_inode(inode);
+	struct fscrypt_str cstr;
+	struct fscrypt_str pstr;
+
+	if (!dentry)
+		return ERR_PTR(-ECHILD);
+
+	if (ubifs_crypt_is_encrypted(inode)) {
+		err = fscrypt_get_encryption_info(inode);
+		if (err)
+			return ERR_PTR(err);
+	} else
+		return ui->data;
+
+
+	sd = (struct fscrypt_symlink_data *)ui->data;
+	cstr.name = sd->encrypted_path;
+	cstr.len = le16_to_cpu(sd->len);
+
+	if (cstr.len == 0)
+		return ERR_PTR(-ENOENT);
+
+	if ((cstr.len + sizeof(struct fscrypt_symlink_data) - 1) > ui->data_len)
+		return ERR_PTR(-EIO);
+
+	err = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr);
+	if (err)
+		return ERR_PTR(err);
+
+	err = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr);
+	if (err < 0) {
+		fscrypt_fname_free_buffer(&pstr);
+		return ERR_PTR(err);
+	}
+
+	pstr.name[err] = '\0';
+
+	if (pstr.name[0] == '\0') {
+		fscrypt_fname_free_buffer(&pstr);
+		return ERR_PTR(-ENOENT);
+	}
+
+	set_delayed_call(done, kfree_link, pstr.name);
+	return pstr.name;
+}
+
+
 const struct address_space_operations ubifs_file_address_operations = {
 	.readpage       = ubifs_readpage,
 	.writepage      = ubifs_writepage,
@@ -1706,7 +1759,7 @@ const struct inode_operations ubifs_file_inode_operations = {
 
 const struct inode_operations ubifs_symlink_inode_operations = {
 	.readlink    = generic_readlink,
-	.get_link    = simple_get_link,
+	.get_link    = ubifs_get_link,
 	.setattr     = ubifs_setattr,
 	.getattr     = ubifs_getattr,
 	.setxattr    = generic_setxattr,
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index ae25c908fbe5..e08aa04fc835 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -198,7 +198,6 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
 		}
 		memcpy(ui->data, ino->data, ui->data_len);
 		((char *)ui->data)[ui->data_len] = '\0';
-		inode->i_link = ui->data;
 		break;
 	case S_IFBLK:
 	case S_IFCHR:
-- 
2.7.3



From richard at nod.at  Fri Oct 21 05:48:39 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 14:48:39 +0200
Subject: [PATCH 24/26] ubifs: Implement UBIFS_FLG_DOUBLE_HASH
In-Reply-To: <1477054121-10198-1-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
Message-ID: <1477054121-10198-25-git-send-email-richard@nod.at>

This feature flag indicates that all directory entry nodes have a 32bit
cookie set and therefore UBIFS is allowed to perform lookups by hash.

Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/ubifs/journal.c     | 14 +++++++++++---
 fs/ubifs/sb.c          |  2 ++
 fs/ubifs/tnc.c         |  3 +++
 fs/ubifs/ubifs-media.h |  3 +++
 fs/ubifs/ubifs.h       |  2 ++
 5 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c
index dcecfbfbf40e..c8a483a0df2c 100644
--- a/fs/ubifs/journal.c
+++ b/fs/ubifs/journal.c
@@ -501,6 +501,14 @@ static void mark_inode_clean(struct ubifs_info *c, struct ubifs_inode *ui)
 	ui->dirty = 0;
 }
 
+static void set_dent_cookie(struct ubifs_info *c, struct ubifs_dent_node *dent)
+{
+	if (c->double_hash)
+		dent->cookie = prandom_u32();
+	else
+		dent->cookie = 0;
+}
+
 /**
  * ubifs_jnl_update - update inode.
  * @c: UBIFS file-system description object
@@ -589,7 +597,7 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
 	dent->nlen = cpu_to_le16(fname_len(nm));
 	memcpy(dent->name, fname_name(nm), fname_len(nm));
 	dent->name[fname_len(nm)] = '\0';
-	dent->cookie = prandom_u32();
+	set_dent_cookie(c, dent);
 
 	zero_dent_node_unused(dent);
 	ubifs_prep_grp_node(c, dent, dlen, 0);
@@ -993,7 +1001,7 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
 	dent->nlen = cpu_to_le16(fname_len(new_nm));
 	memcpy(dent->name, fname_name(new_nm), fname_len(new_nm));
 	dent->name[fname_len(new_nm)] = '\0';
-	dent->cookie = prandom_u32();
+	set_dent_cookie(c, dent);
 	zero_dent_node_unused(dent);
 	ubifs_prep_grp_node(c, dent, dlen1, 0);
 
@@ -1006,7 +1014,7 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
 	dent2->nlen = cpu_to_le16(fname_len(old_nm));
 	memcpy(dent2->name, fname_name(old_nm), fname_len(old_nm));
 	dent2->name[fname_len(old_nm)] = '\0';
-	dent2->cookie = prandom_u32();
+	set_dent_cookie(c, dent2);
 	zero_dent_node_unused(dent2);
 	ubifs_prep_grp_node(c, dent2, dlen2, 0);
 
diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c
index 3cbb904a6d7d..4a2b4c361587 100644
--- a/fs/ubifs/sb.c
+++ b/fs/ubifs/sb.c
@@ -163,6 +163,7 @@ static int create_default_filesystem(struct ubifs_info *c)
 	tmp64 = (long long)max_buds * c->leb_size;
 	if (big_lpt)
 		sup_flags |= UBIFS_FLG_BIGLPT;
+	sup_flags |= UBIFS_FLG_DOUBLE_HASH;
 
 	sup->ch.node_type  = UBIFS_SB_NODE;
 	sup->key_hash      = UBIFS_KEY_HASH_R5;
@@ -620,6 +621,7 @@ int ubifs_read_superblock(struct ubifs_info *c)
 	memcpy(&c->uuid, &sup->uuid, 16);
 	c->big_lpt = !!(sup_flags & UBIFS_FLG_BIGLPT);
 	c->space_fixup = !!(sup_flags & UBIFS_FLG_SPACE_FIXUP);
+	c->double_hash = !!(sup_flags & UBIFS_FLG_DOUBLE_HASH);
 
 	/* Automatically increase file system size to the maximum size */
 	c->old_leb_cnt = c->leb_cnt;
diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c
index 1eaf994addb4..02205a68f851 100644
--- a/fs/ubifs/tnc.c
+++ b/fs/ubifs/tnc.c
@@ -1939,6 +1939,9 @@ int ubifs_tnc_lookup_dh(struct ubifs_info *c, const union ubifs_key *key,
 	int err;
 	const struct ubifs_dent_node *dent = node;
 
+	if (!c->double_hash)
+		return -EOPNOTSUPP;
+
 	/*
 	 * We assume that in most of the cases there are no name collisions and
 	 * 'ubifs_tnc_lookup()' returns us the right direntry.
diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h
index 249124d9a801..0cbdc6b70a00 100644
--- a/fs/ubifs/ubifs-media.h
+++ b/fs/ubifs/ubifs-media.h
@@ -418,10 +418,13 @@ enum {
  *
  * UBIFS_FLG_BIGLPT: if "big" LPT model is used if set
  * UBIFS_FLG_SPACE_FIXUP: first-mount "fixup" of free space within LEBs needed
+ * UBIFS_FLG_DOUBLE_HASH: store a 32bit cookie in directory entry nodes to
+ *			  support 64bit cookies for lookups by hash
  */
 enum {
 	UBIFS_FLG_BIGLPT = 0x02,
 	UBIFS_FLG_SPACE_FIXUP = 0x04,
+	UBIFS_FLG_DOUBLE_HASH = 0x08,
 };
 
 /**
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 294e4047bcc0..59d55887b3d8 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -1014,6 +1014,7 @@ struct ubifs_debug_info;
  *
  * @big_lpt: flag that LPT is too big to write whole during commit
  * @space_fixup: flag indicating that free space in LEBs needs to be cleaned up
+ * @double_hash: flag indicating that we can do lookups by hash
  * @no_chk_data_crc: do not check CRCs when reading data nodes (except during
  *                   recovery)
  * @bulk_read: enable bulk-reads
@@ -1256,6 +1257,7 @@ struct ubifs_info {
 
 	unsigned int big_lpt:1;
 	unsigned int space_fixup:1;
+	unsigned int double_hash:1;
 	unsigned int no_chk_data_crc:1;
 	unsigned int bulk_read:1;
 	unsigned int default_compr:2;
-- 
2.7.3



From richard at nod.at  Fri Oct 21 05:48:40 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 14:48:40 +0200
Subject: [PATCH 25/26] ubifs: Implement UBIFS_FLG_ENCRYPTION
In-Reply-To: <1477054121-10198-1-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
Message-ID: <1477054121-10198-26-git-send-email-richard@nod.at>

This feature flag indicates that the filesystem contains encrypted
files.

Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/ubifs/ioctl.c       |  5 +++++
 fs/ubifs/sb.c          | 40 ++++++++++++++++++++++++++++++++++++++++
 fs/ubifs/ubifs-media.h |  2 ++
 fs/ubifs/ubifs.h       |  3 +++
 4 files changed, 50 insertions(+)

diff --git a/fs/ubifs/ioctl.c b/fs/ubifs/ioctl.c
index 6bb5b35050de..3d10f5525274 100644
--- a/fs/ubifs/ioctl.c
+++ b/fs/ubifs/ioctl.c
@@ -183,6 +183,7 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 	}
 	case FS_IOC_SET_ENCRYPTION_POLICY: {
 #ifdef CONFIG_UBIFS_FS_ENCRYPTION
+		struct ubifs_info *c = inode->i_sb->s_fs_info;
 		struct fscrypt_policy policy;
 
 		if (copy_from_user(&policy,
@@ -190,6 +191,10 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 				   sizeof(policy)))
 			return -EFAULT;
 
+		err = ubifs_enable_encryption(c);
+		if (err)
+			return err;
+
 		err = fscrypt_process_policy(file, &policy);
 
 		return err;
diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c
index 4a2b4c361587..54cef70ea16f 100644
--- a/fs/ubifs/sb.c
+++ b/fs/ubifs/sb.c
@@ -622,6 +622,16 @@ int ubifs_read_superblock(struct ubifs_info *c)
 	c->big_lpt = !!(sup_flags & UBIFS_FLG_BIGLPT);
 	c->space_fixup = !!(sup_flags & UBIFS_FLG_SPACE_FIXUP);
 	c->double_hash = !!(sup_flags & UBIFS_FLG_DOUBLE_HASH);
+	c->encrypted = !!(sup_flags & UBIFS_FLG_ENCRYPTION);
+
+#ifndef CONFIG_UBIFS_FS_ENCRYPTION
+	if (c->encrypted) {
+		ubifs_err(c, "file system contains encrypted files but UBIFS"
+			     " was built without crypto support.");
+		err = -EINVAL;
+		goto out;
+	}
+#endif
 
 	/* Automatically increase file system size to the maximum size */
 	c->old_leb_cnt = c->leb_cnt;
@@ -809,3 +819,33 @@ int ubifs_fixup_free_space(struct ubifs_info *c)
 	ubifs_msg(c, "free space fixup complete");
 	return err;
 }
+
+int ubifs_enable_encryption(struct ubifs_info *c)
+{
+	int err;
+	struct ubifs_sb_node *sup;
+
+	if (c->encrypted)
+		return 0;
+
+	if (c->ro_mount || c->ro_media)
+		return -EROFS;
+
+	if (c->fmt_version < 5) {
+		ubifs_err(c, "on-flash format version 5 is needed for encryption");
+		return -EINVAL;
+	}
+
+	sup = ubifs_read_sb_node(c);
+	if (IS_ERR(sup))
+		return PTR_ERR(sup);
+
+	sup->flags |= cpu_to_le32(UBIFS_FLG_ENCRYPTION);
+
+	err = ubifs_write_sb_node(c, sup);
+	if (!err)
+		c->encrypted = 1;
+	kfree(sup);
+
+	return err;
+}
diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h
index 0cbdc6b70a00..bdc7935a5e41 100644
--- a/fs/ubifs/ubifs-media.h
+++ b/fs/ubifs/ubifs-media.h
@@ -420,11 +420,13 @@ enum {
  * UBIFS_FLG_SPACE_FIXUP: first-mount "fixup" of free space within LEBs needed
  * UBIFS_FLG_DOUBLE_HASH: store a 32bit cookie in directory entry nodes to
  *			  support 64bit cookies for lookups by hash
+ * UBIFS_FLG_ENCRYPTION: this filesystem contains encrypted files
  */
 enum {
 	UBIFS_FLG_BIGLPT = 0x02,
 	UBIFS_FLG_SPACE_FIXUP = 0x04,
 	UBIFS_FLG_DOUBLE_HASH = 0x08,
+	UBIFS_FLG_ENCRYPTION = 0x10,
 };
 
 /**
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 59d55887b3d8..85e2929aa6db 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -1015,6 +1015,7 @@ struct ubifs_debug_info;
  * @big_lpt: flag that LPT is too big to write whole during commit
  * @space_fixup: flag indicating that free space in LEBs needs to be cleaned up
  * @double_hash: flag indicating that we can do lookups by hash
+ * @encrypted: flag indicating that this file system contains encrypted files
  * @no_chk_data_crc: do not check CRCs when reading data nodes (except during
  *                   recovery)
  * @bulk_read: enable bulk-reads
@@ -1258,6 +1259,7 @@ struct ubifs_info {
 	unsigned int big_lpt:1;
 	unsigned int space_fixup:1;
 	unsigned int double_hash:1;
+	unsigned int encrypted:1;
 	unsigned int no_chk_data_crc:1;
 	unsigned int bulk_read:1;
 	unsigned int default_compr:2;
@@ -1651,6 +1653,7 @@ int ubifs_read_superblock(struct ubifs_info *c);
 struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c);
 int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup);
 int ubifs_fixup_free_space(struct ubifs_info *c);
+int ubifs_enable_encryption(struct ubifs_info *c);
 
 /* replay.c */
 int ubifs_validate_entry(struct ubifs_info *c,
-- 
2.7.3



From richard at nod.at  Fri Oct 21 05:48:33 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 14:48:33 +0200
Subject: [PATCH 18/26] ubifs: Constify struct inode pointer in
 ubifs_crypt_is_encrypted()
In-Reply-To: <1477054121-10198-1-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
Message-ID: <1477054121-10198-19-git-send-email-richard@nod.at>

...and provide a non const variant for fscrypto

Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/ubifs/crypto.c | 2 +-
 fs/ubifs/ubifs.h  | 7 ++++++-
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/fs/ubifs/crypto.c b/fs/ubifs/crypto.c
index 160c31479e0c..d19a097435f0 100644
--- a/fs/ubifs/crypto.c
+++ b/fs/ubifs/crypto.c
@@ -38,7 +38,7 @@ static int ubifs_key_prefix(struct inode *inode, u8 **key)
 struct fscrypt_operations ubifs_crypt_operations = {
 	.get_context		= ubifs_crypt_get_context,
 	.set_context		= ubifs_crypt_set_context,
-	.is_encrypted		= ubifs_crypt_is_encrypted,
+	.is_encrypted		= __ubifs_crypt_is_encrypted,
 	.empty_dir		= ubifs_crypt_empty_dir,
 	.max_namelen		= ubifs_crypt_max_namelen,
 	.key_prefix		= ubifs_key_prefix,
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 6c56a08afcd7..456f22aed35c 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -1816,13 +1816,18 @@ extern struct fscrypt_operations ubifs_crypt_operations;
 #define fscrypt_fname_usr_to_disk       fscrypt_notsupp_fname_usr_to_disk
 #endif
 
-static inline bool ubifs_crypt_is_encrypted(struct inode *inode)
+static inline bool __ubifs_crypt_is_encrypted(struct inode *inode)
 {
 	struct ubifs_inode *ui = ubifs_inode(inode);
 
 	return ui->flags & UBIFS_CRYPT_FL;
 }
 
+static inline bool ubifs_crypt_is_encrypted(const struct inode *inode)
+{
+	return __ubifs_crypt_is_encrypted((struct inode *)inode);
+}
+
 /* Normal UBIFS messages */
 __printf(2, 3)
 void ubifs_msg(const struct ubifs_info *c, const char *fmt, ...);
-- 
2.7.3



From richard at nod.at  Fri Oct 21 05:48:36 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 14:48:36 +0200
Subject: [PATCH 21/26] ubifs: Rename tnc_read_node_nm
In-Reply-To: <1477054121-10198-1-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
Message-ID: <1477054121-10198-22-git-send-email-richard@nod.at>

tnc_read_hashed_node() is a better name since we read a node
by a given hash, not a name.

Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/ubifs/tnc.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c
index 0d0030461cb4..0d751297873e 100644
--- a/fs/ubifs/tnc.c
+++ b/fs/ubifs/tnc.c
@@ -378,7 +378,7 @@ static void lnc_free(struct ubifs_zbranch *zbr)
 }
 
 /**
- * tnc_read_node_nm - read a "hashed" leaf node.
+ * tnc_read_hashed_node - read a "hashed" leaf node.
  * @c: UBIFS file-system description object
  * @zbr: key and position of the node
  * @node: node is returned here
@@ -388,8 +388,8 @@ static void lnc_free(struct ubifs_zbranch *zbr)
  * added to LNC. Returns zero in case of success or a negative negative error
  * code in case of failure.
  */
-static int tnc_read_node_nm(struct ubifs_info *c, struct ubifs_zbranch *zbr,
-			    void *node)
+static int tnc_read_hashed_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+				void *node)
 {
 	int err;
 
@@ -1454,7 +1454,7 @@ again:
 		 * In this case the leaf node cache gets used, so we pass the
 		 * address of the zbranch and keep the mutex locked
 		 */
-		err = tnc_read_node_nm(c, zt, node);
+		err = tnc_read_hashed_node(c, zt, node);
 		goto out;
 	}
 	if (safely) {
@@ -1817,7 +1817,7 @@ static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
 		goto out_unlock;
 	}
 
-	err = tnc_read_node_nm(c, &znode->zbranch[n], node);
+	err = tnc_read_hashed_node(c, &znode->zbranch[n], node);
 
 out_unlock:
 	mutex_unlock(&c->tnc_mutex);
@@ -2815,7 +2815,7 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
 		goto out_free;
 	}
 
-	err = tnc_read_node_nm(c, zbr, dent);
+	err = tnc_read_hashed_node(c, zbr, dent);
 	if (unlikely(err))
 		goto out_free;
 
-- 
2.7.3



From richard at nod.at  Fri Oct 21 05:48:30 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 14:48:30 +0200
Subject: [PATCH 15/26] ubifs: Implement encrypt/decrypt for all IO
In-Reply-To: <1477054121-10198-1-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
Message-ID: <1477054121-10198-16-git-send-email-richard@nod.at>

Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/ubifs/file.c    |  36 ++++++++++++++++++
 fs/ubifs/journal.c | 105 +++++++++++++++++++++++++++++++++++++++++++----------
 fs/ubifs/super.c   |   6 ++-
 fs/ubifs/ubifs.h   |   6 +++
 4 files changed, 131 insertions(+), 22 deletions(-)

diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index bd0049788e24..60e089d50c82 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -78,6 +78,24 @@ static int read_block(struct inode *inode, void *addr, unsigned int block,
 		goto dump;
 
 	dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
+
+	if (ubifs_crypt_is_encrypted(inode)) {
+		int clen = le16_to_cpu(dn->compr_size);
+
+		if (clen <= 0 || clen > UBIFS_BLOCK_SIZE || clen > dlen)
+			goto dump;
+
+		ubifs_assert(dlen <= UBIFS_BLOCK_SIZE);
+		err = fscrypt_decrypt_buffer(inode, &dn->data, &dn->data, dlen, block, GFP_NOFS);
+		if (err) {
+			ubifs_err(c, "fscrypt_decrypt_buffer failed: %i", err);
+			return err;
+		}
+
+		ubifs_assert(clen <= dlen);
+		dlen = clen;
+	}
+
 	out_len = UBIFS_BLOCK_SIZE;
 	err = ubifs_decompress(c, &dn->data, dlen, addr, &out_len,
 			       le16_to_cpu(dn->compr_type));
@@ -650,6 +668,24 @@ static int populate_page(struct ubifs_info *c, struct page *page,
 
 			dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
 			out_len = UBIFS_BLOCK_SIZE;
+
+			if (ubifs_crypt_is_encrypted(inode)) {
+				int clen = le16_to_cpu(dn->compr_size);
+
+				if (clen <= 0 || clen > UBIFS_BLOCK_SIZE || clen > dlen)
+					goto out_err;
+
+				ubifs_assert(dlen <= UBIFS_BLOCK_SIZE);
+				err = fscrypt_decrypt_buffer(inode, &dn->data, &dn->data, dlen, page_block, GFP_NOFS);
+				if (err) {
+					ubifs_err(c, "fscrypt_decrypt_buffer failed: %i", err);
+					goto out_err;
+				}
+
+				ubifs_assert(clen <= dlen);
+				dlen = clen;
+			}
+
 			err = ubifs_decompress(c, &dn->data, dlen, addr, &out_len,
 					       le16_to_cpu(dn->compr_type));
 			if (err || len != out_len)
diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c
index a643de4e3d91..da694e520ec8 100644
--- a/fs/ubifs/journal.c
+++ b/fs/ubifs/journal.c
@@ -691,11 +691,15 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
 	int err, lnum, offs, compr_type, out_len;
 	int dlen = COMPRESSED_DATA_NODE_BUF_SZ, allocated = 1;
 	struct ubifs_inode *ui = ubifs_inode(inode);
+	bool encrypted = ubifs_crypt_is_encrypted(inode);
 
 	dbg_jnlk(key, "ino %lu, blk %u, len %d, key ",
 		(unsigned long)key_inum(c, key), key_block(c, key), len);
 	ubifs_assert(len <= UBIFS_BLOCK_SIZE);
 
+	if (encrypted)
+		dlen += UBIFS_CIPHER_BLOCK_SIZE;
+
 	data = kmalloc(dlen, GFP_NOFS | __GFP_NOWARN);
 	if (!data) {
 		/*
@@ -724,6 +728,26 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
 	ubifs_compress(c, buf, len, &data->data, &out_len, &compr_type);
 	ubifs_assert(out_len <= UBIFS_BLOCK_SIZE);
 
+	if (encrypted) {
+		void *p = &data->data;
+		int plen = round_up(out_len, UBIFS_CIPHER_BLOCK_SIZE);
+
+		data->compr_size = cpu_to_le16(out_len);
+
+		if (plen != out_len) {
+			memset(p + out_len, 0, plen - out_len);
+			out_len = plen;
+		}
+
+		err = fscrypt_encrypt_buffer(inode, &data->data, &data->data, out_len, key_block(c, key), GFP_NOFS);
+		if (err) {
+			ubifs_err(c, "fscrypt_encrypt_buffer failed: %i", err);
+			goto out_free;
+		}
+	} else {
+		data->compr_size = 0;
+	}
+
 	dlen = UBIFS_DATA_NODE_SZ + out_len;
 	data->compr_type = cpu_to_le16(compr_type);
 
@@ -1083,31 +1107,79 @@ out_free:
 }
 
 /**
- * recomp_data_node - re-compress a truncated data node.
+ * truncate_data_node - re-compress/encrypt a truncated data node.
+ * @c: UBIFS file-system description object
+ * @inode: inode which referes to the data node
+ * @block: data block number
  * @dn: data node to re-compress
  * @new_len: new length
  *
  * This function is used when an inode is truncated and the last data node of
- * the inode has to be re-compressed and re-written.
+ * the inode has to be re-compressed/encrypted and re-written.
  */
-static int recomp_data_node(const struct ubifs_info *c,
-			    struct ubifs_data_node *dn, int *new_len)
+static int truncate_data_node(const struct ubifs_info *c, struct inode *inode,
+			      unsigned int block, struct ubifs_data_node *dn,
+			      int *new_len)
 {
 	void *buf;
-	int err, len, compr_type, out_len;
+	int err, dlen, compr_type, out_len, old_dlen;
 
 	out_len = le32_to_cpu(dn->size);
 	buf = kmalloc(out_len * WORST_COMPR_FACTOR, GFP_NOFS);
 	if (!buf)
 		return -ENOMEM;
 
-	len = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
+	dlen = old_dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
 	compr_type = le16_to_cpu(dn->compr_type);
-	err = ubifs_decompress(c, &dn->data, len, buf, &out_len, compr_type);
-	if (err)
-		goto out;
 
-	ubifs_compress(c, buf, *new_len, &dn->data, &out_len, &compr_type);
+	if (ubifs_crypt_is_encrypted(inode)) {
+		int clen = le16_to_cpu(dn->compr_size);
+
+		if (clen <= 0 || clen > UBIFS_BLOCK_SIZE || clen > dlen) {
+			ubifs_err(c, "bad compr_size: %i", clen);
+			err = -EINVAL;
+			goto out;
+		}
+
+		err = fscrypt_decrypt_buffer(inode, &dn->data, &dn->data, dlen, block, GFP_NOFS);
+		if (err) {
+			ubifs_err(c, "fscrypt_decrypt_buffer failed: %i", err);
+			goto out;
+		}
+
+		ubifs_assert(clen <= dlen);
+		dlen = clen;
+	}
+
+	if (compr_type != UBIFS_COMPR_NONE) {
+		err = ubifs_decompress(c, &dn->data, dlen, buf, &out_len, compr_type);
+		if (err)
+			goto out;
+
+		ubifs_compress(c, buf, *new_len, &dn->data, &out_len, &compr_type);
+	}
+
+	if (ubifs_crypt_is_encrypted(inode)) {
+		void *p = &dn->data;
+		int plen = round_up(out_len, UBIFS_CIPHER_BLOCK_SIZE);
+
+		ubifs_assert(old_dlen >= plen);
+		dn->compr_size = cpu_to_le16(out_len);
+
+		if (plen != out_len) {
+			memset(p + out_len, 0, plen - out_len);
+			out_len = plen;
+		}
+
+		err = fscrypt_encrypt_buffer(inode, &dn->data, &dn->data, out_len, block, GFP_NOFS);
+		if (err) {
+			ubifs_msg(c, "fscrypt_encrypt_buffer failed: %i", err);
+			goto out;
+		}
+	} else {
+		dn->compr_size = 0;
+	}
+
 	ubifs_assert(out_len <= UBIFS_BLOCK_SIZE);
 	dn->compr_type = cpu_to_le16(compr_type);
 	dn->size = cpu_to_le32(*new_len);
@@ -1179,16 +1251,9 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
 			if (le32_to_cpu(dn->size) <= dlen)
 				dlen = 0; /* Nothing to do */
 			else {
-				int compr_type = le16_to_cpu(dn->compr_type);
-
-				if (compr_type != UBIFS_COMPR_NONE) {
-					err = recomp_data_node(c, dn, &dlen);
-					if (err)
-						goto out_free;
-				} else {
-					dn->size = cpu_to_le32(dlen);
-					dlen += UBIFS_DATA_NODE_SZ;
-				}
+				err = truncate_data_node(c, inode, blk, dn, &dlen);
+				if (err)
+					goto out_free;
 			}
 		}
 	}
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index a31222947265..ae25c908fbe5 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -1210,7 +1210,8 @@ static int mount_ubifs(struct ubifs_info *c)
 		bu_init(c);
 
 	if (!c->ro_mount) {
-		c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ,
+		c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ + \
+					       UBIFS_CIPHER_BLOCK_SIZE,
 					       GFP_KERNEL);
 		if (!c->write_reserve_buf)
 			goto out_free;
@@ -1623,7 +1624,8 @@ static int ubifs_remount_rw(struct ubifs_info *c)
 		goto out;
 	}
 
-	c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ, GFP_KERNEL);
+	c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ + \
+				       UBIFS_CIPHER_BLOCK_SIZE, GFP_KERNEL);
 	if (!c->write_reserve_buf) {
 		err = -ENOMEM;
 		goto out;
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 63dd027727ca..6c56a08afcd7 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -139,6 +139,12 @@
  */
 #define WORST_COMPR_FACTOR 2
 
+#ifdef CONFIG_UBIFS_FS_ENCRYPTION
+#define UBIFS_CIPHER_BLOCK_SIZE FS_CRYPTO_BLOCK_SIZE
+#else
+#define UBIFS_CIPHER_BLOCK_SIZE 0
+#endif
+
 /*
  * How much memory is needed for a buffer where we compress a data node.
  */
-- 
2.7.3



From richard at nod.at  Fri Oct 21 05:48:37 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 14:48:37 +0200
Subject: [PATCH 22/26] ubifs: Add full hash lookup support
In-Reply-To: <1477054121-10198-1-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
Message-ID: <1477054121-10198-23-git-send-email-richard@nod.at>

UBIFS stores a 32bit hash of every file, for traditional lookups by name
this scheme is fine since UBIFS can first try to find the file by the
hash of the filename and upon collisions it can walk through all entries
with the same hash and do a string compare.
When filesnames are encrypted fscrypto will ask the filesystem for a
unique cookie, based on this cookie the filesystem has to be able to
locate the target file again. With 32bit hashes this is impossible
because the chance for collisions is very high. Do deal with that we
store a 32bit cookie directly in the UBIFS directory entry node such
that we get a 64bit cookie (32bit from filename hash and the dent
cookie). For a lookup by hash UBIFS finds the entry by the first 32bit
and then compares the dent cookie. If it does not match, it has to do a
linear search of the whole directory and compares all dent cookies until
the correct entry is found.

Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/ubifs/dir.c         |  7 +++-
 fs/ubifs/journal.c     |  1 -
 fs/ubifs/tnc.c         | 99 +++++++++++++++++++++++++++++++++++++++++++++++++-
 fs/ubifs/ubifs-media.h |  5 ++-
 fs/ubifs/ubifs.h       |  2 +
 5 files changed, 107 insertions(+), 7 deletions(-)

diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index 2f33be5ca57c..4b2db102a0a9 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -253,7 +253,7 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
 		ubifs_assert(fname_len(&nm) == 0);
 		ubifs_assert(fname_name(&nm) == NULL);
 		dent_key_init_hash(c, &key, dir->i_ino, nm.hash);
-		err = ubifs_tnc_lookup(c, &key, dent);
+		err = ubifs_tnc_lookup_dh(c, &key, dent, nm.minor_hash);
 	} else {
 		dent_key_init(c, &key, dir->i_ino, &nm);
 		err = ubifs_tnc_lookup_nm(c, &key, dent, &nm);
@@ -521,7 +521,10 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
 		if (encrypted) {
 			fstr.len = fstr_real_len;
 
-			err = fscrypt_fname_disk_to_usr(dir, key_hash_flash(c, &dent->key), 0, &nm.disk_name, &fstr);
+			err = fscrypt_fname_disk_to_usr(dir, key_hash_flash(c,
+							&dent->key),
+							le32_to_cpu(dent->cookie),
+							&nm.disk_name, &fstr);
 			if (err < 0)
 				goto out;
 		} else {
diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c
index eb1cef8032e7..50696c6e0ae2 100644
--- a/fs/ubifs/journal.c
+++ b/fs/ubifs/journal.c
@@ -78,7 +78,6 @@ static inline void zero_ino_node_unused(struct ubifs_ino_node *ino)
 static inline void zero_dent_node_unused(struct ubifs_dent_node *dent)
 {
 	dent->padding1 = 0;
-	memset(dent->padding2, 0, 4);
 }
 
 /**
diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c
index 0d751297873e..1eaf994addb4 100644
--- a/fs/ubifs/tnc.c
+++ b/fs/ubifs/tnc.c
@@ -1783,7 +1783,7 @@ int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu)
  * @node: the node is returned here
  * @nm: node name
  *
- * This function look up and reads a node which contains name hash in the key.
+ * This function looks up and reads a node which contains name hash in the key.
  * Since the hash may have collisions, there may be many nodes with the same
  * key, so we have to sequentially look to all of them until the needed one is
  * found. This function returns zero in case of success, %-ENOENT if the node
@@ -1831,7 +1831,7 @@ out_unlock:
  * @node: the node is returned here
  * @nm: node name
  *
- * This function look up and reads a node which contains name hash in the key.
+ * This function looks up and reads a node which contains name hash in the key.
  * Since the hash may have collisions, there may be many nodes with the same
  * key, so we have to sequentially look to all of them until the needed one is
  * found. This function returns zero in case of success, %-ENOENT if the node
@@ -1859,9 +1859,104 @@ int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
 	 * Unluckily, there are hash collisions and we have to iterate over
 	 * them look at each direntry with colliding name hash sequentially.
 	 */
+
 	return do_lookup_nm(c, key, node, nm);
 }
 
+static int do_lookup_dh(struct ubifs_info *c, const union ubifs_key *key,
+			struct ubifs_dent_node *dent, uint32_t cookie)
+{
+	int n, err, type = key_type(c, key);
+	struct ubifs_znode *znode;
+	struct ubifs_zbranch *zbr;
+	union ubifs_key *cur_key, start_key;
+
+	ubifs_assert(is_hash_key(c, key));
+
+	lowest_dent_key(c, &start_key, key_inum(c, key));
+	cur_key = &start_key;
+
+	for (;;) {
+		mutex_lock(&c->tnc_mutex);
+
+		err = ubifs_lookup_level0(c, cur_key, &znode, &n);
+		if (unlikely(err < 0))
+			goto out_unlock;
+
+		if (!err) {
+			err = tnc_next(c, &znode, &n);
+			if (err)
+				goto out_unlock;
+		}
+
+		zbr = &znode->zbranch[n];
+		cur_key = &zbr->key;
+
+		if (key_inum(c, cur_key) != key_inum(c, key) ||
+		    key_type(c, cur_key) != type) {
+			err = -ENOENT;
+			goto out_unlock;
+		}
+
+		err = tnc_read_hashed_node(c, zbr, dent);
+		if (err)
+			goto out_unlock;
+
+		if (key_hash(c, key) == key_hash(c, cur_key) &&
+		    le32_to_cpu(dent->cookie) == cookie) {
+			/* We found the entry. :-) */
+			err = 0;
+			goto out_unlock;
+		}
+
+		mutex_unlock(&c->tnc_mutex);
+	}
+
+	ubifs_assert(0);
+
+out_unlock:
+	mutex_unlock(&c->tnc_mutex);
+	return err;
+}
+
+/**
+ * ubifs_tnc_lookup_dh - look up a "double hashed" node.
+ * @c: UBIFS file-system description object
+ * @key: node key to lookup
+ * @node: the node is returned here
+ * @cookie: node cookie for collision resolution
+ *
+ * This function looks up and reads a node which contains name hash in the key.
+ * Since the hash may have collisions, there may be many nodes with the same
+ * key, so we have to sequentially look to all of them until the needed one
+ * with the same cookie value is found.
+ * This function returns zero in case of success, %-ENOENT if the node
+ * was not found, and a negative error code in case of failure.
+ */
+int ubifs_tnc_lookup_dh(struct ubifs_info *c, const union ubifs_key *key,
+			void *node, uint32_t cookie)
+{
+	int err;
+	const struct ubifs_dent_node *dent = node;
+
+	/*
+	 * We assume that in most of the cases there are no name collisions and
+	 * 'ubifs_tnc_lookup()' returns us the right direntry.
+	 */
+	err = ubifs_tnc_lookup(c, key, node);
+	if (err)
+		return err;
+
+	if (le32_to_cpu(dent->cookie) == cookie)
+		return 0;
+
+	/*
+	 * Unluckily, there are hash collisions and we have to iterate over
+	 * them look at each direntry with colliding name hash sequentially.
+	 */
+	return do_lookup_dh(c, key, node, cookie);
+}
+
 /**
  * correct_parent_keys - correct parent znodes' keys.
  * @c: UBIFS file-system description object
diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h
index e46331dcca4c..249124d9a801 100644
--- a/fs/ubifs/ubifs-media.h
+++ b/fs/ubifs/ubifs-media.h
@@ -530,7 +530,8 @@ struct ubifs_ino_node {
  * @padding1: reserved for future, zeroes
  * @type: type of the target inode (%UBIFS_ITYPE_REG, %UBIFS_ITYPE_DIR, etc)
  * @nlen: name length
- * @padding2: reserved for future, zeroes
+ * @cookie: A 32bits random number, used to construct a 64bits
+ *          identifier.
  * @name: zero-terminated name
  *
  * Note, do not forget to amend 'zero_dent_node_unused()' function when
@@ -543,7 +544,7 @@ struct ubifs_dent_node {
 	__u8 padding1;
 	__u8 type;
 	__le16 nlen;
-	__u8 padding2[4]; /* Watch 'zero_dent_node_unused()' if changing! */
+	__le32 cookie;
 	__u8 name[];
 } __packed;
 
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index f91ef52a4523..3f68b26b120f 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -1573,6 +1573,8 @@ int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
 			struct ubifs_znode **zn, int *n);
 int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
 			void *node, const struct fscrypt_name *nm);
+int ubifs_tnc_lookup_dh(struct ubifs_info *c, const union ubifs_key *key,
+			void *node, uint32_t secondary_hash);
 int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key,
 		     void *node, int *lnum, int *offs);
 int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
-- 
2.7.3



From cyrille.pitchen at atmel.com  Fri Oct 21 05:50:12 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Fri, 21 Oct 2016 14:50:12 +0200
Subject: [PATCH] mtd: spi-nor: fixed spansion quad enable
In-Reply-To: <F6CD090A69E64C4289DC608E1C5D20242544AEF1@DE08W1305.global.ds.honeywell.com>
References: <1476971026-9665-1-git-send-email-joel.esponde@honeywell.com>
 <56670303-e8e8-fb2c-e043-035c566f347c@atmel.com>
 <F6CD090A69E64C4289DC608E1C5D20242544AEF1@DE08W1305.global.ds.honeywell.com>
Message-ID: <f45e1845-573f-d0b7-0f23-abd035f25945@atmel.com>

Hi Jo?l,

Le 21/10/2016 ? 12:37, Esponde, Joel a ?crit :
> Hi Cyrille,
> 
> First, thanks for your comments !
> Please, see below mines.
> 
>> -----Message d'origine-----
>> De : Cyrille Pitchen [mailto:cyrille.pitchen at atmel.com]
>> Envoy? : jeudi 20 octobre 2016 17:23
>> ? : Esponde, Joel <Joel.Esponde at Honeywell.com>; linux-
>> mtd at lists.infradead.org
>> Objet : Re: [PATCH] mtd: spi-nor: fixed spansion quad enable
>>
>> Hi Jo?l,
>>
>> Le 20/10/2016 ? 15:43, Jo?l Esponde a ?crit :
>>> With the S25FL127S nor flash part, each writing to the configuration register
>> takes hundreds of ms. During that  time, no more accesses to the flash
>> should be done (even reads).
>>>
>>> This commit adds:
>>> - a pre check of the quad enable bit to avoid a useless and time
>>> consuming writing to the flash,
>>> - a wait loop after the register writing until the flash finishes its work.
>>>
>>> This issue could make rootfs mounting fail when the latter was done too
>> much closely to this quad enable bit setting step. And in this case, a driver as
>> UBIFS may try to recover the filesystem and may broke it completely.
>>> ---
>>>  drivers/mtd/spi-nor/spi-nor.c | 31 +++++++++++++++++++++++++++----
>>>  1 file changed, 27 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/drivers/mtd/spi-nor/spi-nor.c
>>> b/drivers/mtd/spi-nor/spi-nor.c index d0fc165..df43cd7 100644
>>> --- a/drivers/mtd/spi-nor/spi-nor.c
>>> +++ b/drivers/mtd/spi-nor/spi-nor.c
>>> @@ -1246,18 +1246,41 @@ static int spansion_quad_enable(struct spi_nor
>> *nor)
>>>  	int ret;
>>>  	int quad_en = CR_QUAD_EN_SPAN << 8;
>>>
>>> +	/* check quad enable bit
>>> +	 * as S25FL127S takes 200 ms to execute each write of SR & CR
>>> +	 * registers even if data is the same, write step will be shorted
>>> +	 * if not needed
>>> +	 */
>>> +	ret = read_cr(nor);
>>
>> Sorry but the Read Configuration Register (35h) command is not supported
>> by all Spansion (or Spansion-like) memories.
> 
> I have a doubt here, if this is really the case, why read_cr() is already called at the end of the current implementation of the spansion_quad_enable() function to check that quad enable bit is set? 
> 

That's a very good remark and I think the reason is that the current
implementation of spansion_quad_enable() suffers from a bug but this one is
almost harmless:

I assume there is pull-up resistor on the MISO line: spansion_quad_enable()
sends a 35h command, which is not supported hence ignored by some memories,
then it reads a 1-byte value of FFh due to the pull-up so we pass the test
which checks that the Quad Enable bit has successfully been set.

Then if we now add the same test before sending the Write Status (01h) command
with 2 bytes (SR1 then CR/SR2), we also read a FFh value for the Configuration
Register hence we skip the Write Status command because we think the Quad
Enable bit has already been set but if we are using a brand new memory still
using its factory settings the Quad Enable has never been set and won't be set
since we now skip the Write Status command.

I think this what currently happens but I need to check with one of my memory
samples if I can find one which doesn't support the Read CR command but I
not sure to have such a sample...

spansion_quad_enable() is used by QSPI memories from some manufacturers other
than Spansion.

>> For more details, please refer to the JEDEC JESD216B specification, especially
>> the part dealing with the "Quad Enable Requirements". An extract of this
>> specification can also be found in this patch:
>> https://patchwork.ozlabs.org/patch/678408/
>>
>> Please have a look at values 001b, 100b and 101b for the bits[22:20] of the
>> 15th DWORD.
>>
>> I think your patch is likely to introduce a regression on some old memory
>> parts.
>>
>> However, *if* your S25FL127S memory implements the SFDP tables
>> correctly, bits[22:20] of the 15th DWORD should be set to 101b, hence using
>> SFDP patch above should fix the issue:
>> spansion_new_quad_enable() will be called instead of the current
>> spansion_quad_enable(). This new function adds the very same test on the
>> Quad Enable bit as your patch does.
>>
>> If you want to test the SFDP patch, you will need to apply the whole series
>> which introduces some improvement on QSPI memory support:
>> http://lists.infradead.org/pipermail/linux-mtd/2016-October/069554.html
> 
> Your patch using SFDP to dynamically manage memories seems really great (from a feature point of view, I am not yet able to have an opinion on the implementation...).
> 
>>
>> I'm just cautious with Spansion memories: I tested one sample, and I guess it
>> was a S25FL127S, which claimed to be compliant with JESD216 rev B (minor 6)
>> but words after the 9th one were all 0xffffffff.
>> JESD216 (minor 0) describes only 9 DWORDs in the Basic Flash Parameter
>> Table
>> JESD216 rev A (minor 5) introduces 7 new DWORDS, hence 16 DWORDS in the
>> (BFPT).
>> the 15th DWORD provides the Quad Enable Requirements, which describes
>> the procedure to set the Quad Enable bit.
>>
>> If the BFPT of your S25FL127S is incomplete but the memory still claiming to
>> be
>> JESD216 rev B compliant, neither spansion_quad_enable() nor
>> spansion_new_quad_enable() would be called. Since the Quad Enable bit is
>> non-volatile on Spansion memories, it will work if the bit as already been set
>> before.
>>
> 
> See below for code that should be IMO added because of the non-volatibility of spansion memories.
> 
>>> +	if (ret < 0) {
>>> +		dev_err(nor->dev, "error %d reading CR\n", ret);
>>> +		return ret;
>>> +	}
>>> +	if (ret & CR_QUAD_EN_SPAN) {
>>> +		/* quad enable bit is already set */
>>> +		return 0;
>>> +	}
>>> +
>>> +	/* set SR & CR, enable quad I/O */
>>>  	write_enable(nor);
>>>
>>>  	ret = write_sr_cr(nor, quad_en);
>>>  	if (ret < 0) {
>>> -		dev_err(nor->dev,
>>> -			"error while writing configuration register\n");
>>> +		dev_err(nor->dev, "error while writing SR and CR
>> registers\n");
>>>  		return -EINVAL;
>>>  	}
>>>
>>> -	/* read back and check it */
>>> +	ret = spi_nor_wait_till_ready(nor);
>>> +	if (ret)
>>> +		return ret;
>>> +
> 
> I think that this wait is required with every memories that store Quad Enable bit in a non-volatile way.
> I am using today a stripped down kernel with a rootfs based on UBIFS.
> When this bit is set, UBIFS will start reading the memory 100ms after.
> As this bit writing step takes up to 200ms, spansion memory is not ready and UBIFS will fail when trying to read the content of the partition.
> As UBIFS has a recovery mechanism, it will even broke the file system.
> 

I agree with you about adding the spi_nor_wait_till_ready() call. I plan to
add it in my SFDP patch for the spansion_new_quad_enable(), if not done yet.

>>> +	/* read CR and check it */
>>>  	ret = read_cr(nor);
>>> -	if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
>>> +	if (ret < 0) {
>>> +		dev_err(nor->dev, "error %d reading CR\n", ret);
>>> +		return ret;
>>> +	}
> 
> This test on the validity of the returned data may also be useful.
> When negative errors are returned, it is likely that the CR_QUAD_EN_SPAN bit is set, and so, next test may be meaningless...
> 
>>> +	if (!(ret & CR_QUAD_EN_SPAN)) {
>>>  		dev_err(nor->dev, "Spansion Quad bit not set\n");
>>>  		return -EINVAL;
>>>  	}
>>>
> 
> Best regards,
> Jo?l
> 

Best regards,

Cyrille


From richard at nod.at  Fri Oct 21 05:48:31 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 14:48:31 +0200
Subject: [PATCH 16/26] ubifs: Relax checks in ubifs_validate_entry()
In-Reply-To: <1477054121-10198-1-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
Message-ID: <1477054121-10198-17-git-send-email-richard@nod.at>

With encrypted filenames we store raw binary data, doing
string tests is no longer possible.

Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/ubifs/replay.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
index 3ca4540130b5..f02adc49425b 100644
--- a/fs/ubifs/replay.c
+++ b/fs/ubifs/replay.c
@@ -456,7 +456,7 @@ int ubifs_validate_entry(struct ubifs_info *c,
 	if (le32_to_cpu(dent->ch.len) != nlen + UBIFS_DENT_NODE_SZ + 1 ||
 	    dent->type >= UBIFS_ITYPES_CNT ||
 	    nlen > UBIFS_MAX_NLEN || dent->name[nlen] != 0 ||
-	    strnlen(dent->name, nlen) != nlen ||
+	    (key_type == UBIFS_XENT_KEY && strnlen(dent->name, nlen) != nlen) ||
 	    le64_to_cpu(dent->inum) > MAX_INUM) {
 		ubifs_err(c, "bad %s node", key_type == UBIFS_DENT_KEY ?
 			  "directory entry" : "extended attribute entry");
-- 
2.7.3



From richard at nod.at  Fri Oct 21 05:48:34 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 14:48:34 +0200
Subject: [PATCH 19/26] ubifs: Implement encrypted filenames
In-Reply-To: <1477054121-10198-1-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
Message-ID: <1477054121-10198-20-git-send-email-richard@nod.at>

Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/ubifs/debug.c   |  14 +--
 fs/ubifs/dir.c     | 284 +++++++++++++++++++++++++++++++++++++++++++----------
 fs/ubifs/journal.c |  76 +++++++-------
 fs/ubifs/key.h     |  19 ++--
 fs/ubifs/replay.c  |   8 +-
 fs/ubifs/tnc.c     |  54 +++++-----
 fs/ubifs/ubifs.h   |  19 ++--
 fs/ubifs/xattr.c   |  42 ++++----
 8 files changed, 350 insertions(+), 166 deletions(-)

diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c
index 69e287e20732..1e712a364680 100644
--- a/fs/ubifs/debug.c
+++ b/fs/ubifs/debug.c
@@ -233,7 +233,7 @@ static void dump_ch(const struct ubifs_ch *ch)
 void ubifs_dump_inode(struct ubifs_info *c, const struct inode *inode)
 {
 	const struct ubifs_inode *ui = ubifs_inode(inode);
-	struct qstr nm = { .name = NULL };
+	struct fscrypt_name nm = {0};
 	union ubifs_key key;
 	struct ubifs_dent_node *dent, *pdent = NULL;
 	int count = 2;
@@ -289,8 +289,8 @@ void ubifs_dump_inode(struct ubifs_info *c, const struct inode *inode)
 		pr_err("\t%d: %s (%s)\n",
 		       count++, dent->name, get_dent_type(dent->type));
 
-		nm.name = dent->name;
-		nm.len = le16_to_cpu(dent->nlen);
+		fname_name(&nm) = dent->name;
+		fname_len(&nm) = le16_to_cpu(dent->nlen);
 		kfree(pdent);
 		pdent = dent;
 		key_read(c, &dent->key, &key);
@@ -1107,7 +1107,7 @@ int dbg_check_dir(struct ubifs_info *c, const struct inode *dir)
 	unsigned int nlink = 2;
 	union ubifs_key key;
 	struct ubifs_dent_node *dent, *pdent = NULL;
-	struct qstr nm = { .name = NULL };
+	struct fscrypt_name nm = {0};
 	loff_t size = UBIFS_INO_NODE_SZ;
 
 	if (!dbg_is_chk_gen(c))
@@ -1128,9 +1128,9 @@ int dbg_check_dir(struct ubifs_info *c, const struct inode *dir)
 			return err;
 		}
 
-		nm.name = dent->name;
-		nm.len = le16_to_cpu(dent->nlen);
-		size += CALC_DENT_SIZE(nm.len);
+		fname_name(&nm) = dent->name;
+		fname_len(&nm) = le16_to_cpu(dent->nlen);
+		size += CALC_DENT_SIZE(fname_len(&nm));
 		if (dent->type == UBIFS_ITYPE_DIR)
 			nlink += 1;
 		kfree(pdent);
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index 7ee32768ba19..723bae4dec30 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -196,13 +196,13 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
 
 static int dbg_check_name(const struct ubifs_info *c,
 			  const struct ubifs_dent_node *dent,
-			  const struct qstr *nm)
+			  const struct fscrypt_name *nm)
 {
 	if (!dbg_is_chk_gen(c))
 		return 0;
-	if (le16_to_cpu(dent->nlen) != nm->len)
+	if (le16_to_cpu(dent->nlen) != fname_len(nm))
 		return -EINVAL;
-	if (memcmp(dent->name, nm->name, nm->len))
+	if (memcmp(dent->name, fname_name(nm), fname_len(nm)))
 		return -EINVAL;
 	return 0;
 }
@@ -215,6 +215,7 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
 	struct inode *inode = NULL;
 	struct ubifs_dent_node *dent;
 	struct ubifs_info *c = dir->i_sb->s_fs_info;
+	struct fscrypt_name nm;
 
 	dbg_gen("'%pd' in dir ino %lu", dentry, dir->i_ino);
 
@@ -233,27 +234,42 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
 			return ERR_PTR(err);
 	}
 
-	if (dentry->d_name.len > UBIFS_MAX_NLEN)
-		return ERR_PTR(-ENAMETOOLONG);
+	err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm);
+	if (err)
+		return ERR_PTR(err);
+
+	if (fname_len(&nm) > UBIFS_MAX_NLEN) {
+		err = -ENAMETOOLONG;
+		goto out_fname;
+	}
 
 	dent = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS);
-	if (!dent)
-		return ERR_PTR(-ENOMEM);
+	if (!dent) {
+		err = -ENOMEM;
+		goto out_fname;
+	}
 
-	dent_key_init(c, &key, dir->i_ino, &dentry->d_name);
+	if (nm.hash) {
+		ubifs_assert(fname_len(&nm) == 0);
+		ubifs_assert(fname_name(&nm) == NULL);
+		dent_key_init_hash(c, &key, dir->i_ino, nm.hash);
+		err = ubifs_tnc_lookup(c, &key, dent);
+	} else {
+		dent_key_init(c, &key, dir->i_ino, &nm);
+		err = ubifs_tnc_lookup_nm(c, &key, dent, &nm);
+	}
 
-	err = ubifs_tnc_lookup_nm(c, &key, dent, &dentry->d_name);
 	if (err) {
 		if (err == -ENOENT) {
 			dbg_gen("not found");
 			goto done;
 		}
-		goto out;
+		goto out_dent;
 	}
 
-	if (dbg_check_name(c, dent, &dentry->d_name)) {
+	if (dbg_check_name(c, dent, &nm)) {
 		err = -EINVAL;
-		goto out;
+		goto out_dent;
 	}
 
 	inode = ubifs_iget(dir->i_sb, le64_to_cpu(dent->inum));
@@ -266,11 +282,12 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
 		ubifs_err(c, "dead directory entry '%pd', error %d",
 			  dentry, err);
 		ubifs_ro_mode(c, err);
-		goto out;
+		goto out_dent;
 	}
 
 done:
 	kfree(dent);
+	fscrypt_free_filename(&nm);
 	/*
 	 * Note, d_splice_alias() would be required instead if we supported
 	 * NFS.
@@ -278,8 +295,10 @@ done:
 	d_add(dentry, inode);
 	return NULL;
 
-out:
+out_dent:
 	kfree(dent);
+out_fname:
+	fscrypt_free_filename(&nm);
 	return ERR_PTR(err);
 }
 
@@ -288,10 +307,11 @@ static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
 {
 	struct inode *inode;
 	struct ubifs_info *c = dir->i_sb->s_fs_info;
-	int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len);
 	struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
 					.dirtied_ino = 1 };
 	struct ubifs_inode *dir_ui = ubifs_inode(dir);
+	struct fscrypt_name nm;
+	int err, sz_change;
 
 	/*
 	 * Budget request settings: new inode, new direntry, changing the
@@ -305,10 +325,16 @@ static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
 	if (err)
 		return err;
 
+	err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm);
+	if (err)
+		goto out_budg;
+
+	sz_change = CALC_DENT_SIZE(fname_len(&nm));
+
 	inode = ubifs_new_inode(c, dir, mode);
 	if (IS_ERR(inode)) {
 		err = PTR_ERR(inode);
-		goto out_budg;
+		goto out_fname;
 	}
 
 	err = ubifs_init_security(dir, inode, &dentry->d_name);
@@ -319,12 +345,13 @@ static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
 	dir->i_size += sz_change;
 	dir_ui->ui_size = dir->i_size;
 	dir->i_mtime = dir->i_ctime = inode->i_ctime;
-	err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0);
+	err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0);
 	if (err)
 		goto out_cancel;
 	mutex_unlock(&dir_ui->ui_mutex);
 
 	ubifs_release_budget(c, &req);
+	fscrypt_free_filename(&nm);
 	insert_inode_hash(inode);
 	d_instantiate(dentry, inode);
 	return 0;
@@ -336,6 +363,8 @@ out_cancel:
 out_inode:
 	make_bad_inode(inode);
 	iput(inode);
+out_fname:
+	fscrypt_free_filename(&nm);
 out_budg:
 	ubifs_release_budget(c, &req);
 	ubifs_err(c, "cannot create regular file, error %d", err);
@@ -391,21 +420,36 @@ static unsigned int vfs_dent_type(uint8_t type)
  */
 static int ubifs_readdir(struct file *file, struct dir_context *ctx)
 {
-	int err;
-	struct qstr nm;
+	int err, fstr_real_len;
+	struct fscrypt_name nm;
+	struct fscrypt_str fstr = {0};
 	union ubifs_key key;
 	struct ubifs_dent_node *dent;
 	struct inode *dir = file_inode(file);
 	struct ubifs_info *c = dir->i_sb->s_fs_info;
+	bool encrypted = ubifs_crypt_is_encrypted(dir);
 
 	dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, ctx->pos);
 
-	if (ctx->pos > UBIFS_S_KEY_HASH_MASK || ctx->pos == 2)
+	if (ctx->pos > UBIFS_S_KEY_HASH_MASK || ctx->pos == 2) {
 		/*
 		 * The directory was seek'ed to a senseless position or there
 		 * are no more entries.
 		 */
 		return 0;
+	}
+
+	if (encrypted) {
+		err = fscrypt_get_encryption_info(dir);
+		if (err && err != -ENOKEY)
+			return err;
+
+		err = fscrypt_fname_alloc_buffer(dir, UBIFS_MAX_NLEN, &fstr);
+		if (err)
+			return err;
+
+		fstr_real_len = fstr.len;
+	}
 
 	if (file->f_version == 0) {
 		/*
@@ -428,12 +472,15 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
 	/* File positions 0 and 1 correspond to "." and ".." */
 	if (ctx->pos < 2) {
 		ubifs_assert(!file->private_data);
-		if (!dir_emit_dots(file, ctx))
+		if (!dir_emit_dots(file, ctx)) {
+			if (encrypted)
+				fscrypt_fname_free_buffer(&fstr);
 			return 0;
+		}
 
 		/* Find the first entry in TNC and save it */
 		lowest_dent_key(c, &key, dir->i_ino);
-		nm.name = NULL;
+		fname_len(&nm) = 0;
 		dent = ubifs_tnc_next_ent(c, &key, &nm);
 		if (IS_ERR(dent)) {
 			err = PTR_ERR(dent);
@@ -451,7 +498,7 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
 		 * Find the entry corresponding to @ctx->pos or the closest one.
 		 */
 		dent_key_init_hash(c, &key, dir->i_ino, ctx->pos);
-		nm.name = NULL;
+		fname_len(&nm) = 0;
 		dent = ubifs_tnc_next_ent(c, &key, &nm);
 		if (IS_ERR(dent)) {
 			err = PTR_ERR(dent);
@@ -468,15 +515,30 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
 		ubifs_assert(le64_to_cpu(dent->ch.sqnum) >
 			     ubifs_inode(dir)->creat_sqnum);
 
-		nm.len = le16_to_cpu(dent->nlen);
-		if (!dir_emit(ctx, dent->name, nm.len,
+		fname_len(&nm) = le16_to_cpu(dent->nlen);
+		fname_name(&nm) = dent->name;
+
+		if (encrypted) {
+			fstr.len = fstr_real_len;
+
+			err = fscrypt_fname_disk_to_usr(dir, key_hash_flash(c, &dent->key), 0, &nm.disk_name, &fstr);
+			if (err < 0)
+				goto out;
+		} else {
+			fstr.len = fname_len(&nm);
+			fstr.name = fname_name(&nm);
+		}
+
+		if (!dir_emit(ctx, fstr.name, fstr.len,
 			       le64_to_cpu(dent->inum),
-			       vfs_dent_type(dent->type)))
+			       vfs_dent_type(dent->type))) {
+			if (encrypted)
+				fscrypt_fname_free_buffer(&fstr);
 			return 0;
+		}
 
 		/* Switch to the next entry */
 		key_read(c, &dent->key, &key);
-		nm.name = dent->name;
 		dent = ubifs_tnc_next_ent(c, &key, &nm);
 		if (IS_ERR(dent)) {
 			err = PTR_ERR(dent);
@@ -493,6 +555,9 @@ out:
 	kfree(file->private_data);
 	file->private_data = NULL;
 
+	if (encrypted)
+		fscrypt_fname_free_buffer(&fstr);
+
 	if (err != -ENOENT) {
 		ubifs_err(c, "cannot find next direntry, error %d", err);
 		return err;
@@ -547,6 +612,7 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
 	int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len);
 	struct ubifs_budget_req req = { .new_dent = 1, .dirtied_ino = 2,
 				.dirtied_ino_d = ALIGN(ui->data_len, 8) };
+	struct fscrypt_name nm;
 
 	/*
 	 * Budget request settings: new direntry, changing the target inode,
@@ -559,17 +625,29 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
 	ubifs_assert(inode_is_locked(dir));
 	ubifs_assert(inode_is_locked(inode));
 
-	if (ubifs_crypt_is_encrypted(dir) &&
-	    !fscrypt_has_permitted_context(dir, inode))
-		return -EPERM;
+	if (ubifs_crypt_is_encrypted(dir)) {
+		if (!fscrypt_has_permitted_context(dir, inode))
+			return -EPERM;
 
-	err = dbg_check_synced_i_size(c, inode);
+		err = fscrypt_get_encryption_info(inode);
+		if (err)
+			return err;
+
+		if (!fscrypt_has_encryption_key(inode))
+			return -EPERM;
+	}
+
+	err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm);
 	if (err)
 		return err;
 
+	err = dbg_check_synced_i_size(c, inode);
+	if (err)
+		goto out_fname;
+
 	err = ubifs_budget_space(c, &req);
 	if (err)
-		return err;
+		goto out_fname;
 
 	lock_2_inodes(dir, inode);
 	inc_nlink(inode);
@@ -578,13 +656,14 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
 	dir->i_size += sz_change;
 	dir_ui->ui_size = dir->i_size;
 	dir->i_mtime = dir->i_ctime = inode->i_ctime;
-	err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0);
+	err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0);
 	if (err)
 		goto out_cancel;
 	unlock_2_inodes(dir, inode);
 
 	ubifs_release_budget(c, &req);
 	d_instantiate(dentry, inode);
+	fscrypt_free_filename(&nm);
 	return 0;
 
 out_cancel:
@@ -594,6 +673,8 @@ out_cancel:
 	unlock_2_inodes(dir, inode);
 	ubifs_release_budget(c, &req);
 	iput(inode);
+out_fname:
+	fscrypt_free_filename(&nm);
 	return err;
 }
 
@@ -602,10 +683,10 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
 	struct ubifs_info *c = dir->i_sb->s_fs_info;
 	struct inode *inode = d_inode(dentry);
 	struct ubifs_inode *dir_ui = ubifs_inode(dir);
-	int sz_change = CALC_DENT_SIZE(dentry->d_name.len);
-	int err, budgeted = 1;
+	int err, sz_change, budgeted = 1;
 	struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 };
 	unsigned int saved_nlink = inode->i_nlink;
+	struct fscrypt_name nm;
 
 	/*
 	 * Budget request settings: deletion direntry, deletion inode (+1 for
@@ -617,16 +698,29 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
 	dbg_gen("dent '%pd' from ino %lu (nlink %d) in dir ino %lu",
 		dentry, inode->i_ino,
 		inode->i_nlink, dir->i_ino);
+
+	if (ubifs_crypt_is_encrypted(dir)) {
+		err = fscrypt_get_encryption_info(dir);
+		if (err && err != -ENOKEY)
+			return err;
+	}
+
+	err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm);
+	if (err)
+		return err;
+
+	sz_change = CALC_DENT_SIZE(fname_len(&nm));
+
 	ubifs_assert(inode_is_locked(dir));
 	ubifs_assert(inode_is_locked(inode));
 	err = dbg_check_synced_i_size(c, inode);
 	if (err)
-		return err;
+		goto out_fname;
 
 	err = ubifs_budget_space(c, &req);
 	if (err) {
 		if (err != -ENOSPC)
-			return err;
+			goto out_fname;
 		budgeted = 0;
 	}
 
@@ -636,7 +730,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
 	dir->i_size -= sz_change;
 	dir_ui->ui_size = dir->i_size;
 	dir->i_mtime = dir->i_ctime = inode->i_ctime;
-	err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 1, 0);
+	err = ubifs_jnl_update(c, dir, &nm, inode, 1, 0);
 	if (err)
 		goto out_cancel;
 	unlock_2_inodes(dir, inode);
@@ -648,6 +742,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
 		c->bi.nospace = c->bi.nospace_rp = 0;
 		smp_wmb();
 	}
+	fscrypt_free_filename(&nm);
 	return 0;
 
 out_cancel:
@@ -657,6 +752,8 @@ out_cancel:
 	unlock_2_inodes(dir, inode);
 	if (budgeted)
 		ubifs_release_budget(c, &req);
+out_fname:
+	fscrypt_free_filename(&nm);
 	return err;
 }
 
@@ -671,7 +768,7 @@ out_cancel:
 int ubifs_check_dir_empty(struct inode *dir)
 {
 	struct ubifs_info *c = dir->i_sb->s_fs_info;
-	struct qstr nm = { .name = NULL };
+	struct fscrypt_name nm = { 0 };
 	struct ubifs_dent_node *dent;
 	union ubifs_key key;
 	int err;
@@ -693,10 +790,10 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
 {
 	struct ubifs_info *c = dir->i_sb->s_fs_info;
 	struct inode *inode = d_inode(dentry);
-	int sz_change = CALC_DENT_SIZE(dentry->d_name.len);
-	int err, budgeted = 1;
+	int err, sz_change, budgeted = 1;
 	struct ubifs_inode *dir_ui = ubifs_inode(dir);
 	struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 };
+	struct fscrypt_name nm;
 
 	/*
 	 * Budget request settings: deletion direntry, deletion inode and
@@ -712,10 +809,22 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
 	if (err)
 		return err;
 
+	if (ubifs_crypt_is_encrypted(dir)) {
+		err = fscrypt_get_encryption_info(dir);
+		if (err && err != -ENOKEY)
+			return err;
+	}
+
+	err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm);
+	if (err)
+		return err;
+
+	sz_change = CALC_DENT_SIZE(fname_len(&nm));
+
 	err = ubifs_budget_space(c, &req);
 	if (err) {
 		if (err != -ENOSPC)
-			return err;
+			goto out_fname;
 		budgeted = 0;
 	}
 
@@ -726,7 +835,7 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
 	dir->i_size -= sz_change;
 	dir_ui->ui_size = dir->i_size;
 	dir->i_mtime = dir->i_ctime = inode->i_ctime;
-	err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 1, 0);
+	err = ubifs_jnl_update(c, dir, &nm, inode, 1, 0);
 	if (err)
 		goto out_cancel;
 	unlock_2_inodes(dir, inode);
@@ -738,6 +847,7 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
 		c->bi.nospace = c->bi.nospace_rp = 0;
 		smp_wmb();
 	}
+	fscrypt_free_filename(&nm);
 	return 0;
 
 out_cancel:
@@ -748,6 +858,8 @@ out_cancel:
 	unlock_2_inodes(dir, inode);
 	if (budgeted)
 		ubifs_release_budget(c, &req);
+out_fname:
+	fscrypt_free_filename(&nm);
 	return err;
 }
 
@@ -756,8 +868,9 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 	struct inode *inode;
 	struct ubifs_inode *dir_ui = ubifs_inode(dir);
 	struct ubifs_info *c = dir->i_sb->s_fs_info;
-	int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len);
+	int err, sz_change;
 	struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1 };
+	struct fscrypt_name nm;
 
 	/*
 	 * Budget request settings: new inode, new direntry and changing parent
@@ -771,10 +884,27 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 	if (err)
 		return err;
 
+	if (ubifs_crypt_is_encrypted(dir)) {
+		err = fscrypt_get_encryption_info(dir);
+		if (err)
+			goto out_budg;
+
+		if (!fscrypt_has_encryption_key(dir)) {
+			err = -EPERM;
+			goto out_budg;
+		}
+	}
+
+	err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm);
+	if (err)
+		goto out_budg;
+
+	sz_change = CALC_DENT_SIZE(fname_len(&nm));
+
 	inode = ubifs_new_inode(c, dir, S_IFDIR | mode);
 	if (IS_ERR(inode)) {
 		err = PTR_ERR(inode);
-		goto out_budg;
+		goto out_fname;
 	}
 
 	err = ubifs_init_security(dir, inode, &dentry->d_name);
@@ -788,7 +918,7 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 	dir->i_size += sz_change;
 	dir_ui->ui_size = dir->i_size;
 	dir->i_mtime = dir->i_ctime = inode->i_ctime;
-	err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0);
+	err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0);
 	if (err) {
 		ubifs_err(c, "cannot create directory, error %d", err);
 		goto out_cancel;
@@ -797,6 +927,7 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 
 	ubifs_release_budget(c, &req);
 	d_instantiate(dentry, inode);
+	fscrypt_free_filename(&nm);
 	return 0;
 
 out_cancel:
@@ -807,6 +938,8 @@ out_cancel:
 out_inode:
 	make_bad_inode(inode);
 	iput(inode);
+out_fname:
+	fscrypt_free_filename(&nm);
 out_budg:
 	ubifs_release_budget(c, &req);
 	return err;
@@ -820,11 +953,12 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
 	struct ubifs_inode *dir_ui = ubifs_inode(dir);
 	struct ubifs_info *c = dir->i_sb->s_fs_info;
 	union ubifs_dev_desc *dev = NULL;
-	int sz_change = CALC_DENT_SIZE(dentry->d_name.len);
+	int sz_change;
 	int err, devlen = 0;
 	struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
 					.new_ino_d = ALIGN(devlen, 8),
 					.dirtied_ino = 1 };
+	struct fscrypt_name nm;
 
 	/*
 	 * Budget request settings: new inode, new direntry and changing parent
@@ -846,11 +980,28 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
 		return err;
 	}
 
+	if (ubifs_crypt_is_encrypted(dir)) {
+		err = fscrypt_get_encryption_info(dir);
+		if (err)
+			goto out_budg;
+
+		if (!fscrypt_has_encryption_key(dir)) {
+			err = -EPERM;
+			goto out_budg;
+		}
+	}
+
+	err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm);
+	if (err)
+		goto out_budg;
+
+	sz_change = CALC_DENT_SIZE(fname_len(&nm));
+
 	inode = ubifs_new_inode(c, dir, mode);
 	if (IS_ERR(inode)) {
 		kfree(dev);
 		err = PTR_ERR(inode);
-		goto out_budg;
+		goto out_fname;
 	}
 
 	init_special_inode(inode, inode->i_mode, rdev);
@@ -867,7 +1018,7 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
 	dir->i_size += sz_change;
 	dir_ui->ui_size = dir->i_size;
 	dir->i_mtime = dir->i_ctime = inode->i_ctime;
-	err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0);
+	err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0);
 	if (err)
 		goto out_cancel;
 	mutex_unlock(&dir_ui->ui_mutex);
@@ -875,6 +1026,7 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
 	ubifs_release_budget(c, &req);
 	insert_inode_hash(inode);
 	d_instantiate(dentry, inode);
+	fscrypt_free_filename(&nm);
 	return 0;
 
 out_cancel:
@@ -884,6 +1036,8 @@ out_cancel:
 out_inode:
 	make_bad_inode(inode);
 	iput(inode);
+out_fname:
+	fscrypt_free_filename(&nm);
 out_budg:
 	ubifs_release_budget(c, &req);
 	return err;
@@ -1019,15 +1173,14 @@ static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
 	struct ubifs_inode *old_inode_ui = ubifs_inode(old_inode);
 	int err, release, sync = 0, move = (new_dir != old_dir);
 	int is_dir = S_ISDIR(old_inode->i_mode);
-	int unlink = !!new_inode;
-	int new_sz = CALC_DENT_SIZE(new_dentry->d_name.len);
-	int old_sz = CALC_DENT_SIZE(old_dentry->d_name.len);
+	int unlink = !!new_inode, new_sz, old_sz;
 	struct ubifs_budget_req req = { .new_dent = 1, .mod_dent = 1,
 					.dirtied_ino = 3 };
 	struct ubifs_budget_req ino_req = { .dirtied_ino = 1,
 			.dirtied_ino_d = ALIGN(old_inode_ui->data_len, 8) };
 	struct timespec time;
 	unsigned int uninitialized_var(saved_nlink);
+	struct fscrypt_name old_nm, new_nm;
 
 	/*
 	 * Budget request settings: deletion direntry, new direntry, removing
@@ -1058,11 +1211,29 @@ static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
 			return err;
 	}
 
-	err = ubifs_budget_space(c, &req);
+	err = fscrypt_setup_filename(old_dir, &old_dentry->d_name, 0, &old_nm);
 	if (err)
 		return err;
+
+	err = fscrypt_setup_filename(new_dir, &new_dentry->d_name, 0, &new_nm);
+	if (err) {
+		fscrypt_free_filename(&old_nm);
+		return err;
+	}
+
+	new_sz = CALC_DENT_SIZE(fname_len(&new_nm));
+	old_sz = CALC_DENT_SIZE(fname_len(&old_nm));
+
+	err = ubifs_budget_space(c, &req);
+	if (err) {
+		fscrypt_free_filename(&old_nm);
+		fscrypt_free_filename(&new_nm);
+		return err;
+	}
 	err = ubifs_budget_space(c, &ino_req);
 	if (err) {
+		fscrypt_free_filename(&old_nm);
+		fscrypt_free_filename(&new_nm);
 		ubifs_release_budget(c, &req);
 		return err;
 	}
@@ -1137,7 +1308,7 @@ static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
 		if (unlink && IS_SYNC(new_inode))
 			sync = 1;
 	}
-	err = ubifs_jnl_rename(c, old_dir, old_dentry, new_dir, new_dentry,
+	err = ubifs_jnl_rename(c, old_dir, old_inode, &old_nm, new_dir, new_inode, &new_nm,
 			       sync);
 	if (err)
 		goto out_cancel;
@@ -1154,6 +1325,9 @@ static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
 		ubifs_release_budget(c, &ino_req);
 	if (IS_SYNC(old_inode))
 		err = old_inode->i_sb->s_op->write_inode(old_inode, NULL);
+
+	fscrypt_free_filename(&old_nm);
+	fscrypt_free_filename(&new_nm);
 	return err;
 
 out_cancel:
@@ -1178,6 +1352,8 @@ out_cancel:
 	unlock_3_inodes(old_dir, new_dir, new_inode);
 	ubifs_release_budget(c, &ino_req);
 	ubifs_release_budget(c, &req);
+	fscrypt_free_filename(&old_nm);
+	fscrypt_free_filename(&new_nm);
 	return err;
 }
 
diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c
index da694e520ec8..eb1cef8032e7 100644
--- a/fs/ubifs/journal.c
+++ b/fs/ubifs/journal.c
@@ -530,7 +530,7 @@ static void mark_inode_clean(struct ubifs_info *c, struct ubifs_inode *ui)
  * success. In case of failure, a negative error code is returned.
  */
 int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
-		     const struct qstr *nm, const struct inode *inode,
+		     const struct fscrypt_name *nm, const struct inode *inode,
 		     int deletion, int xent)
 {
 	int err, dlen, ilen, len, lnum, ino_offs, dent_offs;
@@ -542,11 +542,11 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
 	struct ubifs_ino_node *ino;
 	union ubifs_key dent_key, ino_key;
 
-	dbg_jnl("ino %lu, dent '%.*s', data len %d in dir ino %lu",
-		inode->i_ino, nm->len, nm->name, ui->data_len, dir->i_ino);
+	//dbg_jnl("ino %lu, dent '%.*s', data len %d in dir ino %lu",
+	//	inode->i_ino, nm->len, nm->name, ui->data_len, dir->i_ino);
 	ubifs_assert(mutex_is_locked(&host_ui->ui_mutex));
 
-	dlen = UBIFS_DENT_NODE_SZ + nm->len + 1;
+	dlen = UBIFS_DENT_NODE_SZ + fname_len(nm) + 1;
 	ilen = UBIFS_INO_NODE_SZ;
 
 	/*
@@ -587,9 +587,10 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
 	key_write(c, &dent_key, dent->key);
 	dent->inum = deletion ? 0 : cpu_to_le64(inode->i_ino);
 	dent->type = get_dent_type(inode->i_mode);
-	dent->nlen = cpu_to_le16(nm->len);
-	memcpy(dent->name, nm->name, nm->len);
-	dent->name[nm->len] = '\0';
+	dent->nlen = cpu_to_le16(fname_len(nm));
+	memcpy(dent->name, fname_name(nm), fname_len(nm));
+	dent->name[fname_len(nm)] = '\0';
+
 	zero_dent_node_unused(dent);
 	ubifs_prep_grp_node(c, dent, dlen, 0);
 
@@ -936,30 +937,31 @@ int ubifs_jnl_delete_inode(struct ubifs_info *c, const struct inode *inode)
  * returned.
  */
 int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
-		     const struct dentry *old_dentry,
+		     const struct inode *old_inode,
+		     const struct fscrypt_name *old_nm,
 		     const struct inode *new_dir,
-		     const struct dentry *new_dentry, int sync)
+		     const struct inode *new_inode,
+		     const struct fscrypt_name *new_nm,
+		     int sync)
 {
 	void *p;
 	union ubifs_key key;
 	struct ubifs_dent_node *dent, *dent2;
 	int err, dlen1, dlen2, ilen, lnum, offs, len;
-	const struct inode *old_inode = d_inode(old_dentry);
-	const struct inode *new_inode = d_inode(new_dentry);
 	int aligned_dlen1, aligned_dlen2, plen = UBIFS_INO_NODE_SZ;
 	int last_reference = !!(new_inode && new_inode->i_nlink == 0);
 	int move = (old_dir != new_dir);
 	struct ubifs_inode *uninitialized_var(new_ui);
 
-	dbg_jnl("dent '%pd' in dir ino %lu to dent '%pd' in dir ino %lu",
-		old_dentry, old_dir->i_ino, new_dentry, new_dir->i_ino);
+	//dbg_jnl("dent '%pd' in dir ino %lu to dent '%pd' in dir ino %lu",
+	//	old_dentry, old_dir->i_ino, new_dentry, new_dir->i_ino);
 	ubifs_assert(ubifs_inode(old_dir)->data_len == 0);
 	ubifs_assert(ubifs_inode(new_dir)->data_len == 0);
 	ubifs_assert(mutex_is_locked(&ubifs_inode(old_dir)->ui_mutex));
 	ubifs_assert(mutex_is_locked(&ubifs_inode(new_dir)->ui_mutex));
 
-	dlen1 = UBIFS_DENT_NODE_SZ + new_dentry->d_name.len + 1;
-	dlen2 = UBIFS_DENT_NODE_SZ + old_dentry->d_name.len + 1;
+	dlen1 = UBIFS_DENT_NODE_SZ + fname_len(new_nm) + 1;
+	dlen2 = UBIFS_DENT_NODE_SZ + fname_len(old_nm) + 1;
 	if (new_inode) {
 		new_ui = ubifs_inode(new_inode);
 		ubifs_assert(mutex_is_locked(&new_ui->ui_mutex));
@@ -985,25 +987,24 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
 
 	/* Make new dent */
 	dent->ch.node_type = UBIFS_DENT_NODE;
-	dent_key_init_flash(c, &dent->key, new_dir->i_ino, &new_dentry->d_name);
+	dent_key_init_flash(c, &dent->key, new_dir->i_ino, new_nm);
 	dent->inum = cpu_to_le64(old_inode->i_ino);
 	dent->type = get_dent_type(old_inode->i_mode);
-	dent->nlen = cpu_to_le16(new_dentry->d_name.len);
-	memcpy(dent->name, new_dentry->d_name.name, new_dentry->d_name.len);
-	dent->name[new_dentry->d_name.len] = '\0';
+	dent->nlen = cpu_to_le16(fname_len(new_nm));
+	memcpy(dent->name, fname_name(new_nm), fname_len(new_nm));
+	dent->name[fname_len(new_nm)] = '\0';
 	zero_dent_node_unused(dent);
 	ubifs_prep_grp_node(c, dent, dlen1, 0);
 
 	/* Make deletion dent */
 	dent2 = (void *)dent + aligned_dlen1;
 	dent2->ch.node_type = UBIFS_DENT_NODE;
-	dent_key_init_flash(c, &dent2->key, old_dir->i_ino,
-			    &old_dentry->d_name);
+	dent_key_init_flash(c, &dent2->key, old_dir->i_ino, old_nm);
 	dent2->inum = 0;
 	dent2->type = DT_UNKNOWN;
-	dent2->nlen = cpu_to_le16(old_dentry->d_name.len);
-	memcpy(dent2->name, old_dentry->d_name.name, old_dentry->d_name.len);
-	dent2->name[old_dentry->d_name.len] = '\0';
+	dent2->nlen = cpu_to_le16(fname_len(old_nm));
+	memcpy(dent2->name, fname_name(old_nm), fname_len(old_nm));
+	dent2->name[fname_len(old_nm)] = '\0';
 	zero_dent_node_unused(dent2);
 	ubifs_prep_grp_node(c, dent2, dlen2, 0);
 
@@ -1044,8 +1045,8 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
 	}
 	release_head(c, BASEHD);
 
-	dent_key_init(c, &key, new_dir->i_ino, &new_dentry->d_name);
-	err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen1, &new_dentry->d_name);
+	dent_key_init(c, &key, new_dir->i_ino, new_nm);
+	err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen1, new_nm);
 	if (err)
 		goto out_ro;
 
@@ -1053,8 +1054,8 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
 	if (err)
 		goto out_ro;
 
-	dent_key_init(c, &key, old_dir->i_ino, &old_dentry->d_name);
-	err = ubifs_tnc_remove_nm(c, &key, &old_dentry->d_name);
+	dent_key_init(c, &key, old_dir->i_ino, old_nm);
+	err = ubifs_tnc_remove_nm(c, &key, old_nm);
 	if (err)
 		goto out_ro;
 
@@ -1117,7 +1118,7 @@ out_free:
  * This function is used when an inode is truncated and the last data node of
  * the inode has to be re-compressed/encrypted and re-written.
  */
-static int truncate_data_node(const struct ubifs_info *c, struct inode *inode,
+static int truncate_data_node(const struct ubifs_info *c, const struct inode *inode,
 			      unsigned int block, struct ubifs_data_node *dn,
 			      int *new_len)
 {
@@ -1338,7 +1339,8 @@ out_free:
  * error code in case of failure.
  */
 int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
-			   const struct inode *inode, const struct qstr *nm)
+			   const struct inode *inode,
+			   const struct fscrypt_name *nm)
 {
 	int err, xlen, hlen, len, lnum, xent_offs, aligned_xlen;
 	struct ubifs_dent_node *xent;
@@ -1347,9 +1349,9 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
 	int sync = IS_DIRSYNC(host);
 	struct ubifs_inode *host_ui = ubifs_inode(host);
 
-	dbg_jnl("host %lu, xattr ino %lu, name '%s', data len %d",
-		host->i_ino, inode->i_ino, nm->name,
-		ubifs_inode(inode)->data_len);
+	//dbg_jnl("host %lu, xattr ino %lu, name '%s', data len %d",
+	//	host->i_ino, inode->i_ino, nm->name,
+	//	ubifs_inode(inode)->data_len);
 	ubifs_assert(inode->i_nlink == 0);
 	ubifs_assert(mutex_is_locked(&host_ui->ui_mutex));
 
@@ -1357,7 +1359,7 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
 	 * Since we are deleting the inode, we do not bother to attach any data
 	 * to it and assume its length is %UBIFS_INO_NODE_SZ.
 	 */
-	xlen = UBIFS_DENT_NODE_SZ + nm->len + 1;
+	xlen = UBIFS_DENT_NODE_SZ + fname_len(nm) + 1;
 	aligned_xlen = ALIGN(xlen, 8);
 	hlen = host_ui->data_len + UBIFS_INO_NODE_SZ;
 	len = aligned_xlen + UBIFS_INO_NODE_SZ + ALIGN(hlen, 8);
@@ -1378,9 +1380,9 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
 	key_write(c, &xent_key, xent->key);
 	xent->inum = 0;
 	xent->type = get_dent_type(inode->i_mode);
-	xent->nlen = cpu_to_le16(nm->len);
-	memcpy(xent->name, nm->name, nm->len);
-	xent->name[nm->len] = '\0';
+	xent->nlen = cpu_to_le16(fname_len(nm));
+	memcpy(xent->name, fname_name(nm), fname_len(nm));
+	xent->name[fname_len(nm)] = '\0';
 	zero_dent_node_unused(xent);
 	ubifs_prep_grp_node(c, xent, xlen, 0);
 
diff --git a/fs/ubifs/key.h b/fs/ubifs/key.h
index ca4371fdfa7d..7547be512db2 100644
--- a/fs/ubifs/key.h
+++ b/fs/ubifs/key.h
@@ -153,13 +153,13 @@ static inline void highest_ino_key(const struct ubifs_info *c,
  * @c: UBIFS file-system description object
  * @key: key to initialize
  * @inum: parent inode number
- * @nm: direntry name and length
+ * @nm: direntry name and length. Not a string when encrypted!
  */
 static inline void dent_key_init(const struct ubifs_info *c,
 				 union ubifs_key *key, ino_t inum,
-				 const struct qstr *nm)
+				 const struct fscrypt_name *nm)
 {
-	uint32_t hash = c->key_hash(nm->name, nm->len);
+	uint32_t hash = c->key_hash(fname_name(nm), fname_len(nm));
 
 	ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
 	key->u32[0] = inum;
@@ -191,10 +191,11 @@ static inline void dent_key_init_hash(const struct ubifs_info *c,
  * @nm: direntry name and length
  */
 static inline void dent_key_init_flash(const struct ubifs_info *c, void *k,
-				       ino_t inum, const struct qstr *nm)
+				       ino_t inum,
+				       const struct fscrypt_name *nm)
 {
 	union ubifs_key *key = k;
-	uint32_t hash = c->key_hash(nm->name, nm->len);
+	uint32_t hash = c->key_hash(fname_name(nm), fname_len(nm));
 
 	ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
 	key->j32[0] = cpu_to_le32(inum);
@@ -225,9 +226,9 @@ static inline void lowest_dent_key(const struct ubifs_info *c,
  */
 static inline void xent_key_init(const struct ubifs_info *c,
 				 union ubifs_key *key, ino_t inum,
-				 const struct qstr *nm)
+				 const struct fscrypt_name *nm)
 {
-	uint32_t hash = c->key_hash(nm->name, nm->len);
+	uint32_t hash = c->key_hash(fname_name(nm), fname_len(nm));
 
 	ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
 	key->u32[0] = inum;
@@ -242,10 +243,10 @@ static inline void xent_key_init(const struct ubifs_info *c,
  * @nm: extended attribute entry name and length
  */
 static inline void xent_key_init_flash(const struct ubifs_info *c, void *k,
-				       ino_t inum, const struct qstr *nm)
+				       ino_t inum, const struct fscrypt_name *nm)
 {
 	union ubifs_key *key = k;
-	uint32_t hash = c->key_hash(nm->name, nm->len);
+	uint32_t hash = c->key_hash(fname_name(nm), fname_len(nm));
 
 	ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
 	key->j32[0] = cpu_to_le32(inum);
diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
index f02adc49425b..4143982e3701 100644
--- a/fs/ubifs/replay.c
+++ b/fs/ubifs/replay.c
@@ -61,7 +61,7 @@ struct replay_entry {
 	struct list_head list;
 	union ubifs_key key;
 	union {
-		struct qstr nm;
+		struct fscrypt_name nm;
 		struct {
 			loff_t old_size;
 			loff_t new_size;
@@ -327,7 +327,7 @@ static void destroy_replay_list(struct ubifs_info *c)
 
 	list_for_each_entry_safe(r, tmp, &c->replay_list, list) {
 		if (is_hash_key(c, &r->key))
-			kfree(r->nm.name);
+			kfree(fname_name(&r->nm));
 		list_del(&r->list);
 		kfree(r);
 	}
@@ -430,10 +430,10 @@ static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
 	r->deletion = !!deletion;
 	r->sqnum = sqnum;
 	key_copy(c, key, &r->key);
-	r->nm.len = nlen;
+	fname_len(&r->nm) = nlen;
 	memcpy(nbuf, name, nlen);
 	nbuf[nlen] = '\0';
-	r->nm.name = nbuf;
+	fname_name(&r->nm) = nbuf;
 
 	list_add_tail(&r->list, &c->replay_list);
 	return 0;
diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c
index fa9a20cc60d6..0d0030461cb4 100644
--- a/fs/ubifs/tnc.c
+++ b/fs/ubifs/tnc.c
@@ -519,7 +519,7 @@ static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
  * of failure, a negative error code is returned.
  */
 static int matches_name(struct ubifs_info *c, struct ubifs_zbranch *zbr,
-			const struct qstr *nm)
+			const struct fscrypt_name *nm)
 {
 	struct ubifs_dent_node *dent;
 	int nlen, err;
@@ -542,11 +542,11 @@ static int matches_name(struct ubifs_info *c, struct ubifs_zbranch *zbr,
 		dent = zbr->leaf;
 
 	nlen = le16_to_cpu(dent->nlen);
-	err = memcmp(dent->name, nm->name, min_t(int, nlen, nm->len));
+	err = memcmp(dent->name, fname_name(nm), min_t(int, nlen, fname_len(nm)));
 	if (err == 0) {
-		if (nlen == nm->len)
+		if (nlen == fname_len(nm))
 			return NAME_MATCHES;
-		else if (nlen < nm->len)
+		else if (nlen < fname_len(nm))
 			return NAME_LESS;
 		else
 			return NAME_GREATER;
@@ -689,7 +689,7 @@ static int tnc_prev(struct ubifs_info *c, struct ubifs_znode **zn, int *n)
  */
 static int resolve_collision(struct ubifs_info *c, const union ubifs_key *key,
 			     struct ubifs_znode **zn, int *n,
-			     const struct qstr *nm)
+			     const struct fscrypt_name *nm)
 {
 	int err;
 
@@ -807,7 +807,7 @@ static int resolve_collision(struct ubifs_info *c, const union ubifs_key *key,
  */
 static int fallible_matches_name(struct ubifs_info *c,
 				 struct ubifs_zbranch *zbr,
-				 const struct qstr *nm)
+				 const struct fscrypt_name *nm)
 {
 	struct ubifs_dent_node *dent;
 	int nlen, err;
@@ -835,11 +835,11 @@ static int fallible_matches_name(struct ubifs_info *c,
 		dent = zbr->leaf;
 
 	nlen = le16_to_cpu(dent->nlen);
-	err = memcmp(dent->name, nm->name, min_t(int, nlen, nm->len));
+	err = memcmp(dent->name, fname_name(nm), min_t(int, nlen, fname_len(nm)));
 	if (err == 0) {
-		if (nlen == nm->len)
+		if (nlen == fname_len(nm))
 			return NAME_MATCHES;
-		else if (nlen < nm->len)
+		else if (nlen < fname_len(nm))
 			return NAME_LESS;
 		else
 			return NAME_GREATER;
@@ -878,7 +878,8 @@ out_free:
 static int fallible_resolve_collision(struct ubifs_info *c,
 				      const union ubifs_key *key,
 				      struct ubifs_znode **zn, int *n,
-				      const struct qstr *nm, int adding)
+				      const struct fscrypt_name *nm,
+				      int adding)
 {
 	struct ubifs_znode *o_znode = NULL, *znode = *zn;
 	int uninitialized_var(o_n), err, cmp, unsure = 0, nn = *n;
@@ -1789,12 +1790,12 @@ int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu)
  * was not found, and a negative error code in case of failure.
  */
 static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
-			void *node, const struct qstr *nm)
+			void *node, const struct fscrypt_name *nm)
 {
 	int found, n, err;
 	struct ubifs_znode *znode;
 
-	dbg_tnck(key, "name '%.*s' key ", nm->len, nm->name);
+	//dbg_tnck(key, "name '%.*s' key ", nm->len, nm->name);
 	mutex_lock(&c->tnc_mutex);
 	found = ubifs_lookup_level0(c, key, &znode, &n);
 	if (!found) {
@@ -1837,7 +1838,7 @@ out_unlock:
  * was not found, and a negative error code in case of failure.
  */
 int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
-			void *node, const struct qstr *nm)
+			void *node, const struct fscrypt_name *nm)
 {
 	int err, len;
 	const struct ubifs_dent_node *dent = node;
@@ -1851,7 +1852,7 @@ int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
 		return err;
 
 	len = le16_to_cpu(dent->nlen);
-	if (nm->len == len && !memcmp(dent->name, nm->name, len))
+	if (fname_len(nm) == len && !memcmp(dent->name, fname_name(nm), len))
 		return 0;
 
 	/*
@@ -2279,14 +2280,15 @@ out_unlock:
  * may have collisions, like directory entry keys.
  */
 int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
-		     int lnum, int offs, int len, const struct qstr *nm)
+		     int lnum, int offs, int len,
+		     const struct fscrypt_name *nm)
 {
 	int found, n, err = 0;
 	struct ubifs_znode *znode;
 
 	mutex_lock(&c->tnc_mutex);
-	dbg_tnck(key, "LEB %d:%d, name '%.*s', key ",
-		 lnum, offs, nm->len, nm->name);
+	//dbg_tnck(key, "LEB %d:%d, name '%.*s', key ",
+	//	 lnum, offs, nm->len, nm->name);
 	found = lookup_level0_dirty(c, key, &znode, &n);
 	if (found < 0) {
 		err = found;
@@ -2344,7 +2346,7 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
 			 * by passing 'ubifs_tnc_remove_nm()' the same key but
 			 * an unmatchable name.
 			 */
-			struct qstr noname = { .name = "" };
+			struct fscrypt_name noname = { .disk_name = { .name = "", .len = 1 } };
 
 			err = dbg_check_tnc(c, 0);
 			mutex_unlock(&c->tnc_mutex);
@@ -2514,13 +2516,13 @@ out_unlock:
  * Returns %0 on success or negative error code on failure.
  */
 int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
-			const struct qstr *nm)
+			const struct fscrypt_name *nm)
 {
 	int n, err;
 	struct ubifs_znode *znode;
 
 	mutex_lock(&c->tnc_mutex);
-	dbg_tnck(key, "%.*s, key ", nm->len, nm->name);
+	//dbg_tnck(key, "%.*s, key ", nm->len, nm->name);
 	err = lookup_level0_dirty(c, key, &znode, &n);
 	if (err < 0)
 		goto out_unlock;
@@ -2669,7 +2671,7 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum)
 {
 	union ubifs_key key1, key2;
 	struct ubifs_dent_node *xent, *pxent = NULL;
-	struct qstr nm = { .name = NULL };
+	struct fscrypt_name nm = {0};
 
 	dbg_tnc("ino %lu", (unsigned long)inum);
 
@@ -2694,8 +2696,8 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum)
 		dbg_tnc("xent '%s', ino %lu", xent->name,
 			(unsigned long)xattr_inum);
 
-		nm.name = xent->name;
-		nm.len = le16_to_cpu(xent->nlen);
+		fname_name(&nm) = xent->name;
+		fname_len(&nm) = le16_to_cpu(xent->nlen);
 		err = ubifs_tnc_remove_nm(c, &key1, &nm);
 		if (err) {
 			kfree(xent);
@@ -2747,7 +2749,7 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum)
  */
 struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
 					   union ubifs_key *key,
-					   const struct qstr *nm)
+					   const struct fscrypt_name *nm)
 {
 	int n, err, type = key_type(c, key);
 	struct ubifs_znode *znode;
@@ -2755,7 +2757,7 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
 	struct ubifs_zbranch *zbr;
 	union ubifs_key *dkey;
 
-	dbg_tnck(key, "%s ", nm->name ? (char *)nm->name : "(lowest)");
+	//dbg_tnck(key, "%s ", nm->name ? (char *)nm->name : "(lowest)");
 	ubifs_assert(is_hash_key(c, key));
 
 	mutex_lock(&c->tnc_mutex);
@@ -2763,7 +2765,7 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
 	if (unlikely(err < 0))
 		goto out_unlock;
 
-	if (nm->name) {
+	if (fname_len(nm) > 0) {
 		if (err) {
 			/* Handle collisions */
 			err = resolve_collision(c, key, &znode, &n, nm);
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 456f22aed35c..f91ef52a4523 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -1521,20 +1521,23 @@ int ubifs_consolidate_log(struct ubifs_info *c);
 
 /* journal.c */
 int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
-		     const struct qstr *nm, const struct inode *inode,
+		     const struct fscrypt_name *nm, const struct inode *inode,
 		     int deletion, int xent);
 int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
 			 const union ubifs_key *key, const void *buf, int len);
 int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode);
 int ubifs_jnl_delete_inode(struct ubifs_info *c, const struct inode *inode);
 int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
-		     const struct dentry *old_dentry,
+		     const struct inode *old_inode,
+		     const struct fscrypt_name *old_nm,
 		     const struct inode *new_dir,
-		     const struct dentry *new_dentry, int sync);
+		     const struct inode *new_inode,
+		     const struct fscrypt_name *new_nm,
+		     int sync);
 int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
 		       loff_t old_size, loff_t new_size);
 int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
-			   const struct inode *inode, const struct qstr *nm);
+			   const struct inode *inode, const struct fscrypt_name *nm);
 int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode1,
 			   const struct inode *inode2);
 
@@ -1569,7 +1572,7 @@ int ubifs_save_dirty_idx_lnums(struct ubifs_info *c);
 int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
 			struct ubifs_znode **zn, int *n);
 int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
-			void *node, const struct qstr *nm);
+			void *node, const struct fscrypt_name *nm);
 int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key,
 		     void *node, int *lnum, int *offs);
 int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
@@ -1577,16 +1580,16 @@ int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
 int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key,
 		      int old_lnum, int old_offs, int lnum, int offs, int len);
 int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
-		     int lnum, int offs, int len, const struct qstr *nm);
+		     int lnum, int offs, int len, const struct fscrypt_name *nm);
 int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key);
 int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
-			const struct qstr *nm);
+			const struct fscrypt_name *nm);
 int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key,
 			   union ubifs_key *to_key);
 int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum);
 struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
 					   union ubifs_key *key,
-					   const struct qstr *nm);
+					   const struct fscrypt_name *nm);
 void ubifs_tnc_close(struct ubifs_info *c);
 int ubifs_tnc_has_node(struct ubifs_info *c, union ubifs_key *key, int level,
 		       int lnum, int offs, int is_idx);
diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c
index d3b53c55ea39..469b3ff9748c 100644
--- a/fs/ubifs/xattr.c
+++ b/fs/ubifs/xattr.c
@@ -97,7 +97,7 @@ static const struct file_operations empty_fops;
  * of failure.
  */
 static int create_xattr(struct ubifs_info *c, struct inode *host,
-			const struct qstr *nm, const void *value, int size)
+			const struct fscrypt_name *nm, const void *value, int size)
 {
 	int err, names_len;
 	struct inode *inode;
@@ -117,7 +117,7 @@ static int create_xattr(struct ubifs_info *c, struct inode *host,
 	 * extended attributes if the name list becomes larger. This limitation
 	 * is artificial for UBIFS, though.
 	 */
-	names_len = host_ui->xattr_names + host_ui->xattr_cnt + nm->len + 1;
+	names_len = host_ui->xattr_names + host_ui->xattr_cnt + fname_len(nm) + 1;
 	if (names_len > XATTR_LIST_MAX) {
 		ubifs_err(c, "cannot add one more xattr name to inode %lu, total names length would become %d, max. is %d",
 			  host->i_ino, names_len, XATTR_LIST_MAX);
@@ -154,9 +154,9 @@ static int create_xattr(struct ubifs_info *c, struct inode *host,
 	mutex_lock(&host_ui->ui_mutex);
 	host->i_ctime = ubifs_current_time(host);
 	host_ui->xattr_cnt += 1;
-	host_ui->xattr_size += CALC_DENT_SIZE(nm->len);
+	host_ui->xattr_size += CALC_DENT_SIZE(fname_len(nm));
 	host_ui->xattr_size += CALC_XATTR_BYTES(size);
-	host_ui->xattr_names += nm->len;
+	host_ui->xattr_names += fname_len(nm);
 
 	/*
 	 * We handle UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT here because we
@@ -164,7 +164,7 @@ static int create_xattr(struct ubifs_info *c, struct inode *host,
 	 * To avoid multiple updates of the same inode in the same operation,
 	 * let's do it here.
 	 */
-	if (strcmp(nm->name, UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT) == 0)
+	if (strcmp(fname_name(nm), UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT) == 0)
 		host_ui->flags |= UBIFS_CRYPT_FL;
 
 	err = ubifs_jnl_update(c, host, nm, inode, 0, 1);
@@ -179,7 +179,7 @@ static int create_xattr(struct ubifs_info *c, struct inode *host,
 
 out_cancel:
 	host_ui->xattr_cnt -= 1;
-	host_ui->xattr_size -= CALC_DENT_SIZE(nm->len);
+	host_ui->xattr_size -= CALC_DENT_SIZE(fname_len(nm));
 	host_ui->xattr_size -= CALC_XATTR_BYTES(size);
 	host_ui->flags &= ~UBIFS_CRYPT_FL;
 	mutex_unlock(&host_ui->ui_mutex);
@@ -281,7 +281,7 @@ int ubifs_xattr_set(struct inode *host, const char *name, const void *value,
 {
 	struct inode *inode;
 	struct ubifs_info *c = host->i_sb->s_fs_info;
-	struct qstr nm = QSTR_INIT(name, strlen(name));
+	struct fscrypt_name nm = { .disk_name = FSTR_INIT((char *)name, strlen(name))};
 	struct ubifs_dent_node *xent;
 	union ubifs_key key;
 	int err;
@@ -297,7 +297,7 @@ int ubifs_xattr_set(struct inode *host, const char *name, const void *value,
 	if (size > UBIFS_MAX_INO_DATA)
 		return -ERANGE;
 
-	if (nm.len > UBIFS_MAX_NLEN)
+	if (fname_len(&nm) > UBIFS_MAX_NLEN)
 		return -ENAMETOOLONG;
 
 	xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS);
@@ -347,13 +347,13 @@ ssize_t ubifs_xattr_get(struct inode *host, const char *name, void *buf,
 {
 	struct inode *inode;
 	struct ubifs_info *c = host->i_sb->s_fs_info;
-	struct qstr nm = QSTR_INIT(name, strlen(name));
+	struct fscrypt_name nm = { .disk_name = FSTR_INIT((char *)name, strlen(name))};
 	struct ubifs_inode *ui;
 	struct ubifs_dent_node *xent;
 	union ubifs_key key;
 	int err;
 
-	if (nm.len > UBIFS_MAX_NLEN)
+	if (fname_len(&nm) > UBIFS_MAX_NLEN)
 		return -ENAMETOOLONG;
 
 	xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS);
@@ -422,7 +422,7 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size)
 	struct ubifs_inode *host_ui = ubifs_inode(host);
 	struct ubifs_dent_node *xent, *pxent = NULL;
 	int err, len, written = 0;
-	struct qstr nm = { .name = NULL };
+	struct fscrypt_name nm = {0};
 
 	dbg_gen("ino %lu ('%pd'), buffer size %zd", host->i_ino,
 		dentry, size);
@@ -446,12 +446,12 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size)
 			break;
 		}
 
-		nm.name = xent->name;
-		nm.len = le16_to_cpu(xent->nlen);
+		fname_name(&nm) = xent->name;
+		fname_len(&nm) = le16_to_cpu(xent->nlen);
 
 		if (xattr_visible(xent->name)) {
-			memcpy(buffer + written, nm.name, nm.len + 1);
-			written += nm.len + 1;
+			memcpy(buffer + written, fname_name(&nm), fname_len(&nm) + 1);
+			written += fname_len(&nm) + 1;
 		}
 
 		kfree(pxent);
@@ -470,7 +470,7 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size)
 }
 
 static int remove_xattr(struct ubifs_info *c, struct inode *host,
-			struct inode *inode, const struct qstr *nm)
+			struct inode *inode, const struct fscrypt_name *nm)
 {
 	int err;
 	struct ubifs_inode *host_ui = ubifs_inode(host);
@@ -487,9 +487,9 @@ static int remove_xattr(struct ubifs_info *c, struct inode *host,
 	mutex_lock(&host_ui->ui_mutex);
 	host->i_ctime = ubifs_current_time(host);
 	host_ui->xattr_cnt -= 1;
-	host_ui->xattr_size -= CALC_DENT_SIZE(nm->len);
+	host_ui->xattr_size -= CALC_DENT_SIZE(fname_len(nm));
 	host_ui->xattr_size -= CALC_XATTR_BYTES(ui->data_len);
-	host_ui->xattr_names -= nm->len;
+	host_ui->xattr_names -= fname_len(nm);
 
 	err = ubifs_jnl_delete_xattr(c, host, inode, nm);
 	if (err)
@@ -501,7 +501,7 @@ static int remove_xattr(struct ubifs_info *c, struct inode *host,
 
 out_cancel:
 	host_ui->xattr_cnt += 1;
-	host_ui->xattr_size += CALC_DENT_SIZE(nm->len);
+	host_ui->xattr_size += CALC_DENT_SIZE(fname_len(nm));
 	host_ui->xattr_size += CALC_XATTR_BYTES(ui->data_len);
 	mutex_unlock(&host_ui->ui_mutex);
 	ubifs_release_budget(c, &req);
@@ -513,14 +513,14 @@ static int ubifs_xattr_remove(struct inode *host, const char *name)
 {
 	struct inode *inode;
 	struct ubifs_info *c = host->i_sb->s_fs_info;
-	struct qstr nm = QSTR_INIT(name, strlen(name));
+	struct fscrypt_name nm = { .disk_name = FSTR_INIT((char *)name, strlen(name))};
 	struct ubifs_dent_node *xent;
 	union ubifs_key key;
 	int err;
 
 	ubifs_assert(inode_is_locked(host));
 
-	if (nm.len > UBIFS_MAX_NLEN)
+	if (fname_len(&nm) > UBIFS_MAX_NLEN)
 		return -ENAMETOOLONG;
 
 	xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS);
-- 
2.7.3



From hch at infradead.org  Fri Oct 21 05:53:13 2016
From: hch at infradead.org (Christoph Hellwig)
Date: Fri, 21 Oct 2016 05:53:13 -0700
Subject: UBIFS with dma on 4.6 kernel is not working
In-Reply-To: <519a83bf-1244-5151-b873-bb8e1f2db3c6@nod.at>
References: <DA6901612C71B84D91459DE817C418AE26DF0F2B@XAP-PVEXMBX01.xlnx.xilinx.com>
 <519a83bf-1244-5151-b873-bb8e1f2db3c6@nod.at>
Message-ID: <20161021125313.GA16754@infradead.org>

On Fri, Oct 21, 2016 at 11:29:16AM +0200, Richard Weinberger wrote:
> DMA to vmalloced memory not good, it may work by chance if you transfer
> less than PAGE_SIZE.
> Especially on ARM.

DMA to vmalloc'ed or vmap memory is perfectly fine, you just have to be
very careful.

I would suggest to not expose the vmalloc address to the lower layers
that do DMA, but instead expose the pages, either as an array or
scatterlist.  Either allocate the pages using the normal page allocator
and then use vm_map_ram to generate a virtual address for them (that
is what XFS does for it's large metadata objects for example).  Or if
you can't do that iterate over the vmalloc address in page size chunks
and use vmalloc_to_page (we still also do that for one piece of legacy
cruft in XFS, but I'd rather avoid that for new designs).


From marcin.krzeminski at nokia.com  Fri Oct 21 05:55:46 2016
From: marcin.krzeminski at nokia.com (marcin.krzeminski at nokia.com)
Date: Fri, 21 Oct 2016 14:55:46 +0200
Subject: [PATCH] mtd: spi-nor: Add possibility to disable chip erase
Message-ID: <1477054546-2548-1-git-send-email-marcin.krzeminski@nokia.com>

From: Marcin Krzeminski <marcin.krzeminski at nokia.com>

n25q00 does not support chip erase command (0xC7),
but spi-nor framework still send if if user want to erase
whole flash. This patch adds option to disable chip erase
command and enable in on n25q00.

Signed-off-by: Marcin Krzeminski <marcin.krzeminski at nokia.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 9 ++++++---
 include/linux/mtd/spi-nor.h   | 1 +
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index d0fc165..8338be1 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -75,6 +75,7 @@ struct flash_info {
 					 * bit. Must be used with
 					 * SPI_NOR_HAS_LOCK.
 					 */
+#define DISABLE_CE			BIT(10)	/*Some multi-die flash does not support CE */
 };
 
 #define JEDEC_MFR(info)	((info)->id[0])
@@ -368,7 +369,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
 		return ret;
 
 	/* whole-chip erase? */
-	if (len == mtd->size) {
+	if (len == mtd->size && !(nor->flags & SNOR_F_DISABLE_CE)) {
 		unsigned long timeout;
 
 		write_enable(nor);
@@ -886,8 +887,8 @@ static const struct flash_info spi_nor_ids[] = {
 	{ "n25q256a",    INFO(0x20ba19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_QUAD_READ) },
 	{ "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) },
+	{ "n25q00",      INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | DISABLE_CE) },
+	{ "n25q00a",     INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | DISABLE_CE) },
 
 	/* PMC */
 	{ "pm25lv512",   INFO(0,        0, 32 * 1024,    2, SECT_4K_PMC) },
@@ -1395,6 +1396,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 		nor->flags |= SNOR_F_USE_FSR;
 	if (info->flags & SPI_NOR_HAS_TB)
 		nor->flags |= SNOR_F_HAS_SR_TB;
+	if (info->flags & DISABLE_CE)
+		nor->flags |= SNOR_F_DISABLE_CE;
 
 #ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
 	/* prefer "small sector" erase if possible */
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index c425c7b..2d0b967 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -119,6 +119,7 @@ enum spi_nor_ops {
 enum spi_nor_option_flags {
 	SNOR_F_USE_FSR		= BIT(0),
 	SNOR_F_HAS_SR_TB	= BIT(1),
+	SNOR_F_DISABLE_CE	= BIT(2),
 };
 
 /**
-- 
2.7.4



From hch at infradead.org  Fri Oct 21 06:05:58 2016
From: hch at infradead.org (Christoph Hellwig)
Date: Fri, 21 Oct 2016 06:05:58 -0700
Subject: [PATCH 01/26] fscrypto: Add buffer operations
In-Reply-To: <1477054121-10198-2-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
 <1477054121-10198-2-git-send-email-richard@nod.at>
Message-ID: <20161021130558.GA2411@infradead.org>

On Fri, Oct 21, 2016 at 02:48:16PM +0200, Richard Weinberger wrote:
> Not all filesystems operate on pages, therefore offer
> operations to en/decrypt buffers.
> Of course these buffers have to be allocated in a way such that
> the kernel crypto framework can work with them.

Which means they need to be backed by the page allocator eventually.
I think we'd better off providing the pages from ubifs from the API
point of view.  What are the issues with doing that?


From richard at nod.at  Fri Oct 21 05:48:41 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 14:48:41 +0200
Subject: [PATCH 26/26] ubifs: Raise write version to 5
In-Reply-To: <1477054121-10198-1-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
Message-ID: <1477054121-10198-27-git-send-email-richard@nod.at>

Starting with version 5 the following properties change:
 - UBIFS_FLG_DOUBLE_HASH is mandatory
 - UBIFS_FLG_ENCRYPTION is optional but depdens on UBIFS_FLG_DOUBLE_HASH
 - Filesystems with unknown super block flags will be rejected, this
   allows us in future to add new features without raising the UBIFS
   write version.

Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/ubifs/sb.c          | 17 +++++++++++++++++
 fs/ubifs/ubifs-media.h |  4 +++-
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c
index 54cef70ea16f..7f1ead29e727 100644
--- a/fs/ubifs/sb.c
+++ b/fs/ubifs/sb.c
@@ -466,6 +466,16 @@ static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup)
 		goto failed;
 	}
 
+	if (!c->double_hash && c->fmt_version >= 5) {
+		err = 16;
+		goto failed;
+	}
+
+	if (c->encrypted && c->fmt_version < 5) {
+		err = 17;
+		goto failed;
+	}
+
 	return 0;
 
 failed:
@@ -624,6 +634,13 @@ int ubifs_read_superblock(struct ubifs_info *c)
 	c->double_hash = !!(sup_flags & UBIFS_FLG_DOUBLE_HASH);
 	c->encrypted = !!(sup_flags & UBIFS_FLG_ENCRYPTION);
 
+	if ((sup_flags & ~UBIFS_FLG_MASK) != 0) {
+		ubifs_err(c, "Unknown feature flags found: %#x",
+			  sup_flags & ~UBIFS_FLG_MASK);
+		err = -EINVAL;
+		goto out;
+	}
+
 #ifndef CONFIG_UBIFS_FS_ENCRYPTION
 	if (c->encrypted) {
 		ubifs_err(c, "file system contains encrypted files but UBIFS"
diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h
index bdc7935a5e41..e8c23c9d4f4a 100644
--- a/fs/ubifs/ubifs-media.h
+++ b/fs/ubifs/ubifs-media.h
@@ -46,7 +46,7 @@
  * UBIFS went into mainline kernel with format version 4. The older formats
  * were development formats.
  */
-#define UBIFS_FORMAT_VERSION 4
+#define UBIFS_FORMAT_VERSION 5
 
 /*
  * Read-only compatibility version. If the UBIFS format is changed, older UBIFS
@@ -429,6 +429,8 @@ enum {
 	UBIFS_FLG_ENCRYPTION = 0x10,
 };
 
+#define UBIFS_FLG_MASK (UBIFS_FLG_BIGLPT|UBIFS_FLG_SPACE_FIXUP|UBIFS_FLG_DOUBLE_HASH|UBIFS_FLG_ENCRYPTION)
+
 /**
  * struct ubifs_ch - common header node.
  * @magic: UBIFS node magic number (%UBIFS_NODE_MAGIC)
-- 
2.7.3



From richard at nod.at  Fri Oct 21 06:07:57 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 15:07:57 +0200
Subject: UBIFS with dma on 4.6 kernel is not working
In-Reply-To: <20161021125313.GA16754@infradead.org>
References: <DA6901612C71B84D91459DE817C418AE26DF0F2B@XAP-PVEXMBX01.xlnx.xilinx.com>
 <519a83bf-1244-5151-b873-bb8e1f2db3c6@nod.at>
 <20161021125313.GA16754@infradead.org>
Message-ID: <c0b0098d-3a68-3a4a-0b7e-a1d95dd4aafc@nod.at>

Christoph,

On 21.10.2016 14:53, Christoph Hellwig wrote:
> On Fri, Oct 21, 2016 at 11:29:16AM +0200, Richard Weinberger wrote:
>> DMA to vmalloced memory not good, it may work by chance if you transfer
>> less than PAGE_SIZE.
>> Especially on ARM.
> 
> DMA to vmalloc'ed or vmap memory is perfectly fine, you just have to be
> very careful.
> 
> I would suggest to not expose the vmalloc address to the lower layers
> that do DMA, but instead expose the pages, either as an array or
> scatterlist.  Either allocate the pages using the normal page allocator
> and then use vm_map_ram to generate a virtual address for them (that
> is what XFS does for it's large metadata objects for example).  Or if
> you can't do that iterate over the vmalloc address in page size chunks
> and use vmalloc_to_page (we still also do that for one piece of legacy
> cruft in XFS, but I'd rather avoid that for new designs).
> 

Hmm, thought this is still problematic on VIVT architectures.
Boris tried to provide a solution for that some time ago:
http://www.spinics.net/lists/arm-kernel/msg494025.html

Thanks,
//richard


From hch at infradead.org  Fri Oct 21 06:15:05 2016
From: hch at infradead.org (Christoph Hellwig)
Date: Fri, 21 Oct 2016 06:15:05 -0700
Subject: UBIFS with dma on 4.6 kernel is not working
In-Reply-To: <c0b0098d-3a68-3a4a-0b7e-a1d95dd4aafc@nod.at>
References: <DA6901612C71B84D91459DE817C418AE26DF0F2B@XAP-PVEXMBX01.xlnx.xilinx.com>
 <519a83bf-1244-5151-b873-bb8e1f2db3c6@nod.at>
 <20161021125313.GA16754@infradead.org>
 <c0b0098d-3a68-3a4a-0b7e-a1d95dd4aafc@nod.at>
Message-ID: <20161021131505.GA25942@infradead.org>

On Fri, Oct 21, 2016 at 03:07:57PM +0200, Richard Weinberger wrote:
> Hmm, thought this is still problematic on VIVT architectures.
> Boris tried to provide a solution for that some time ago:
> http://www.spinics.net/lists/arm-kernel/msg494025.html

Things have been working fine for approx 10 years when using
flush_kernel_vmap_range before doing I/O using the physical addresses and
then invalidate_kernel_vmap_range when completing the I/O and going back
to using the virtual mapping for XFS.

Of course all this assumes at least the higher level that did the
vm_map_ram operation knows about this dance between virtually mapped and
physiscal addresses. 


From richard at nod.at  Fri Oct 21 06:17:03 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 15:17:03 +0200
Subject: [PATCH 01/26] fscrypto: Add buffer operations
In-Reply-To: <20161021130558.GA2411@infradead.org>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
 <1477054121-10198-2-git-send-email-richard@nod.at>
 <20161021130558.GA2411@infradead.org>
Message-ID: <9c80d1d0-0237-606f-91ce-a004c3694aa5@nod.at>

Christoph,

On 21.10.2016 15:05, Christoph Hellwig wrote:
> On Fri, Oct 21, 2016 at 02:48:16PM +0200, Richard Weinberger wrote:
>> Not all filesystems operate on pages, therefore offer
>> operations to en/decrypt buffers.
>> Of course these buffers have to be allocated in a way such that
>> the kernel crypto framework can work with them.
> 
> Which means they need to be backed by the page allocator eventually.
> I think we'd better off providing the pages from ubifs from the API
> point of view.  What are the issues with doing that?
> 

UBIFS works on kmalloc()'ed buffers where it constructs the NAND/NOR pages
which will be written to the MTD. JFFS2 does the same.

So you suggest obtaining the struct page from the kmalloc()'ed buffer and
feeding it into fscrypto? This should work too.
I found the buffer operations approach more suitable.

Another reason why I did the buffer functions is because fscrypt_encrypt_page()
always allocates a bounce page as temporary memory. For ext4 this is needed,
for UBIFS not.
UBIFS has already a construction buffer, especially since it also does compression.

Thanks,
//richard


From hch at infradead.org  Fri Oct 21 06:24:00 2016
From: hch at infradead.org (Christoph Hellwig)
Date: Fri, 21 Oct 2016 06:24:00 -0700
Subject: [PATCH 01/26] fscrypto: Add buffer operations
In-Reply-To: <9c80d1d0-0237-606f-91ce-a004c3694aa5@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
 <1477054121-10198-2-git-send-email-richard@nod.at>
 <20161021130558.GA2411@infradead.org>
 <9c80d1d0-0237-606f-91ce-a004c3694aa5@nod.at>
Message-ID: <20161021132400.GA28880@infradead.org>

On Fri, Oct 21, 2016 at 03:17:03PM +0200, Richard Weinberger wrote:
> UBIFS works on kmalloc()'ed buffers where it constructs the NAND/NOR pages
> which will be written to the MTD. JFFS2 does the same.

Yes, you can trivially do a virt_to_page on a kmalloc buffer.

> Another reason why I did the buffer functions is because fscrypt_encrypt_page()
> always allocates a bounce page as temporary memory. For ext4 this is needed,
> for UBIFS not.
> UBIFS has already a construction buffer, especially since it also does compression.

We should defintively find a way to avoid that, but it's a separate
issue from adding another API just to pass buffers.


From cyrille.pitchen at atmel.com  Fri Oct 21 06:44:45 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Fri, 21 Oct 2016 15:44:45 +0200
Subject: [PATCH] mtd: spi-nor: fixed spansion quad enable
In-Reply-To: <f45e1845-573f-d0b7-0f23-abd035f25945@atmel.com>
References: <1476971026-9665-1-git-send-email-joel.esponde@honeywell.com>
 <56670303-e8e8-fb2c-e043-035c566f347c@atmel.com>
 <F6CD090A69E64C4289DC608E1C5D20242544AEF1@DE08W1305.global.ds.honeywell.com>
 <f45e1845-573f-d0b7-0f23-abd035f25945@atmel.com>
Message-ID: <83e02f1d-2c58-10cc-567c-2a58a363767e@atmel.com>

Le 21/10/2016 ? 14:50, Cyrille Pitchen a ?crit :
> Hi Jo?l,
> 
> Le 21/10/2016 ? 12:37, Esponde, Joel a ?crit :
>> Hi Cyrille,
>>
>> First, thanks for your comments !
>> Please, see below mines.
>>
>>> -----Message d'origine-----
>>> De : Cyrille Pitchen [mailto:cyrille.pitchen at atmel.com]
>>> Envoy? : jeudi 20 octobre 2016 17:23
>>> ? : Esponde, Joel <Joel.Esponde at Honeywell.com>; linux-
>>> mtd at lists.infradead.org
>>> Objet : Re: [PATCH] mtd: spi-nor: fixed spansion quad enable
>>>
>>> Hi Jo?l,
>>>
>>> Le 20/10/2016 ? 15:43, Jo?l Esponde a ?crit :
>>>> With the S25FL127S nor flash part, each writing to the configuration register
>>> takes hundreds of ms. During that  time, no more accesses to the flash
>>> should be done (even reads).
>>>>
>>>> This commit adds:
>>>> - a pre check of the quad enable bit to avoid a useless and time
>>>> consuming writing to the flash,
>>>> - a wait loop after the register writing until the flash finishes its work.
>>>>
>>>> This issue could make rootfs mounting fail when the latter was done too
>>> much closely to this quad enable bit setting step. And in this case, a driver as
>>> UBIFS may try to recover the filesystem and may broke it completely.
>>>> ---
>>>>  drivers/mtd/spi-nor/spi-nor.c | 31 +++++++++++++++++++++++++++----
>>>>  1 file changed, 27 insertions(+), 4 deletions(-)
>>>>
>>>> diff --git a/drivers/mtd/spi-nor/spi-nor.c
>>>> b/drivers/mtd/spi-nor/spi-nor.c index d0fc165..df43cd7 100644
>>>> --- a/drivers/mtd/spi-nor/spi-nor.c
>>>> +++ b/drivers/mtd/spi-nor/spi-nor.c
>>>> @@ -1246,18 +1246,41 @@ static int spansion_quad_enable(struct spi_nor
>>> *nor)
>>>>  	int ret;
>>>>  	int quad_en = CR_QUAD_EN_SPAN << 8;
>>>>
>>>> +	/* check quad enable bit
>>>> +	 * as S25FL127S takes 200 ms to execute each write of SR & CR
>>>> +	 * registers even if data is the same, write step will be shorted
>>>> +	 * if not needed
>>>> +	 */
>>>> +	ret = read_cr(nor);
>>>
>>> Sorry but the Read Configuration Register (35h) command is not supported
>>> by all Spansion (or Spansion-like) memories.
>>
>> I have a doubt here, if this is really the case, why read_cr() is already called at the end of the current implementation of the spansion_quad_enable() function to check that quad enable bit is set? 
>>
> 
> That's a very good remark and I think the reason is that the current
> implementation of spansion_quad_enable() suffers from a bug but this one is
> almost harmless:
> 
> I assume there is pull-up resistor on the MISO line: spansion_quad_enable()
> sends a 35h command, which is not supported hence ignored by some memories,
> then it reads a 1-byte value of FFh due to the pull-up so we pass the test
> which checks that the Quad Enable bit has successfully been set.
> 
> Then if we now add the same test before sending the Write Status (01h) command
> with 2 bytes (SR1 then CR/SR2), we also read a FFh value for the Configuration
> Register hence we skip the Write Status command because we think the Quad
> Enable bit has already been set but if we are using a brand new memory still
> using its factory settings the Quad Enable has never been set and won't be set
> since we now skip the Write Status command.
> 
> I think this what currently happens but I need to check with one of my memory
> samples if I can find one which doesn't support the Read CR command but I
> not sure to have such a sample...

The JESD216B specification clearly deals with 2 cases: a first one where the
35h command is not used, I guess because not supported, and a second case using
both the 05h and 35h commands to read the SR1 and SR2/CR1 memory registers
before writing both SR1 and SR2/CR1 with the 01h command.

However I can't provide any example of memory sample falling into the first
case. I guess case 1 only applies to old and buggy memories and maybe not so
used in production.
Besides, your patch is great so I wonder whether it makes sense to reject it
just because it might introduce a regression with some unidentified memories...
If so, I think we could still find a workaround later to handle those very
few (deprecated) parts.

The S25FL127S memory is still recommended by Cypress/Spansion for new designs.

> 
> spansion_quad_enable() is used by QSPI memories from some manufacturers other
> than Spansion.
> 
>>> For more details, please refer to the JEDEC JESD216B specification, especially
>>> the part dealing with the "Quad Enable Requirements". An extract of this
>>> specification can also be found in this patch:
>>> https://patchwork.ozlabs.org/patch/678408/
>>>
>>> Please have a look at values 001b, 100b and 101b for the bits[22:20] of the
>>> 15th DWORD.
>>>
>>> I think your patch is likely to introduce a regression on some old memory
>>> parts.
>>>
>>> However, *if* your S25FL127S memory implements the SFDP tables
>>> correctly, bits[22:20] of the 15th DWORD should be set to 101b, hence using
>>> SFDP patch above should fix the issue:
>>> spansion_new_quad_enable() will be called instead of the current
>>> spansion_quad_enable(). This new function adds the very same test on the
>>> Quad Enable bit as your patch does.
>>>
>>> If you want to test the SFDP patch, you will need to apply the whole series
>>> which introduces some improvement on QSPI memory support:
>>> http://lists.infradead.org/pipermail/linux-mtd/2016-October/069554.html
>>
>> Your patch using SFDP to dynamically manage memories seems really great (from a feature point of view, I am not yet able to have an opinion on the implementation...).
>>
>>>
>>> I'm just cautious with Spansion memories: I tested one sample, and I guess it
>>> was a S25FL127S, which claimed to be compliant with JESD216 rev B (minor 6)
>>> but words after the 9th one were all 0xffffffff.
>>> JESD216 (minor 0) describes only 9 DWORDs in the Basic Flash Parameter
>>> Table
>>> JESD216 rev A (minor 5) introduces 7 new DWORDS, hence 16 DWORDS in the
>>> (BFPT).
>>> the 15th DWORD provides the Quad Enable Requirements, which describes
>>> the procedure to set the Quad Enable bit.
>>>
>>> If the BFPT of your S25FL127S is incomplete but the memory still claiming to
>>> be
>>> JESD216 rev B compliant, neither spansion_quad_enable() nor
>>> spansion_new_quad_enable() would be called. Since the Quad Enable bit is
>>> non-volatile on Spansion memories, it will work if the bit as already been set
>>> before.
>>>
>>
>> See below for code that should be IMO added because of the non-volatibility of spansion memories.
>>
>>>> +	if (ret < 0) {
>>>> +		dev_err(nor->dev, "error %d reading CR\n", ret);
>>>> +		return ret;
>>>> +	}
>>>> +	if (ret & CR_QUAD_EN_SPAN) {
>>>> +		/* quad enable bit is already set */
>>>> +		return 0;
>>>> +	}
>>>> +
>>>> +	/* set SR & CR, enable quad I/O */
>>>>  	write_enable(nor);
>>>>
>>>>  	ret = write_sr_cr(nor, quad_en);
>>>>  	if (ret < 0) {
>>>> -		dev_err(nor->dev,
>>>> -			"error while writing configuration register\n");
>>>> +		dev_err(nor->dev, "error while writing SR and CR
>>> registers\n");
>>>>  		return -EINVAL;
>>>>  	}
>>>>
>>>> -	/* read back and check it */
>>>> +	ret = spi_nor_wait_till_ready(nor);
>>>> +	if (ret)
>>>> +		return ret;
>>>> +
>>
>> I think that this wait is required with every memories that store Quad Enable bit in a non-volatile way.
>> I am using today a stripped down kernel with a rootfs based on UBIFS.
>> When this bit is set, UBIFS will start reading the memory 100ms after.
>> As this bit writing step takes up to 200ms, spansion memory is not ready and UBIFS will fail when trying to read the content of the partition.
>> As UBIFS has a recovery mechanism, it will even broke the file system.
>>
> 
> I agree with you about adding the spi_nor_wait_till_ready() call. I plan to
> add it in my SFDP patch for the spansion_new_quad_enable(), if not done yet.
> 
>>>> +	/* read CR and check it */
>>>>  	ret = read_cr(nor);
>>>> -	if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
>>>> +	if (ret < 0) {
>>>> +		dev_err(nor->dev, "error %d reading CR\n", ret);
>>>> +		return ret;
>>>> +	}
>>
>> This test on the validity of the returned data may also be useful.
>> When negative errors are returned, it is likely that the CR_QUAD_EN_SPAN bit is set, and so, next test may be meaningless...
>>
>>>> +	if (!(ret & CR_QUAD_EN_SPAN)) {
>>>>  		dev_err(nor->dev, "Spansion Quad bit not set\n");
>>>>  		return -EINVAL;
>>>>  	}
>>>>
>>
>> Best regards,
>> Jo?l
>>
> 
> Best regards,
> 
> Cyrille
> 
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/
> 



From tytso at mit.edu  Fri Oct 21 07:57:20 2016
From: tytso at mit.edu (Theodore Ts'o)
Date: Fri, 21 Oct 2016 10:57:20 -0400
Subject: [PATCH 02/26] fscrypto: Constify struct inode pointer
In-Reply-To: <1477054121-10198-3-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
 <1477054121-10198-3-git-send-email-richard@nod.at>
Message-ID: <20161021145720.raaeyivtonf2ynmb@thunk.org>

On Fri, Oct 21, 2016 at 02:48:17PM +0200, Richard Weinberger wrote:
> Some filesystems, such as UBIFS, maintain a const pointer
> for struct inode.
> 
>  /* fname.c */
> -extern int fscrypt_setup_filename(struct inode *, const struct qstr *,
> -				int lookup, struct fscrypt_name *);
> +extern int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
> +			   int lookup, struct fscrypt_name *fname);

Was it deliberate that you didn't add a const pointer here?

I take it that ubifs is basically using const in certain places to
essentially promise that those functions don't actually modify the
inode structure?

							- Ted


From richard at nod.at  Fri Oct 21 08:10:48 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 17:10:48 +0200
Subject: [PATCH 02/26] fscrypto: Constify struct inode pointer
In-Reply-To: <20161021145720.raaeyivtonf2ynmb@thunk.org>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
 <1477054121-10198-3-git-send-email-richard@nod.at>
 <20161021145720.raaeyivtonf2ynmb@thunk.org>
Message-ID: <99679ee6-ccda-0c58-3278-14fb8cb8534c@nod.at>

Ted,

On 21.10.2016 16:57, Theodore Ts'o wrote:
> On Fri, Oct 21, 2016 at 02:48:17PM +0200, Richard Weinberger wrote:
>> Some filesystems, such as UBIFS, maintain a const pointer
>> for struct inode.
>>
>>  /* fname.c */
>> -extern int fscrypt_setup_filename(struct inode *, const struct qstr *,
>> -				int lookup, struct fscrypt_name *);
>> +extern int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
>> +			   int lookup, struct fscrypt_name *fname);
> 
> Was it deliberate that you didn't add a const pointer here?

Erm, no. Either I forgot or while rebasing my mess to something
sane the change got lost.

> I take it that ubifs is basically using const in certain places to
> essentially promise that those functions don't actually modify the
> inode structure?

Yes.

Thanks,
//richard


From tytso at mit.edu  Fri Oct 21 08:14:45 2016
From: tytso at mit.edu (Theodore Ts'o)
Date: Fri, 21 Oct 2016 11:14:45 -0400
Subject: [PATCH 01/26] fscrypto: Add buffer operations
In-Reply-To: <20161021132400.GA28880@infradead.org>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
 <1477054121-10198-2-git-send-email-richard@nod.at>
 <20161021130558.GA2411@infradead.org>
 <9c80d1d0-0237-606f-91ce-a004c3694aa5@nod.at>
 <20161021132400.GA28880@infradead.org>
Message-ID: <20161021151445.xcqzggh27nzdqmuh@thunk.org>

On Fri, Oct 21, 2016 at 06:24:00AM -0700, Christoph Hellwig wrote:
> > Another reason why I did the buffer functions is because fscrypt_encrypt_page()
> > always allocates a bounce page as temporary memory. For ext4 this is needed,
> > for UBIFS not.
> > UBIFS has already a construction buffer, especially since it also does compression.
> 
> We should defintively find a way to avoid that, but it's a separate
> issue from adding another API just to pass buffers.

Hmm, one approach we could use is to avoid allocating a bounce page if
the passed-in plaintext_page has the PageSlab flag set.  That would
work for ubifs, but if there are file systems that are using
get_free_page() for their particular construction buffer. it wouldn't
work for them.

Perhaps more importantly, are you planning on making compression +
encryption work?  Some security purists will say that compression +
encryption will leak some information about the plaintext (which is
technically true, but it's much like the people who don't want make it
easy to discard + encrypt, which Linus recently railed against).  So
my take is that as long as users understand that there are minor
leakage issues with compression + encryption, we should let them do
that --- and that would be an argument for supporting buffer
operations, and only requiring that the buffer size must be a multiple
of the underlying encryption block size.

						- Ted


From mhalcrow at google.com  Fri Oct 21 10:14:39 2016
From: mhalcrow at google.com (Michael Halcrow)
Date: Fri, 21 Oct 2016 10:14:39 -0700
Subject: [PATCH 15/26] ubifs: Implement encrypt/decrypt for all IO
In-Reply-To: <1477054121-10198-16-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
 <1477054121-10198-16-git-send-email-richard@nod.at>
Message-ID: <20161021171439.GA17121@google.com>

On Fri, Oct 21, 2016 at 02:48:30PM +0200, Richard Weinberger wrote:
> Signed-off-by: Richard Weinberger <richard at nod.at>
> ---
>  fs/ubifs/file.c    |  36 ++++++++++++++++++
>  fs/ubifs/journal.c | 105 +++++++++++++++++++++++++++++++++++++++++++----------
>  fs/ubifs/super.c   |   6 ++-
>  fs/ubifs/ubifs.h   |   6 +++
>  4 files changed, 131 insertions(+), 22 deletions(-)
> 
> diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
> index bd0049788e24..60e089d50c82 100644
> --- a/fs/ubifs/file.c
> +++ b/fs/ubifs/file.c
> @@ -78,6 +78,24 @@ static int read_block(struct inode *inode, void *addr, unsigned int block,
>  		goto dump;
>  
>  	dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
> +
> +	if (ubifs_crypt_is_encrypted(inode)) {
> +		int clen = le16_to_cpu(dn->compr_size);
> +
> +		if (clen <= 0 || clen > UBIFS_BLOCK_SIZE || clen > dlen)
> +			goto dump;
> +
> +		ubifs_assert(dlen <= UBIFS_BLOCK_SIZE);
> +		err = fscrypt_decrypt_buffer(inode, &dn->data, &dn->data, dlen, block, GFP_NOFS);
> +		if (err) {
> +			ubifs_err(c, "fscrypt_decrypt_buffer failed: %i", err);
> +			return err;
> +		}
> +
> +		ubifs_assert(clen <= dlen);
> +		dlen = clen;
> +	}
> +
>  	out_len = UBIFS_BLOCK_SIZE;
>  	err = ubifs_decompress(c, &dn->data, dlen, addr, &out_len,
>  			       le16_to_cpu(dn->compr_type));
> @@ -650,6 +668,24 @@ static int populate_page(struct ubifs_info *c, struct page *page,
>  
>  			dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
>  			out_len = UBIFS_BLOCK_SIZE;
> +
> +			if (ubifs_crypt_is_encrypted(inode)) {
> +				int clen = le16_to_cpu(dn->compr_size);
> +
> +				if (clen <= 0 || clen > UBIFS_BLOCK_SIZE || clen > dlen)
> +					goto out_err;
> +
> +				ubifs_assert(dlen <= UBIFS_BLOCK_SIZE);
> +				err = fscrypt_decrypt_buffer(inode, &dn->data, &dn->data, dlen, page_block, GFP_NOFS);
> +				if (err) {
> +					ubifs_err(c, "fscrypt_decrypt_buffer failed: %i", err);
> +					goto out_err;
> +				}
> +
> +				ubifs_assert(clen <= dlen);
> +				dlen = clen;
> +			}
> +
>  			err = ubifs_decompress(c, &dn->data, dlen, addr, &out_len,
>  					       le16_to_cpu(dn->compr_type));
>  			if (err || len != out_len)
> diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c
> index a643de4e3d91..da694e520ec8 100644
> --- a/fs/ubifs/journal.c
> +++ b/fs/ubifs/journal.c
> @@ -691,11 +691,15 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
>  	int err, lnum, offs, compr_type, out_len;
>  	int dlen = COMPRESSED_DATA_NODE_BUF_SZ, allocated = 1;
>  	struct ubifs_inode *ui = ubifs_inode(inode);
> +	bool encrypted = ubifs_crypt_is_encrypted(inode);
>  
>  	dbg_jnlk(key, "ino %lu, blk %u, len %d, key ",
>  		(unsigned long)key_inum(c, key), key_block(c, key), len);
>  	ubifs_assert(len <= UBIFS_BLOCK_SIZE);
>  
> +	if (encrypted)
> +		dlen += UBIFS_CIPHER_BLOCK_SIZE;
> +
>  	data = kmalloc(dlen, GFP_NOFS | __GFP_NOWARN);
>  	if (!data) {
>  		/*
> @@ -724,6 +728,26 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
>  	ubifs_compress(c, buf, len, &data->data, &out_len, &compr_type);

Compress-before-encrypt is a hazard.

http://www.iacr.org/cryptodb/archive/2002/FSE/3091/3091.pdf

>  	ubifs_assert(out_len <= UBIFS_BLOCK_SIZE);
>  
> +	if (encrypted) {
> +		void *p = &data->data;
> +		int plen = round_up(out_len, UBIFS_CIPHER_BLOCK_SIZE);
> +
> +		data->compr_size = cpu_to_le16(out_len);
> +
> +		if (plen != out_len) {
> +			memset(p + out_len, 0, plen - out_len);
> +			out_len = plen;
> +		}
> +
> +		err = fscrypt_encrypt_buffer(inode, &data->data, &data->data, out_len, key_block(c, key), GFP_NOFS);
> +		if (err) {
> +			ubifs_err(c, "fscrypt_encrypt_buffer failed: %i", err);
> +			goto out_free;
> +		}
> +	} else {
> +		data->compr_size = 0;
> +	}
> +
>  	dlen = UBIFS_DATA_NODE_SZ + out_len;
>  	data->compr_type = cpu_to_le16(compr_type);
>  
> @@ -1083,31 +1107,79 @@ out_free:
>  }
>  
>  /**
> - * recomp_data_node - re-compress a truncated data node.
> + * truncate_data_node - re-compress/encrypt a truncated data node.
> + * @c: UBIFS file-system description object
> + * @inode: inode which referes to the data node
> + * @block: data block number
>   * @dn: data node to re-compress
>   * @new_len: new length
>   *
>   * This function is used when an inode is truncated and the last data node of
> - * the inode has to be re-compressed and re-written.
> + * the inode has to be re-compressed/encrypted and re-written.
>   */
> -static int recomp_data_node(const struct ubifs_info *c,
> -			    struct ubifs_data_node *dn, int *new_len)
> +static int truncate_data_node(const struct ubifs_info *c, struct inode *inode,
> +			      unsigned int block, struct ubifs_data_node *dn,
> +			      int *new_len)
>  {
>  	void *buf;
> -	int err, len, compr_type, out_len;
> +	int err, dlen, compr_type, out_len, old_dlen;
>  
>  	out_len = le32_to_cpu(dn->size);
>  	buf = kmalloc(out_len * WORST_COMPR_FACTOR, GFP_NOFS);
>  	if (!buf)
>  		return -ENOMEM;
>  
> -	len = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
> +	dlen = old_dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
>  	compr_type = le16_to_cpu(dn->compr_type);
> -	err = ubifs_decompress(c, &dn->data, len, buf, &out_len, compr_type);
> -	if (err)
> -		goto out;
>  
> -	ubifs_compress(c, buf, *new_len, &dn->data, &out_len, &compr_type);
> +	if (ubifs_crypt_is_encrypted(inode)) {
> +		int clen = le16_to_cpu(dn->compr_size);
> +
> +		if (clen <= 0 || clen > UBIFS_BLOCK_SIZE || clen > dlen) {
> +			ubifs_err(c, "bad compr_size: %i", clen);
> +			err = -EINVAL;
> +			goto out;
> +		}
> +
> +		err = fscrypt_decrypt_buffer(inode, &dn->data, &dn->data, dlen, block, GFP_NOFS);
> +		if (err) {
> +			ubifs_err(c, "fscrypt_decrypt_buffer failed: %i", err);
> +			goto out;
> +		}
> +
> +		ubifs_assert(clen <= dlen);
> +		dlen = clen;
> +	}
> +
> +	if (compr_type != UBIFS_COMPR_NONE) {
> +		err = ubifs_decompress(c, &dn->data, dlen, buf, &out_len, compr_type);
> +		if (err)
> +			goto out;
> +
> +		ubifs_compress(c, buf, *new_len, &dn->data, &out_len, &compr_type);
> +	}
> +
> +	if (ubifs_crypt_is_encrypted(inode)) {
> +		void *p = &dn->data;
> +		int plen = round_up(out_len, UBIFS_CIPHER_BLOCK_SIZE);
> +
> +		ubifs_assert(old_dlen >= plen);
> +		dn->compr_size = cpu_to_le16(out_len);
> +
> +		if (plen != out_len) {
> +			memset(p + out_len, 0, plen - out_len);
> +			out_len = plen;
> +		}
> +
> +		err = fscrypt_encrypt_buffer(inode, &dn->data, &dn->data, out_len, block, GFP_NOFS);
> +		if (err) {
> +			ubifs_msg(c, "fscrypt_encrypt_buffer failed: %i", err);
> +			goto out;
> +		}
> +	} else {
> +		dn->compr_size = 0;
> +	}
> +
>  	ubifs_assert(out_len <= UBIFS_BLOCK_SIZE);
>  	dn->compr_type = cpu_to_le16(compr_type);
>  	dn->size = cpu_to_le32(*new_len);
> @@ -1179,16 +1251,9 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
>  			if (le32_to_cpu(dn->size) <= dlen)
>  				dlen = 0; /* Nothing to do */
>  			else {
> -				int compr_type = le16_to_cpu(dn->compr_type);
> -
> -				if (compr_type != UBIFS_COMPR_NONE) {
> -					err = recomp_data_node(c, dn, &dlen);
> -					if (err)
> -						goto out_free;
> -				} else {
> -					dn->size = cpu_to_le32(dlen);
> -					dlen += UBIFS_DATA_NODE_SZ;
> -				}
> +				err = truncate_data_node(c, inode, blk, dn, &dlen);
> +				if (err)
> +					goto out_free;
>  			}
>  		}
>  	}
> diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
> index a31222947265..ae25c908fbe5 100644
> --- a/fs/ubifs/super.c
> +++ b/fs/ubifs/super.c
> @@ -1210,7 +1210,8 @@ static int mount_ubifs(struct ubifs_info *c)
>  		bu_init(c);
>  
>  	if (!c->ro_mount) {
> -		c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ,
> +		c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ + \
> +					       UBIFS_CIPHER_BLOCK_SIZE,
>  					       GFP_KERNEL);
>  		if (!c->write_reserve_buf)
>  			goto out_free;
> @@ -1623,7 +1624,8 @@ static int ubifs_remount_rw(struct ubifs_info *c)
>  		goto out;
>  	}
>  
> -	c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ, GFP_KERNEL);
> +	c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ + \
> +				       UBIFS_CIPHER_BLOCK_SIZE, GFP_KERNEL);
>  	if (!c->write_reserve_buf) {
>  		err = -ENOMEM;
>  		goto out;
> diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
> index 63dd027727ca..6c56a08afcd7 100644
> --- a/fs/ubifs/ubifs.h
> +++ b/fs/ubifs/ubifs.h
> @@ -139,6 +139,12 @@
>   */
>  #define WORST_COMPR_FACTOR 2
>  
> +#ifdef CONFIG_UBIFS_FS_ENCRYPTION
> +#define UBIFS_CIPHER_BLOCK_SIZE FS_CRYPTO_BLOCK_SIZE
> +#else
> +#define UBIFS_CIPHER_BLOCK_SIZE 0
> +#endif
> +
>  /*
>   * How much memory is needed for a buffer where we compress a data node.
>   */
> -- 
> 2.7.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


From richard at nod.at  Fri Oct 21 10:21:04 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 19:21:04 +0200
Subject: [PATCH 15/26] ubifs: Implement encrypt/decrypt for all IO
In-Reply-To: <20161021171439.GA17121@google.com>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
 <1477054121-10198-16-git-send-email-richard@nod.at>
 <20161021171439.GA17121@google.com>
Message-ID: <78f09113-fcc3-c2d2-9849-ba980cd9c0b4@nod.at>

On 21.10.2016 19:14, Michael Halcrow wrote:
> Compress-before-encrypt is a hazard.
> 
> http://www.iacr.org/cryptodb/archive/2002/FSE/3091/3091.pdf

I'm fully aware of that. But as usual it depends on the use case.
Compression is optional in UBIFS, paranoid users can disable it
when encryption is enabled.

Thanks,
//richard


From mhalcrow at google.com  Fri Oct 21 10:31:54 2016
From: mhalcrow at google.com (Michael Halcrow)
Date: Fri, 21 Oct 2016 10:31:54 -0700
Subject: [PATCH 26/26] ubifs: Raise write version to 5
In-Reply-To: <1477054121-10198-27-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
 <1477054121-10198-27-git-send-email-richard@nod.at>
Message-ID: <20161021173154.GB17121@google.com>

On Fri, Oct 21, 2016 at 02:48:41PM +0200, Richard Weinberger wrote:
> Starting with version 5 the following properties change:
>  - UBIFS_FLG_DOUBLE_HASH is mandatory
>  - UBIFS_FLG_ENCRYPTION is optional but depdens on UBIFS_FLG_DOUBLE_HASH
>  - Filesystems with unknown super block flags will be rejected, this
>    allows us in future to add new features without raising the UBIFS
>    write version.
> 
> Signed-off-by: Richard Weinberger <richard at nod.at>
> ---
>  fs/ubifs/sb.c          | 17 +++++++++++++++++
>  fs/ubifs/ubifs-media.h |  4 +++-
>  2 files changed, 20 insertions(+), 1 deletion(-)
> 
> diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c
> index 54cef70ea16f..7f1ead29e727 100644
> --- a/fs/ubifs/sb.c
> +++ b/fs/ubifs/sb.c
> @@ -466,6 +466,16 @@ static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup)
>  		goto failed;
>  	}
>  
> +	if (!c->double_hash && c->fmt_version >= 5) {
> +		err = 16;
> +		goto failed;
> +	}
> +
> +	if (c->encrypted && c->fmt_version < 5) {
> +		err = 17;
> +		goto failed;
> +	}
> +
>  	return 0;
>  
>  failed:
> @@ -624,6 +634,13 @@ int ubifs_read_superblock(struct ubifs_info *c)
>  	c->double_hash = !!(sup_flags & UBIFS_FLG_DOUBLE_HASH);
>  	c->encrypted = !!(sup_flags & UBIFS_FLG_ENCRYPTION);
>  
> +	if ((sup_flags & ~UBIFS_FLG_MASK) != 0) {
> +		ubifs_err(c, "Unknown feature flags found: %#x",
> +			  sup_flags & ~UBIFS_FLG_MASK);
> +		err = -EINVAL;
> +		goto out;
> +	}
> +
>  #ifndef CONFIG_UBIFS_FS_ENCRYPTION
>  	if (c->encrypted) {
>  		ubifs_err(c, "file system contains encrypted files but UBIFS"
> diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h
> index bdc7935a5e41..e8c23c9d4f4a 100644
> --- a/fs/ubifs/ubifs-media.h
> +++ b/fs/ubifs/ubifs-media.h
> @@ -46,7 +46,7 @@
>   * UBIFS went into mainline kernel with format version 4. The older formats
>   * were development formats.
>   */
> -#define UBIFS_FORMAT_VERSION 4
> +#define UBIFS_FORMAT_VERSION 5

Alex Cope is working on a fix for file name encryption in ext4 so that
common plaintext prefixes don't result in common ciphertext prefixes.
Older kernels will not be able to read the new file names.

>  
>  /*
>   * Read-only compatibility version. If the UBIFS format is changed, older UBIFS
> @@ -429,6 +429,8 @@ enum {
>  	UBIFS_FLG_ENCRYPTION = 0x10,
>  };
>  
> +#define UBIFS_FLG_MASK (UBIFS_FLG_BIGLPT|UBIFS_FLG_SPACE_FIXUP|UBIFS_FLG_DOUBLE_HASH|UBIFS_FLG_ENCRYPTION)
> +
>  /**
>   * struct ubifs_ch - common header node.
>   * @magic: UBIFS node magic number (%UBIFS_NODE_MAGIC)
> -- 
> 2.7.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


From tytso at mit.edu  Fri Oct 21 10:47:59 2016
From: tytso at mit.edu (Theodore Ts'o)
Date: Fri, 21 Oct 2016 13:47:59 -0400
Subject: [PATCH 26/26] ubifs: Raise write version to 5
In-Reply-To: <20161021173154.GB17121@google.com>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
 <1477054121-10198-27-git-send-email-richard@nod.at>
 <20161021173154.GB17121@google.com>
Message-ID: <20161021174758.wz7xrulokicuhlht@thunk.org>

On Fri, Oct 21, 2016 at 10:31:54AM -0700, Michael Halcrow wrote:
> > diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h
> > index bdc7935a5e41..e8c23c9d4f4a 100644
> > --- a/fs/ubifs/ubifs-media.h
> > +++ b/fs/ubifs/ubifs-media.h
> > @@ -46,7 +46,7 @@
> >   * UBIFS went into mainline kernel with format version 4. The older formats
> >   * were development formats.
> >   */
> > -#define UBIFS_FORMAT_VERSION 4
> > +#define UBIFS_FORMAT_VERSION 5
> 
> Alex Cope is working on a fix for file name encryption in ext4 so that
> common plaintext prefixes don't result in common ciphertext prefixes.
> Older kernels will not be able to read the new file names.

To be clear, this will be done in the context of a new encryption
mode.  In terms of how Ubifs will handle things, that's going to
depend on whether ubifs uses a single major version number or whether
they have a feature bitmask like other filesystems, including ext4.

This is better because if the user doesn't use a particular feature,
especially a feature like encryption which is optional, we don't want
the file system to reject the mount unnecessarily.  In the case of
encryption, where there may be new encryption algorithms used, or
maybe even hardware-specific encryption modes if you are using in-line
encryption where the encryption is done in hardware, the question is
whether you want to refuse the mount if you know it won't work, or
just throw an error when there is an attempt to access a directory or
file which is encrypted using an encryption algorithm which a
particular kernel version doesn't support.

We did leave some room in the ext4 superblock for an encryption format
version number, as ewll as an array of which encryption algorithsm are
in use in the superblock, but we haven't really decided which strategy
we want to use.

My current thinking is that there ought to be a warning at mount time
if there are some directories which the kernel being used won't be
able to access, but we should just fail the mount entirely, since
there might be a lot of unencrypted files that the user might want to access.

Cheers,

							- Ted


From mhalcrow at google.com  Fri Oct 21 10:52:02 2016
From: mhalcrow at google.com (Michael Halcrow)
Date: Fri, 21 Oct 2016 10:52:02 -0700
Subject: [PATCH 15/26] ubifs: Implement encrypt/decrypt for all IO
In-Reply-To: <78f09113-fcc3-c2d2-9849-ba980cd9c0b4@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
 <1477054121-10198-16-git-send-email-richard@nod.at>
 <20161021171439.GA17121@google.com>
 <78f09113-fcc3-c2d2-9849-ba980cd9c0b4@nod.at>
Message-ID: <20161021175202.GA20642@google.com>

On Fri, Oct 21, 2016 at 07:21:04PM +0200, Richard Weinberger wrote:
> On 21.10.2016 19:14, Michael Halcrow wrote:
> > Compress-before-encrypt is a hazard.
> > 
> > http://www.iacr.org/cryptodb/archive/2002/FSE/3091/3091.pdf
> 
> I'm fully aware of that. But as usual it depends on the use case.
> Compression is optional in UBIFS, paranoid users can disable it
> when encryption is enabled.

It's not the paranoid users I'm concerned about.  It's those building
systems with complexity and nuance on top of UBIFS who aren't paranoid
enough.

I suggest disabling compression by default when encryption is enabled,
unless the user explicitly enables both.

> 
> Thanks,
> //richard


From boris.brezillon at free-electrons.com  Fri Oct 21 10:55:06 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Fri, 21 Oct 2016 19:55:06 +0200
Subject: [PATCH 1/8] mtd: nand: sunxi: fix support for 512bytes ECC chunks
In-Reply-To: <f1cb6efb6817c11b235f073639a137bec6ac17e5.1476951078.git-series.maxime.ripard@free-electrons.com>
References: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
 <f1cb6efb6817c11b235f073639a137bec6ac17e5.1476951078.git-series.maxime.ripard@free-electrons.com>
Message-ID: <20161021195506.10d32e81@bbrezillon>

On Thu, 20 Oct 2016 10:12:42 +0200
Maxime Ripard <maxime.ripard at free-electrons.com> wrote:

> From: Boris Brezillon <boris.brezillon at free-electrons.com>
> 
> The driver is incorrectly assuming that the ECC block size is always 1k
> which is not always true.
> 
> Also take the other cases into account.
> 
> Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
> Signed-off-by: Maxime Ripard <maxime.ripard at free-electrons.com>

Applied.

> ---
>  drivers/mtd/nand/sunxi_nand.c | 4 ++++
>  1 file changed, 4 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
> index 8b8470c4e6d0..e40482a65de6 100644
> --- a/drivers/mtd/nand/sunxi_nand.c
> +++ b/drivers/mtd/nand/sunxi_nand.c
> @@ -145,6 +145,7 @@
>  #define NFC_ECC_PIPELINE	BIT(3)
>  #define NFC_ECC_EXCEPTION	BIT(4)
>  #define NFC_ECC_BLOCK_SIZE_MSK	BIT(5)
> +#define NFC_ECC_BLOCK_512	BIT(5)
>  #define NFC_RANDOM_EN		BIT(9)
>  #define NFC_RANDOM_DIRECTION	BIT(10)
>  #define NFC_ECC_MODE_MSK	GENMASK(15, 12)
> @@ -817,6 +818,9 @@ static void sunxi_nfc_hw_ecc_enable(struct mtd_info *mtd)
>  	ecc_ctl |= NFC_ECC_EN | NFC_ECC_MODE(data->mode) | NFC_ECC_EXCEPTION |
>  		   NFC_ECC_PIPELINE;
>  
> +	if (nand->ecc.size == 512)
> +		ecc_ctl |= NFC_ECC_BLOCK_512;
> +
>  	writel(ecc_ctl, nfc->regs + NFC_REG_ECC_CTL);
>  }
>  



From boris.brezillon at free-electrons.com  Fri Oct 21 10:55:18 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Fri, 21 Oct 2016 19:55:18 +0200
Subject: [PATCH 2/8] mtd: nand: add support for the TC58NVG2S0H chip
In-Reply-To: <62d5d978da8c6bc6b47c340c86e9a5fe5f6971ef.1476951078.git-series.maxime.ripard@free-electrons.com>
References: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
 <62d5d978da8c6bc6b47c340c86e9a5fe5f6971ef.1476951078.git-series.maxime.ripard@free-electrons.com>
Message-ID: <20161021195518.020a3c19@bbrezillon>

On Thu, 20 Oct 2016 10:12:43 +0200
Maxime Ripard <maxime.ripard at free-electrons.com> wrote:

> From: Boris Brezillon <boris.brezillon at free-electrons.com>
> 
> Add the description of the Toshiba TC58NVG2S0H SLC nand to the nand_ids
> table so we can use the NAND ECC infos and the ONFI timings.
> 
> Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
> Signed-off-by: Maxime Ripard <maxime.ripard at free-electrons.com>

Applied.

> ---
>  drivers/mtd/nand/nand_ids.c | 3 +++
>  1 file changed, 3 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
> index 2af9869a115e..b3a332f37e14 100644
> --- a/drivers/mtd/nand/nand_ids.c
> +++ b/drivers/mtd/nand/nand_ids.c
> @@ -36,6 +36,9 @@ struct nand_flash_dev nand_flash_ids[] = {
>  	{"TC58NVG2S0F 4G 3.3V 8-bit",
>  		{ .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} },
>  		  SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) },
> +	{"TC58NVG2S0H 4G 3.3V 8-bit",
> +		{ .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x16, 0x08, 0x00} },
> +		  SZ_4K, SZ_512, SZ_256K, 0, 8, 256, NAND_ECC_INFO(8, SZ_512) },
>  	{"TC58NVG3S0F 8G 3.3V 8-bit",
>  		{ .id = {0x98, 0xd3, 0x90, 0x26, 0x76, 0x15, 0x02, 0x08} },
>  		  SZ_4K, SZ_1K, SZ_256K, 0, 8, 232, NAND_ECC_INFO(4, SZ_512) },



From marek.vasut at gmail.com  Fri Oct 21 10:52:49 2016
From: marek.vasut at gmail.com (Marek Vasut)
Date: Fri, 21 Oct 2016 19:52:49 +0200
Subject: [PATCH] mtd: spi-nor: Add possibility to disable chip erase
In-Reply-To: <1477054546-2548-1-git-send-email-marcin.krzeminski@nokia.com>
References: <1477054546-2548-1-git-send-email-marcin.krzeminski@nokia.com>
Message-ID: <3b23706b-bf46-8d3b-e9b0-01194eec5e11@gmail.com>

On 10/21/2016 02:55 PM, marcin.krzeminski at nokia.com wrote:
> From: Marcin Krzeminski <marcin.krzeminski at nokia.com>
> 
> n25q00 does not support chip erase command (0xC7),
> but spi-nor framework still send if if user want to erase
> whole flash. This patch adds option to disable chip erase
> command and enable in on n25q00.

That's true and it's a pretty nasty issue.
Can you instead implement logic to send multiple die-erase commands ?
They do make erasing faster afterall.

> Signed-off-by: Marcin Krzeminski <marcin.krzeminski at nokia.com>
> ---
>  drivers/mtd/spi-nor/spi-nor.c | 9 ++++++---
>  include/linux/mtd/spi-nor.h   | 1 +
>  2 files changed, 7 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
> index d0fc165..8338be1 100644
> --- a/drivers/mtd/spi-nor/spi-nor.c
> +++ b/drivers/mtd/spi-nor/spi-nor.c
> @@ -75,6 +75,7 @@ struct flash_info {
>  					 * bit. Must be used with
>  					 * SPI_NOR_HAS_LOCK.
>  					 */
> +#define DISABLE_CE			BIT(10)	/*Some multi-die flash does not support CE */
>  };
>  
>  #define JEDEC_MFR(info)	((info)->id[0])
> @@ -368,7 +369,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
>  		return ret;
>  
>  	/* whole-chip erase? */
> -	if (len == mtd->size) {
> +	if (len == mtd->size && !(nor->flags & SNOR_F_DISABLE_CE)) {
>  		unsigned long timeout;
>  
>  		write_enable(nor);
> @@ -886,8 +887,8 @@ static const struct flash_info spi_nor_ids[] = {
>  	{ "n25q256a",    INFO(0x20ba19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_QUAD_READ) },
>  	{ "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) },
> +	{ "n25q00",      INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | DISABLE_CE) },
> +	{ "n25q00a",     INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | DISABLE_CE) },
>  
>  	/* PMC */
>  	{ "pm25lv512",   INFO(0,        0, 32 * 1024,    2, SECT_4K_PMC) },
> @@ -1395,6 +1396,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
>  		nor->flags |= SNOR_F_USE_FSR;
>  	if (info->flags & SPI_NOR_HAS_TB)
>  		nor->flags |= SNOR_F_HAS_SR_TB;
> +	if (info->flags & DISABLE_CE)
> +		nor->flags |= SNOR_F_DISABLE_CE;
>  
>  #ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
>  	/* prefer "small sector" erase if possible */
> diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
> index c425c7b..2d0b967 100644
> --- a/include/linux/mtd/spi-nor.h
> +++ b/include/linux/mtd/spi-nor.h
> @@ -119,6 +119,7 @@ enum spi_nor_ops {
>  enum spi_nor_option_flags {
>  	SNOR_F_USE_FSR		= BIT(0),
>  	SNOR_F_HAS_SR_TB	= BIT(1),
> +	SNOR_F_DISABLE_CE	= BIT(2),
>  };
>  
>  /**
> 


-- 
Best regards,
Marek Vasut


From jagan at openedev.com  Fri Oct 21 10:58:00 2016
From: jagan at openedev.com (Jagan Teki)
Date: Fri, 21 Oct 2016 23:28:00 +0530
Subject: [PATCH v2 1/1] MAINTAINERS: add a maintainer for the SPI NOR
 subsystem
In-Reply-To: <d92f8ef8-be78-0386-fa84-117c3cae6459@denx.de>
References: <aad52b708dcf6754edab87d2e0afe4f0ee6831f9.1476891131.git.cyrille.pitchen@atmel.com>
 <d92f8ef8-be78-0386-fa84-117c3cae6459@denx.de>
Message-ID: <CAD6G_RRm0ttasw8DAQvE2fOpXd61tTsbNwyy_vJ_quAO0y3swA@mail.gmail.com>

On Thu, Oct 20, 2016 at 7:12 PM, Marek Vasut <marex at denx.de> wrote:
> On 10/19/2016 05:34 PM, Cyrille Pitchen wrote:
>> I would like to volunteer as a maintainer for the SPI NOR part of the MTD
>> subsystem.
>>
>> Over the last months, a significant number of SPI NOR related patches have
>> been submitted, some of them have been reviewed, but very few have finally
>> been merged. Hence, the number of pending SPI NOR related patches continues
>> to increase over the time.
>>
>> Through my work on SPI NOR memories from many manufacturers over the last
>> two years, I've gained a solid understanding of this technology.
>> I've already helped by reviewing patches from other contributors on the
>> mailing list, and would like to help getting those patches integrated by
>> volunteering as a maintainer for this specific area.
>>
>> Boris Brezillon has already stepped up as a maintainer for the NAND
>> sub-subsystem in MTD, and the SPI NOR sub-subsystem could be handled in
>> the same way: I would be reviewing patches touching this area, collecting
>> them and sending pull requests to Brian Norris.
>>
>> Also both Marek Vasut and Richard Weinberger have volunteered as well as
>> maintainers for the SPI NOR subsystem.
>>
>> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
>> Acked-by: Boris Brezillon <boris.brezillon at free-electrons.com>
>
> Acked-by: Marek Vasut <marek.vasut at gmail.com>

Acked-by: Jagan Teki <jteki at openedev.com>

>
> btw I think I'll need higher privileges in patchwork to fiddle with patches.
>
>> ---
>> ChangeLog:
>>
>> v1 -> v2:
>> - add Marek and Richard as maintainers.
>> - add Acked-by from Boris Brezillon.
>>
>>
>>  MAINTAINERS | 12 ++++++++++++
>>  1 file changed, 12 insertions(+)
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 757f9c4b388d..7e63b2015072 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -11390,6 +11390,18 @@ W:   http://www.st.com/spear
>>  S:   Maintained
>>  F:   drivers/clk/spear/
>>
>> +SPI NOR SUBSYSTEM
>> +M:   Cyrille Pitchen <cyrille.pitchen at atmel.com>
>> +M:   Marek Vasut <marek.vasut at gmail.com>
>> +M:   Richard Weinberger <richard at nod.at>

May be I was little late, but if there is any space for one more or so
I would also like to co-maintain? Currently I am maintaining
SPI/SPI-FLASH for u-boot and working for generic MTD (with u-boot
driver model) + SPI-NOR addition on u-boot which eventually similar
conceptual theory what Linux follows.

thanks!
-- 
Jagan Teki
Free Software Engineer | www.openedev.com
U-Boot, Linux | Upstream Maintainer
Hyderabad, India.


From ebiggers at google.com  Fri Oct 21 11:19:31 2016
From: ebiggers at google.com (Eric Biggers)
Date: Fri, 21 Oct 2016 11:19:31 -0700
Subject: [PATCH 26/26] ubifs: Raise write version to 5
In-Reply-To: <20161021174758.wz7xrulokicuhlht@thunk.org>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
 <1477054121-10198-27-git-send-email-richard@nod.at>
 <20161021173154.GB17121@google.com>
 <20161021174758.wz7xrulokicuhlht@thunk.org>
Message-ID: <20161021181931.GA90712@google.com>

On Fri, Oct 21, 2016 at 01:47:59PM -0400, Theodore Ts'o wrote:
> On Fri, Oct 21, 2016 at 10:31:54AM -0700, Michael Halcrow wrote:
> > > diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h
> > > index bdc7935a5e41..e8c23c9d4f4a 100644
> > > --- a/fs/ubifs/ubifs-media.h
> > > +++ b/fs/ubifs/ubifs-media.h
> > > @@ -46,7 +46,7 @@
> > >   * UBIFS went into mainline kernel with format version 4. The older formats
> > >   * were development formats.
> > >   */
> > > -#define UBIFS_FORMAT_VERSION 4
> > > +#define UBIFS_FORMAT_VERSION 5
> > 
> > Alex Cope is working on a fix for file name encryption in ext4 so that
> > common plaintext prefixes don't result in common ciphertext prefixes.
> > Older kernels will not be able to read the new file names.
> 
> To be clear, this will be done in the context of a new encryption
> mode.  In terms of how Ubifs will handle things, that's going to
> depend on whether ubifs uses a single major version number or whether
> they have a feature bitmask like other filesystems, including ext4.
> 

I don't think it's reasonable to require require changes to filesystems whenever
someone introduces a new encryption mode --- contents, filenames, or both.
Filesystems need to be able to handle unsupported encryption modes in some way
that makes sense.  Currently, when it sees an unsupported encryption mode
fscrypto will behave as if the encryption key is not available and will also
print a one-time warning to the kernel log.  This happens when a file is
accessed, not when the filesystem is mounted.  As far as I can tell, ext4, f2fs,
and ubifs would all behave this way because this code is shared.  I think this
is probably the most realistic behavior.

Eric


From richard at nod.at  Fri Oct 21 11:21:16 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 21 Oct 2016 20:21:16 +0200
Subject: [PATCH 15/26] ubifs: Implement encrypt/decrypt for all IO
In-Reply-To: <20161021175202.GA20642@google.com>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
 <1477054121-10198-16-git-send-email-richard@nod.at>
 <20161021171439.GA17121@google.com>
 <78f09113-fcc3-c2d2-9849-ba980cd9c0b4@nod.at>
 <20161021175202.GA20642@google.com>
Message-ID: <ccfd1997-8010-3e0f-36ab-e5e360e50564@nod.at>

On 21.10.2016 19:52, Michael Halcrow wrote:
> On Fri, Oct 21, 2016 at 07:21:04PM +0200, Richard Weinberger wrote:
>> On 21.10.2016 19:14, Michael Halcrow wrote:
>>> Compress-before-encrypt is a hazard.
>>>
>>> http://www.iacr.org/cryptodb/archive/2002/FSE/3091/3091.pdf
>>
>> I'm fully aware of that. But as usual it depends on the use case.
>> Compression is optional in UBIFS, paranoid users can disable it
>> when encryption is enabled.
> 
> It's not the paranoid users I'm concerned about.  It's those building
> systems with complexity and nuance on top of UBIFS who aren't paranoid
> enough.
> 
> I suggest disabling compression by default when encryption is enabled,
> unless the user explicitly enables both.

That's definitely an option, yes.

Thanks,
//richard


From ebiggers at google.com  Fri Oct 21 11:25:59 2016
From: ebiggers at google.com (Eric Biggers)
Date: Fri, 21 Oct 2016 11:25:59 -0700
Subject: [PATCH 15/26] ubifs: Implement encrypt/decrypt for all IO
In-Reply-To: <1477054121-10198-16-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
 <1477054121-10198-16-git-send-email-richard@nod.at>
Message-ID: <20161021182559.GB90712@google.com>

On Fri, Oct 21, 2016 at 02:48:30PM +0200, Richard Weinberger wrote:
> +
> +	if (ubifs_crypt_is_encrypted(inode)) {
> +		int clen = le16_to_cpu(dn->compr_size);
> +
> +		if (clen <= 0 || clen > UBIFS_BLOCK_SIZE || clen > dlen)
> +			goto dump;
> +
> +		ubifs_assert(dlen <= UBIFS_BLOCK_SIZE);
> +		err = fscrypt_decrypt_buffer(inode, &dn->data, &dn->data, dlen, block, GFP_NOFS);
> +		if (err) {
> +			ubifs_err(c, "fscrypt_decrypt_buffer failed: %i", err);
> +			return err;
> +		}
> +
> +		ubifs_assert(clen <= dlen);
> +		dlen = clen;
> +	}
> +

There are several code blocks like this, calling either fscrypt_decrypt_buffer()
or fscrypt_encrypt_buffer(), which seem to be mostly duplicated.  Is it possible
to refactor them into helper functions?  There are also some lines well over 80
characters.

Eric


From ebiggers at google.com  Fri Oct 21 11:30:12 2016
From: ebiggers at google.com (Eric Biggers)
Date: Fri, 21 Oct 2016 11:30:12 -0700
Subject: [PATCH 25/26] ubifs: Implement UBIFS_FLG_ENCRYPTION
In-Reply-To: <1477054121-10198-26-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
 <1477054121-10198-26-git-send-email-richard@nod.at>
Message-ID: <20161021183012.GC90712@google.com>

On Fri, Oct 21, 2016 at 02:48:40PM +0200, Richard Weinberger wrote:
> @@ -190,6 +191,10 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
>  				   sizeof(policy)))
>  			return -EFAULT;
>  
> +		err = ubifs_enable_encryption(c);
> +		if (err)
> +			return err;
> +
>  		err = fscrypt_process_policy(file, &policy);

Is ubifs_enable_encryption() being done with proper locking and authorization?
As-is, anyone can call this at any time if they can open some file on UBIFS.

FYI, the approach being taken for ext4 is that the encryption feature flag has
to be explicitly turned on before FS_IOC_SET_ENCRYPTION_POLICY will work.

Eric


From krzk at kernel.org  Fri Oct 21 11:27:10 2016
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 21 Oct 2016 21:27:10 +0300
Subject: [PATCH v3 1/3] mtd: s3c2410: make ecc mode configurable via
 platform data
In-Reply-To: <1476999766-32526-2-git-send-email-sergio.prado@e-labworks.com>
References: <1476999766-32526-1-git-send-email-sergio.prado@e-labworks.com>
 <1476999766-32526-2-git-send-email-sergio.prado@e-labworks.com>
Message-ID: <20161021182710.GA17279@kozik-lap>

On Thu, Oct 20, 2016 at 07:42:44PM -0200, Sergio Prado wrote:
> Removing CONFIG_MTD_NAND_S3C2410_HWECC option and adding a ecc_mode
> field in the drivers's platform data structure so it can be selectable
> via platform data.
> 
> Also setting this field to NAND_ECC_SOFT in all boards using this
> driver since none of them had CONFIG_MTD_NAND_S3C2410_HWECC enabled.
> 
> Signed-off-by: Sergio Prado <sergio.prado at e-labworks.com>
> ---
>  arch/arm/mach-s3c24xx/common-smdk.c            |   1 +
>  arch/arm/mach-s3c24xx/mach-anubis.c            |   1 +
>  arch/arm/mach-s3c24xx/mach-at2440evb.c         |   1 +
>  arch/arm/mach-s3c24xx/mach-bast.c              |   1 +
>  arch/arm/mach-s3c24xx/mach-gta02.c             |   1 +
>  arch/arm/mach-s3c24xx/mach-jive.c              |   1 +
>  arch/arm/mach-s3c24xx/mach-mini2440.c          |   1 +
>  arch/arm/mach-s3c24xx/mach-osiris.c            |   1 +
>  arch/arm/mach-s3c24xx/mach-qt2410.c            |   1 +
>  arch/arm/mach-s3c24xx/mach-rx1950.c            |   1 +
>  arch/arm/mach-s3c24xx/mach-rx3715.c            |   1 +
>  arch/arm/mach-s3c24xx/mach-vstms.c             |   1 +
>  arch/arm/mach-s3c64xx/mach-hmt.c               |   1 +
>  arch/arm/mach-s3c64xx/mach-mini6410.c          |   1 +
>  arch/arm/mach-s3c64xx/mach-real6410.c          |   1 +
>  drivers/mtd/nand/Kconfig                       |   9 --
>  drivers/mtd/nand/s3c2410.c                     | 119 +++++++++++++------------
>  include/linux/platform_data/mtd-nand-s3c2410.h |   6 +-
>  18 files changed, 79 insertions(+), 70 deletions(-)
>

I acked this twice (v1 and v2)... and still you are ignoring them. I am
sorry, I am not gonna to ack this third time!

For v2 I acked also other patches but it it is not there as well...

BR,
Krzysztof


From ebiggers at google.com  Fri Oct 21 11:42:31 2016
From: ebiggers at google.com (Eric Biggers)
Date: Fri, 21 Oct 2016 11:42:31 -0700
Subject: [PATCH 20/26] ubifs: Add support for encrypted symlinks
In-Reply-To: <1477054121-10198-21-git-send-email-richard@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
 <1477054121-10198-21-git-send-email-richard@nod.at>
Message-ID: <20161021184231.GD90712@google.com>

On Fri, Oct 21, 2016 at 02:48:35PM +0200, Richard Weinberger wrote:
> +
> +	if (!dentry)
> +		return ERR_PTR(-ECHILD);
> +
> +	if (ubifs_crypt_is_encrypted(inode)) {
> +		err = fscrypt_get_encryption_info(inode);
> +		if (err)
> +			return ERR_PTR(err);
> +	} else
> +		return ui->data;
> +

This will make path lookups drop out of RCU mode when an unencrypted symlink is
followed.  This can be avoided by checking for unencrypted symlinks first:

	if (!ubifs_crypt_is_encrypted(inode))
		return ui->data;

	if (!dentry)
		return ERR_PTR(-ECHILD);

	err = fscrypt_get_encryption_info(inode);
	if (err)
		return ERR_PTR(err);

> +
> +	pstr.name[err] = '\0';
> +

In 4.9, fscrypt_fname_{disk_to_usr,usr_to_disk} return 0 instead of the output
length, so this will need to be changed to 'pstr.name[pstr.len] = '\0''.


From marek.vasut at gmail.com  Fri Oct 21 11:51:51 2016
From: marek.vasut at gmail.com (Marek Vasut)
Date: Fri, 21 Oct 2016 20:51:51 +0200
Subject: [PATCH v3 1/3] mtd: s3c2410: make ecc mode configurable via
 platform data
In-Reply-To: <20161021182710.GA17279@kozik-lap>
References: <1476999766-32526-1-git-send-email-sergio.prado@e-labworks.com>
 <1476999766-32526-2-git-send-email-sergio.prado@e-labworks.com>
 <20161021182710.GA17279@kozik-lap>
Message-ID: <5a626833-d4bf-a991-65ea-2849f2250dce@gmail.com>

On 10/21/2016 08:27 PM, Krzysztof Kozlowski wrote:
> On Thu, Oct 20, 2016 at 07:42:44PM -0200, Sergio Prado wrote:
>> Removing CONFIG_MTD_NAND_S3C2410_HWECC option and adding a ecc_mode
>> field in the drivers's platform data structure so it can be selectable
>> via platform data.
>>
>> Also setting this field to NAND_ECC_SOFT in all boards using this
>> driver since none of them had CONFIG_MTD_NAND_S3C2410_HWECC enabled.
>>
>> Signed-off-by: Sergio Prado <sergio.prado at e-labworks.com>
>> ---
>>  arch/arm/mach-s3c24xx/common-smdk.c            |   1 +
>>  arch/arm/mach-s3c24xx/mach-anubis.c            |   1 +
>>  arch/arm/mach-s3c24xx/mach-at2440evb.c         |   1 +
>>  arch/arm/mach-s3c24xx/mach-bast.c              |   1 +
>>  arch/arm/mach-s3c24xx/mach-gta02.c             |   1 +
>>  arch/arm/mach-s3c24xx/mach-jive.c              |   1 +
>>  arch/arm/mach-s3c24xx/mach-mini2440.c          |   1 +
>>  arch/arm/mach-s3c24xx/mach-osiris.c            |   1 +
>>  arch/arm/mach-s3c24xx/mach-qt2410.c            |   1 +
>>  arch/arm/mach-s3c24xx/mach-rx1950.c            |   1 +
>>  arch/arm/mach-s3c24xx/mach-rx3715.c            |   1 +
>>  arch/arm/mach-s3c24xx/mach-vstms.c             |   1 +
>>  arch/arm/mach-s3c64xx/mach-hmt.c               |   1 +
>>  arch/arm/mach-s3c64xx/mach-mini6410.c          |   1 +
>>  arch/arm/mach-s3c64xx/mach-real6410.c          |   1 +
>>  drivers/mtd/nand/Kconfig                       |   9 --
>>  drivers/mtd/nand/s3c2410.c                     | 119 +++++++++++++------------
>>  include/linux/platform_data/mtd-nand-s3c2410.h |   6 +-
>>  18 files changed, 79 insertions(+), 70 deletions(-)
>>
> 
> I acked this twice (v1 and v2)... and still you are ignoring them. I am
> sorry, I am not gonna to ack this third time!

Hi, um, I am kinda new to this mess, what's going on ? You ACKed
previous patches, next revision was submitted, so you need to ACK
the next revision too (due to the changes).

> For v2 I acked also other patches but it it is not there as well...
> 
> BR,
> Krzysztof


-- 
Best regards,
Marek Vasut


From sergio.prado at e-labworks.com  Fri Oct 21 12:05:10 2016
From: sergio.prado at e-labworks.com (Sergio Prado)
Date: Fri, 21 Oct 2016 17:05:10 -0200
Subject: [PATCH v3 1/3] mtd: s3c2410: make ecc mode configurable via
 platform data
In-Reply-To: <20161021182710.GA17279@kozik-lap>
References: <1476999766-32526-1-git-send-email-sergio.prado@e-labworks.com>
 <1476999766-32526-2-git-send-email-sergio.prado@e-labworks.com>
 <20161021182710.GA17279@kozik-lap>
Message-ID: <20161021190510.GA10729@sprado-desktop>

On Fri, Oct 21, 2016 at 09:27:10PM +0300, Krzysztof Kozlowski wrote:
> 
> I acked this twice (v1 and v2)... and still you are ignoring them. I am
> sorry, I am not gonna to ack this third time!
> 
> For v2 I acked also other patches but it it is not there as well...
> 
> BR,
> Krzysztof

I'm really sorry Krzysztof. This is my first patch series and I didn't
know I should add the acked-by tag to the patches (I thought it would be
done by the maintainer when the patches are accepted/applied).

I'll make sure to do it right next time.

Thanks for taking your time to reviewing and acking my patches.

Best regards,

Sergio Prado

-- 
Sergio Prado
Embedded Labworks
Office: +55 11 2628-3461
Mobile: +55 11 97123-3420


From krzk at kernel.org  Fri Oct 21 13:06:25 2016
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 21 Oct 2016 23:06:25 +0300
Subject: [PATCH v3 1/3] mtd: s3c2410: make ecc mode configurable via
 platform data
In-Reply-To: <5a626833-d4bf-a991-65ea-2849f2250dce@gmail.com>
References: <1476999766-32526-1-git-send-email-sergio.prado@e-labworks.com>
 <1476999766-32526-2-git-send-email-sergio.prado@e-labworks.com>
 <20161021182710.GA17279@kozik-lap>
 <5a626833-d4bf-a991-65ea-2849f2250dce@gmail.com>
Message-ID: <20161021200625.GA20847@kozik-lap>

On Fri, Oct 21, 2016 at 08:51:51PM +0200, Marek Vasut wrote:
> On 10/21/2016 08:27 PM, Krzysztof Kozlowski wrote:
> > On Thu, Oct 20, 2016 at 07:42:44PM -0200, Sergio Prado wrote:
> >> Removing CONFIG_MTD_NAND_S3C2410_HWECC option and adding a ecc_mode
> >> field in the drivers's platform data structure so it can be selectable
> >> via platform data.
> >>
> >> Also setting this field to NAND_ECC_SOFT in all boards using this
> >> driver since none of them had CONFIG_MTD_NAND_S3C2410_HWECC enabled.
> >>
> >> Signed-off-by: Sergio Prado <sergio.prado at e-labworks.com>
> >> ---
> >>  arch/arm/mach-s3c24xx/common-smdk.c            |   1 +
> >>  arch/arm/mach-s3c24xx/mach-anubis.c            |   1 +
> >>  arch/arm/mach-s3c24xx/mach-at2440evb.c         |   1 +
> >>  arch/arm/mach-s3c24xx/mach-bast.c              |   1 +
> >>  arch/arm/mach-s3c24xx/mach-gta02.c             |   1 +
> >>  arch/arm/mach-s3c24xx/mach-jive.c              |   1 +
> >>  arch/arm/mach-s3c24xx/mach-mini2440.c          |   1 +
> >>  arch/arm/mach-s3c24xx/mach-osiris.c            |   1 +
> >>  arch/arm/mach-s3c24xx/mach-qt2410.c            |   1 +
> >>  arch/arm/mach-s3c24xx/mach-rx1950.c            |   1 +
> >>  arch/arm/mach-s3c24xx/mach-rx3715.c            |   1 +
> >>  arch/arm/mach-s3c24xx/mach-vstms.c             |   1 +
> >>  arch/arm/mach-s3c64xx/mach-hmt.c               |   1 +
> >>  arch/arm/mach-s3c64xx/mach-mini6410.c          |   1 +
> >>  arch/arm/mach-s3c64xx/mach-real6410.c          |   1 +
> >>  drivers/mtd/nand/Kconfig                       |   9 --
> >>  drivers/mtd/nand/s3c2410.c                     | 119 +++++++++++++------------
> >>  include/linux/platform_data/mtd-nand-s3c2410.h |   6 +-
> >>  18 files changed, 79 insertions(+), 70 deletions(-)
> >>
> > 
> > I acked this twice (v1 and v2)... and still you are ignoring them. I am
> > sorry, I am not gonna to ack this third time!
> 
> Hi, um, I am kinda new to this mess, what's going on ? You ACKed
> previous patches, next revision was submitted, so you need to ACK
> the next revision too (due to the changes).
>

Some of the patches (1/3 and 2/3) were not changed. The resubmission of
a patch should contain the ack. Otherwise one would have to ack
indefinitely...

The changes in 2/3 were quite irrelevant to my ack, so the ack could
stay.

BR,
Krzysztof


From jgunthorpe at obsidianresearch.com  Fri Oct 21 13:33:22 2016
From: jgunthorpe at obsidianresearch.com (Jason Gunthorpe)
Date: Fri, 21 Oct 2016 14:33:22 -0600
Subject: [v7, 1/3] nand: pl353: Add basic driver for arm pl353 smc nand
 interface
In-Reply-To: <1433786918-21500-2-git-send-email-punnaia@xilinx.com>
References: <1433786918-21500-2-git-send-email-punnaia@xilinx.com>
Message-ID: <20161021203322.GA28655@obsidianresearch.com>

On Mon, Jun 08, 2015 at 11:38:36PM +0530, Punnaiah Choudary Kalluri wrote:
> Add driver for arm pl353 static memory controller nand interface with
> HW ECC support. This controller is used in xilinx zynq soc for interfacing
> the nand flash memory.
> 
> Signed-off-by: Punnaiah Choudary Kalluri <punnaia at xilinx.com>
> Changes in v7:
>  - Currently not implemented the memclk rate adjustments. I will
>    look into this later and once the basic driver is accepted.
>  - Fixed GPL licence ident
> Changes in v6:
>  - Fixed the checkpatch.pl reported warnings
>  - Using the address cycles information from the onfi param page
>    earlier it is hardcoded to 5 in driver
> Changes in v5:
>  - Configure the nand timing parameters as per the onfi spec
> Changes in v4:
>  - Updated the driver to sync with pl353_smc driver APIs
> Changes in v3:
>  - implemented the proper error codes
>  - further breakdown this patch to multiple sets
>  - added the controller and driver details to Documentation section
>  - updated the licenece to GPLv2
>  - reorganized the pl353_nand_ecc_init function
> Changes in v2:
>  - use "depends on" rather than "select" option in kconfig
>  - remove unused variable parts
>  - remove dummy helper and use writel_relaxed directly

What is the status of getting this driver merged? I am interested in
this driver and can provide some help if there are still TODO items.

At the very least I will test it, is there something newer than v7 out
there?

Regards,
Jason


From boris.brezillon at free-electrons.com  Fri Oct 21 14:29:54 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Fri, 21 Oct 2016 23:29:54 +0200
Subject: [PATCH v2 1/1] MAINTAINERS: add a maintainer for the SPI NOR
 subsystem
In-Reply-To: <aad52b708dcf6754edab87d2e0afe4f0ee6831f9.1476891131.git.cyrille.pitchen@atmel.com>
References: <aad52b708dcf6754edab87d2e0afe4f0ee6831f9.1476891131.git.cyrille.pitchen@atmel.com>
Message-ID: <20161021232954.4900709e@bbrezillon>

On Wed, 19 Oct 2016 17:34:49 +0200
Cyrille Pitchen <cyrille.pitchen at atmel.com> wrote:

> I would like to volunteer as a maintainer for the SPI NOR part of the MTD
> subsystem.
> 
> Over the last months, a significant number of SPI NOR related patches have
> been submitted, some of them have been reviewed, but very few have finally
> been merged. Hence, the number of pending SPI NOR related patches continues
> to increase over the time.
> 
> Through my work on SPI NOR memories from many manufacturers over the last
> two years, I've gained a solid understanding of this technology.
> I've already helped by reviewing patches from other contributors on the
> mailing list, and would like to help getting those patches integrated by
> volunteering as a maintainer for this specific area.
> 
> Boris Brezillon has already stepped up as a maintainer for the NAND
> sub-subsystem in MTD, and the SPI NOR sub-subsystem could be handled in
> the same way: I would be reviewing patches touching this area, collecting
> them and sending pull requests to Brian Norris.
> 
> Also both Marek Vasut and Richard Weinberger have volunteered as well as
> maintainers for the SPI NOR subsystem.
> 
> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
> Acked-by: Boris Brezillon <boris.brezillon at free-electrons.com>
> ---
> ChangeLog:
> 
> v1 -> v2:
> - add Marek and Richard as maintainers.
> - add Acked-by from Boris Brezillon.
> 
> 
>  MAINTAINERS | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 757f9c4b388d..7e63b2015072 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -11390,6 +11390,18 @@ W:	http://www.st.com/spear
>  S:	Maintained
>  F:	drivers/clk/spear/
>  
> +SPI NOR SUBSYSTEM
> +M:	Cyrille Pitchen <cyrille.pitchen at atmel.com>
> +M:	Marek Vasut <marek.vasut at gmail.com>
> +M:	Richard Weinberger <richard at nod.at>

My bad, I think I misunderstood Richard's answer: Richard does not want
to be a spi-nor maintainer, he was just acking Marek's proposal to be a
co-maintainer.

> +L:	linux-mtd at lists.infradead.org
> +W:	http://www.linux-mtd.infradead.org/
> +Q:	http://patchwork.ozlabs.org/project/linux-mtd/list/
> +T:	git git://github.com/spi-nor/linux.git
> +S:	Maintained
> +F:	drivers/mtd/spi-nor/
> +F:	include/linux/mtd/spi-nor.h
> +
>  SPI SUBSYSTEM
>  M:	Mark Brown <broonie at kernel.org>
>  L:	linux-spi at vger.kernel.org



From boris.brezillon at free-electrons.com  Fri Oct 21 14:46:11 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Fri, 21 Oct 2016 23:46:11 +0200
Subject: [v7, 1/3] nand: pl353: Add basic driver for arm pl353 smc nand
 interface
In-Reply-To: <20161021203322.GA28655@obsidianresearch.com>
References: <1433786918-21500-2-git-send-email-punnaia@xilinx.com>
 <20161021203322.GA28655@obsidianresearch.com>
Message-ID: <20161021234611.1f737144@bbrezillon>

On Fri, 21 Oct 2016 14:33:22 -0600
Jason Gunthorpe <jgunthorpe at obsidianresearch.com> wrote:

> On Mon, Jun 08, 2015 at 11:38:36PM +0530, Punnaiah Choudary Kalluri wrote:
> > Add driver for arm pl353 static memory controller nand interface with
> > HW ECC support. This controller is used in xilinx zynq soc for interfacing
> > the nand flash memory.
> > 
> > Signed-off-by: Punnaiah Choudary Kalluri <punnaia at xilinx.com>
> > Changes in v7:
> >  - Currently not implemented the memclk rate adjustments. I will
> >    look into this later and once the basic driver is accepted.
> >  - Fixed GPL licence ident
> > Changes in v6:
> >  - Fixed the checkpatch.pl reported warnings
> >  - Using the address cycles information from the onfi param page
> >    earlier it is hardcoded to 5 in driver
> > Changes in v5:
> >  - Configure the nand timing parameters as per the onfi spec
> > Changes in v4:
> >  - Updated the driver to sync with pl353_smc driver APIs
> > Changes in v3:
> >  - implemented the proper error codes
> >  - further breakdown this patch to multiple sets
> >  - added the controller and driver details to Documentation section
> >  - updated the licenece to GPLv2
> >  - reorganized the pl353_nand_ecc_init function
> > Changes in v2:
> >  - use "depends on" rather than "select" option in kconfig
> >  - remove unused variable parts
> >  - remove dummy helper and use writel_relaxed directly  
> 
> What is the status of getting this driver merged? I am interested in
> this driver and can provide some help if there are still TODO items.

I'll try to review it next week.

> 
> At the very least I will test it, is there something newer than v7 out
> there?
> 
> Regards,
> Jason
> 
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/



From tytso at mit.edu  Fri Oct 21 15:34:25 2016
From: tytso at mit.edu (Theodore Ts'o)
Date: Fri, 21 Oct 2016 18:34:25 -0400
Subject: [PATCH 26/26] ubifs: Raise write version to 5
In-Reply-To: <20161021181931.GA90712@google.com>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
 <1477054121-10198-27-git-send-email-richard@nod.at>
 <20161021173154.GB17121@google.com>
 <20161021174758.wz7xrulokicuhlht@thunk.org>
 <20161021181931.GA90712@google.com>
Message-ID: <20161021223425.sqtjey2xov7fqjh3@thunk.org>

On Fri, Oct 21, 2016 at 11:19:31AM -0700, Eric Biggers wrote:
> 
> I don't think it's reasonable to require require changes to filesystems whenever
> someone introduces a new encryption mode --- contents, filenames, or both.
> Filesystems need to be able to handle unsupported encryption modes in some way
> that makes sense.  Currently, when it sees an unsupported encryption mode
> fscrypto will behave as if the encryption key is not available and will also
> print a one-time warning to the kernel log.  This happens when a file is
> accessed, not when the filesystem is mounted.  As far as I can tell, ext4, f2fs,
> and ubifs would all behave this way because this code is shared.  I think this
> is probably the most realistic behavior.

I tend to agree, but file systems may choose some alternate approach
if they want to "fail fast" (e.g., at mount time).  I wouldn't want to
do that for ext4, but if ubifs (or some other file system) wants do
something more draconian, they can be afraid to do that.  Failing
that, some kind of one-time warning makes sense.

What I would like to do though is to is to have a callback so that
code in fs/crypto can call a file system specific notification
routine.  e.g., for ext4, we would probably want to be able to call
ext4_warning() and ext4_error() from fs/crypto, and other file systems
might want to have a different set of notification routines.

This way we can print a message like

kernel: EXT4-fs warning (device sdb1): fscrypto_xxx: foo bar baz

and if we later on have a way of sending file system specific warnings
or errors through some kind of IPC mechanism, such as netlink or some
future kdbus scheme, we can send the warning and error messages out
the same way we send other filesystem specific error messages.

	      	      	     	       	      - Ted

P.S.  BTW, we actually _do_ have something hacked together inside the
Google production kernel which pipes ext4_error() messages to a
netlink socket, so that monitoring systems don't have scrape dmesg or
/var/log/messages.

If anyone inside or outside google is interested in that
functionality, I can make the code available.  There's nothing
sensitive or Google specific in it; it's just that unfortunately,
getting that code cleaned up and upstreamed has just never made it
"above the fold" on the priority list, the engineer who originally
implemented it is no longer on the team --- and I never had the time
to cleanup work to get the code to upstream quality myself.


From richard.weinberger at gmail.com  Fri Oct 21 23:33:24 2016
From: richard.weinberger at gmail.com (Richard Weinberger)
Date: Sat, 22 Oct 2016 08:33:24 +0200
Subject: [PATCH v2 1/1] MAINTAINERS: add a maintainer for the SPI NOR
 subsystem
In-Reply-To: <20161021232954.4900709e@bbrezillon>
References: <aad52b708dcf6754edab87d2e0afe4f0ee6831f9.1476891131.git.cyrille.pitchen@atmel.com>
 <20161021232954.4900709e@bbrezillon>
Message-ID: <CAFLxGvypdHy+O8-i8Dshzj1+WAemxkpmu8EtrJKnXmf0HWjQwg@mail.gmail.com>

On Fri, Oct 21, 2016 at 11:29 PM, Boris Brezillon
<boris.brezillon at free-electrons.com> wrote:
> On Wed, 19 Oct 2016 17:34:49 +0200
> Cyrille Pitchen <cyrille.pitchen at atmel.com> wrote:
>
>> I would like to volunteer as a maintainer for the SPI NOR part of the MTD
>> subsystem.
>>
>> Over the last months, a significant number of SPI NOR related patches have
>> been submitted, some of them have been reviewed, but very few have finally
>> been merged. Hence, the number of pending SPI NOR related patches continues
>> to increase over the time.
>>
>> Through my work on SPI NOR memories from many manufacturers over the last
>> two years, I've gained a solid understanding of this technology.
>> I've already helped by reviewing patches from other contributors on the
>> mailing list, and would like to help getting those patches integrated by
>> volunteering as a maintainer for this specific area.
>>
>> Boris Brezillon has already stepped up as a maintainer for the NAND
>> sub-subsystem in MTD, and the SPI NOR sub-subsystem could be handled in
>> the same way: I would be reviewing patches touching this area, collecting
>> them and sending pull requests to Brian Norris.
>>
>> Also both Marek Vasut and Richard Weinberger have volunteered as well as
>> maintainers for the SPI NOR subsystem.
>>
>> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
>> Acked-by: Boris Brezillon <boris.brezillon at free-electrons.com>
>> ---
>> ChangeLog:
>>
>> v1 -> v2:
>> - add Marek and Richard as maintainers.
>> - add Acked-by from Boris Brezillon.
>>
>>
>>  MAINTAINERS | 12 ++++++++++++
>>  1 file changed, 12 insertions(+)
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 757f9c4b388d..7e63b2015072 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -11390,6 +11390,18 @@ W:   http://www.st.com/spear
>>  S:   Maintained
>>  F:   drivers/clk/spear/
>>
>> +SPI NOR SUBSYSTEM
>> +M:   Cyrille Pitchen <cyrille.pitchen at atmel.com>
>> +M:   Marek Vasut <marek.vasut at gmail.com>
>> +M:   Richard Weinberger <richard at nod.at>
>
> My bad, I think I misunderstood Richard's answer: Richard does not want
> to be a spi-nor maintainer, he was just acking Marek's proposal to be a
> co-maintainer.

Correct. :-)

-- 
Thanks,
//richard


From jagan at openedev.com  Sat Oct 22 04:00:35 2016
From: jagan at openedev.com (Jagan Teki)
Date: Sat, 22 Oct 2016 16:30:35 +0530
Subject: [PATCH v2 0/9] mtd: spi-nor: parse SFDP tables to setup (Q)SPI
 memories
In-Reply-To: <cover.1475668319.git.cyrille.pitchen@atmel.com>
References: <cover.1475668319.git.cyrille.pitchen@atmel.com>
Message-ID: <CAD6G_RR4Av8+szo9v2oucCFvwnow86gMVC-Ku_-Qfy18TVMGgA@mail.gmail.com>

On Wed, Oct 5, 2016 at 5:30 PM, Cyrille Pitchen
<cyrille.pitchen at atmel.com> wrote:
> Hi all,
>
> This series extends support of SPI protocols to new protocols such as
> SPI x-2-2 and SPI x-4-4. Also spi_nor_scan() tries now to select the right
> op codes, timing parameters (number of mode and dummy cycles) and erase
> sector size by parsing the Serial Flash Discoverable Parameter (SFDP)
> tables, when available, as defined in the JEDEC JESD216 specifications.
>
> When SFDP tables are not available, legacy settings are still used for
> backward compatibility (SPI and earlier QSPI memories).
>
> Support of SPI memories >128Mbits is also improved by using the 4byte
> address instruction set, when available. Using those dedicated op codes
> is stateless as opposed to enter the 4byte address mode, hence a better
> compatibility with some boot loaders which expect to use 3byte address
> op codes.

The memories which are > 128Mbits should have 4-bytes addressing
support based on my experience, do you think BAR is also required
atleast from spi-nor side?

thanks!
-- 
Jagan Teki
Free Software Engineer | www.openedev.com
U-Boot, Linux | Upstream Maintainer
Hyderabad, India.


From boris.brezillon at free-electrons.com  Sat Oct 22 05:29:07 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Sat, 22 Oct 2016 14:29:07 +0200
Subject: [PATCH v3 1/3] mtd: s3c2410: make ecc mode configurable via
 platform data
In-Reply-To: <20161021182710.GA17279@kozik-lap>
References: <1476999766-32526-1-git-send-email-sergio.prado@e-labworks.com>
 <1476999766-32526-2-git-send-email-sergio.prado@e-labworks.com>
 <20161021182710.GA17279@kozik-lap>
Message-ID: <20161022142907.08a3eedf@bbrezillon>

Hi Krzysztof,

On Fri, 21 Oct 2016 21:27:10 +0300
Krzysztof Kozlowski <krzk at kernel.org> wrote:

> On Thu, Oct 20, 2016 at 07:42:44PM -0200, Sergio Prado wrote:
> > Removing CONFIG_MTD_NAND_S3C2410_HWECC option and adding a ecc_mode
> > field in the drivers's platform data structure so it can be selectable
> > via platform data.
> > 
> > Also setting this field to NAND_ECC_SOFT in all boards using this
> > driver since none of them had CONFIG_MTD_NAND_S3C2410_HWECC enabled.
> > 
> > Signed-off-by: Sergio Prado <sergio.prado at e-labworks.com>
> > ---
> >  arch/arm/mach-s3c24xx/common-smdk.c            |   1 +
> >  arch/arm/mach-s3c24xx/mach-anubis.c            |   1 +
> >  arch/arm/mach-s3c24xx/mach-at2440evb.c         |   1 +
> >  arch/arm/mach-s3c24xx/mach-bast.c              |   1 +
> >  arch/arm/mach-s3c24xx/mach-gta02.c             |   1 +
> >  arch/arm/mach-s3c24xx/mach-jive.c              |   1 +
> >  arch/arm/mach-s3c24xx/mach-mini2440.c          |   1 +
> >  arch/arm/mach-s3c24xx/mach-osiris.c            |   1 +
> >  arch/arm/mach-s3c24xx/mach-qt2410.c            |   1 +
> >  arch/arm/mach-s3c24xx/mach-rx1950.c            |   1 +
> >  arch/arm/mach-s3c24xx/mach-rx3715.c            |   1 +
> >  arch/arm/mach-s3c24xx/mach-vstms.c             |   1 +
> >  arch/arm/mach-s3c64xx/mach-hmt.c               |   1 +
> >  arch/arm/mach-s3c64xx/mach-mini6410.c          |   1 +
> >  arch/arm/mach-s3c64xx/mach-real6410.c          |   1 +
> >  drivers/mtd/nand/Kconfig                       |   9 --
> >  drivers/mtd/nand/s3c2410.c                     | 119 +++++++++++++------------
> >  include/linux/platform_data/mtd-nand-s3c2410.h |   6 +-
> >  18 files changed, 79 insertions(+), 70 deletions(-)
> >  
> 
> I acked this twice (v1 and v2)... and still you are ignoring them. I am
> sorry, I am not gonna to ack this third time!
> 
> For v2 I acked also other patches but it it is not there as well...

I'll collect your acks (and Rob ones) when applying the patches. BTW,
how should I proceed with patch 1? Do you want an topic branch
containing this patch?

Regards,

Boris


From boris.brezillon at free-electrons.com  Sat Oct 22 05:36:29 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Sat, 22 Oct 2016 14:36:29 +0200
Subject: [PATCH v2] mtd: nand: Add OX820 NAND Support
In-Reply-To: <20161020084901.6486-1-narmstrong@baylibre.com>
References: <20161020084901.6486-1-narmstrong@baylibre.com>
Message-ID: <20161022143629.7ad30b38@bbrezillon>

On Thu, 20 Oct 2016 10:49:01 +0200
Neil Armstrong <narmstrong at baylibre.com> wrote:

> Add NAND driver to support the Oxford Semiconductor OX820 NAND Controller.
> This is a simple memory mapped NAND controller with single chip select and
> software ECC.
> 
> Acked-by: Rob Herring <robh at kernel.org>
> Signed-off-by: Neil Armstrong <narmstrong at baylibre.com>

Applied.

Thanks,

Boris

> ---
>  .../devicetree/bindings/mtd/oxnas-nand.txt         |  41 +++++
>  drivers/mtd/nand/Kconfig                           |   5 +
>  drivers/mtd/nand/Makefile                          |   1 +
>  drivers/mtd/nand/oxnas_nand.c                      | 196 +++++++++++++++++++++
>  4 files changed, 243 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mtd/oxnas-nand.txt
>  create mode 100644 drivers/mtd/nand/oxnas_nand.c
> 
> Changes since v1 http://lkml.kernel.org/r/20161019145523.6763-1-narmstrong at baylibre.com :
>  - Simplify cmd_ctrl command and drop the ctrl address offset
>  - Change oxnas_nand struct name to oxnas_nand_ctrl
>  - Update DT-Bindings example to reflect the ctrl->chip->partitions hierarchy
> 
> Changes since RFC http://lkml.kernel.org/r/20161018090927.1990-1-narmstrong at baylibre.com :
>  - Avoid using chip->IO_ADDR*
>  - Use new DT structure
>  - Assign a chip for the subnode
>  - Use the nand_hw_control structure
>  - Cleanup probe
>  - Cleanup cmd_ctrl by using a context ctrl offset used in write_bytes
> 
> diff --git a/Documentation/devicetree/bindings/mtd/oxnas-nand.txt b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
> new file mode 100644
> index 0000000..33a77b8
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
> @@ -0,0 +1,41 @@
> +* Oxford Semiconductor OXNAS NAND Controller
> +
> +Please refer to nand.txt for generic information regarding MTD NAND bindings.
> +
> +Required properties:
> + - compatible: "oxsemi,ox820-nand"
> + - reg: Base address and length for NAND mapped memory.
> +
> +Optional Properties:
> + - clocks: phandle to the NAND gate clock if needed.
> + - resets: phandle to the NAND reset control if needed.
> +
> +Example:
> +
> +nand: nand-controller at 41000000 {
> +	compatible = "oxsemi,ox820-nand";
> +	reg = <0x41000000 0x100000>;
> +	clocks = <&stdclk CLK_820_NAND>;
> +	resets = <&reset RESET_NAND>;
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +
> +	nand at 0 {
> +		reg = <0>;
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +		nand-ecc-mode = "soft";
> +		nand-ecc-algo = "hamming";
> +
> +		partition at 0 {
> +			label = "boot";
> +			reg = <0x00000000 0x00e00000>;
> +			read-only;
> +		};
> +
> +		partition at e00000 {
> +			label = "ubi";
> +			reg = <0x00e00000 0x07200000>;
> +		};
> +	};
> +};
> diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
> index 7b7a887..c023125 100644
> --- a/drivers/mtd/nand/Kconfig
> +++ b/drivers/mtd/nand/Kconfig
> @@ -426,6 +426,11 @@ config MTD_NAND_ORION
>  	  No board specific support is done by this driver, each board
>  	  must advertise a platform_device for the driver to attach.
>  
> +config MTD_NAND_OXNAS
> +	tristate "NAND Flash support for Oxford Semiconductor SoC"
> +	help
> +	  This enables the NAND flash controller on Oxford Semiconductor SoCs.
> +
>  config MTD_NAND_FSL_ELBC
>  	tristate "NAND support for Freescale eLBC controllers"
>  	depends on FSL_SOC
> diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
> index cafde6f..05fc054 100644
> --- a/drivers/mtd/nand/Makefile
> +++ b/drivers/mtd/nand/Makefile
> @@ -35,6 +35,7 @@ obj-$(CONFIG_MTD_NAND_TMIO)		+= tmio_nand.o
>  obj-$(CONFIG_MTD_NAND_PLATFORM)		+= plat_nand.o
>  obj-$(CONFIG_MTD_NAND_PASEMI)		+= pasemi_nand.o
>  obj-$(CONFIG_MTD_NAND_ORION)		+= orion_nand.o
> +obj-$(CONFIG_MTD_NAND_OXNAS)		+= oxnas_nand.o
>  obj-$(CONFIG_MTD_NAND_FSL_ELBC)		+= fsl_elbc_nand.o
>  obj-$(CONFIG_MTD_NAND_FSL_IFC)		+= fsl_ifc_nand.o
>  obj-$(CONFIG_MTD_NAND_FSL_UPM)		+= fsl_upm.o
> diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/oxnas_nand.c
> new file mode 100644
> index 0000000..35c94af
> --- /dev/null
> +++ b/drivers/mtd/nand/oxnas_nand.c
> @@ -0,0 +1,196 @@
> +/*
> + * Oxford Semiconductor OXNAS NAND driver
> +
> + * Copyright (C) 2016 Neil Armstrong <narmstrong at baylibre.com>
> + * Heavily based on plat_nand.c :
> + * Author: Vitaly Wool <vitalywool at gmail.com>
> + * Copyright (C) 2013 Ma Haijun <mahaijuns at gmail.com>
> + * Copyright (C) 2012 John Crispin <blogic at openwrt.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/clk.h>
> +#include <linux/reset.h>
> +#include <linux/mtd/mtd.h>
> +#include <linux/mtd/nand.h>
> +#include <linux/mtd/partitions.h>
> +#include <linux/of.h>
> +
> +/* Nand commands */
> +#define OXNAS_NAND_CMD_ALE		BIT(18)
> +#define OXNAS_NAND_CMD_CLE		BIT(19)
> +
> +#define OXNAS_NAND_MAX_CHIPS	1
> +
> +struct oxnas_nand_ctrl {
> +	struct nand_hw_control base;
> +	void __iomem *io_base;
> +	struct clk *clk;
> +	struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS];
> +};
> +
> +static uint8_t oxnas_nand_read_byte(struct mtd_info *mtd)
> +{
> +	struct nand_chip *chip = mtd_to_nand(mtd);
> +	struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
> +
> +	return readb(oxnas->io_base);
> +}
> +
> +static void oxnas_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
> +{
> +	struct nand_chip *chip = mtd_to_nand(mtd);
> +	struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
> +
> +	ioread8_rep(oxnas->io_base, buf, len);
> +}
> +
> +static void oxnas_nand_write_buf(struct mtd_info *mtd,
> +				 const uint8_t *buf, int len)
> +{
> +	struct nand_chip *chip = mtd_to_nand(mtd);
> +	struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
> +
> +	iowrite8_rep(oxnas->io_base, buf, len);
> +}
> +
> +/* Single CS command control */
> +static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
> +				unsigned int ctrl)
> +{
> +	struct nand_chip *chip = mtd_to_nand(mtd);
> +	struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
> +
> +	if (ctrl & NAND_CLE)
> +		writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_CLE);
> +	else if (ctrl & NAND_ALE)
> +		writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_ALE);
> +}
> +
> +/*
> + * Probe for the NAND device.
> + */
> +static int oxnas_nand_probe(struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	struct device_node *nand_np;
> +	struct oxnas_nand_ctrl *oxnas;
> +	struct nand_chip *chip;
> +	struct mtd_info *mtd;
> +	struct resource *res;
> +	int nchips = 0;
> +	int count = 0;
> +	int err = 0;
> +
> +	/* Allocate memory for the device structure (and zero it) */
> +	oxnas = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip),
> +			    GFP_KERNEL);
> +	if (!oxnas)
> +		return -ENOMEM;
> +
> +	nand_hw_control_init(&oxnas->base);
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	oxnas->io_base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(oxnas->io_base))
> +		return PTR_ERR(oxnas->io_base);
> +
> +	oxnas->clk = devm_clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(oxnas->clk))
> +		oxnas->clk = NULL;
> +
> +	/* Only a single chip node is supported */
> +	count = of_get_child_count(np);
> +	if (count > 1)
> +		return -EINVAL;
> +
> +	clk_prepare_enable(oxnas->clk);
> +	device_reset_optional(&pdev->dev);
> +
> +	for_each_child_of_node(np, nand_np) {
> +		chip = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip),
> +				    GFP_KERNEL);
> +		if (!chip)
> +			return -ENOMEM;
> +
> +		chip->controller = &oxnas->base;
> +
> +		nand_set_flash_node(chip, nand_np);
> +		nand_set_controller_data(chip, oxnas);
> +
> +		mtd = nand_to_mtd(chip);
> +		mtd->dev.parent = &pdev->dev;
> +		mtd->priv = chip;
> +
> +		chip->cmd_ctrl = oxnas_nand_cmd_ctrl;
> +		chip->read_buf = oxnas_nand_read_buf;
> +		chip->read_byte = oxnas_nand_read_byte;
> +		chip->write_buf = oxnas_nand_write_buf;
> +		chip->chip_delay = 30;
> +
> +		/* Scan to find existence of the device */
> +		err = nand_scan(mtd, 1);
> +		if (err)
> +			return err;
> +
> +		err = mtd_device_register(mtd, NULL, 0);
> +		if (err) {
> +			nand_release(mtd);
> +			return err;
> +		}
> +
> +		oxnas->chips[nchips] = chip;
> +		++nchips;
> +	}
> +
> +	/* Exit if no chips found */
> +	if (!nchips)
> +		return -ENODEV;
> +
> +	platform_set_drvdata(pdev, oxnas);
> +
> +	return 0;
> +}
> +
> +static int oxnas_nand_remove(struct platform_device *pdev)
> +{
> +	struct oxnas_nand_ctrl *oxnas = platform_get_drvdata(pdev);
> +
> +	if (oxnas->chips[0])
> +		nand_release(nand_to_mtd(oxnas->chips[0]));
> +
> +	clk_disable_unprepare(oxnas->clk);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id oxnas_nand_match[] = {
> +	{ .compatible = "oxsemi,ox820-nand" },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, oxnas_nand_match);
> +
> +static struct platform_driver oxnas_nand_driver = {
> +	.probe	= oxnas_nand_probe,
> +	.remove	= oxnas_nand_remove,
> +	.driver	= {
> +		.name		= "oxnas_nand",
> +		.of_match_table = oxnas_nand_match,
> +	},
> +};
> +
> +module_platform_driver(oxnas_nand_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Neil Armstrong <narmstrong at baylibre.com>");
> +MODULE_DESCRIPTION("Oxnas NAND driver");
> +MODULE_ALIAS("platform:oxnas_nand");



From krzk at kernel.org  Sat Oct 22 08:32:08 2016
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sat, 22 Oct 2016 18:32:08 +0300
Subject: [PATCH v3 1/3] mtd: s3c2410: make ecc mode configurable via
 platform data
In-Reply-To: <20161022142907.08a3eedf@bbrezillon>
References: <1476999766-32526-1-git-send-email-sergio.prado@e-labworks.com>
 <1476999766-32526-2-git-send-email-sergio.prado@e-labworks.com>
 <20161021182710.GA17279@kozik-lap>
 <20161022142907.08a3eedf@bbrezillon>
Message-ID: <20161022153208.GA3830@kozik-lap>

On Sat, Oct 22, 2016 at 02:29:07PM +0200, Boris Brezillon wrote:
> Hi Krzysztof,
> 
> On Fri, 21 Oct 2016 21:27:10 +0300
> Krzysztof Kozlowski <krzk at kernel.org> wrote:
> 
> > On Thu, Oct 20, 2016 at 07:42:44PM -0200, Sergio Prado wrote:
> > > Removing CONFIG_MTD_NAND_S3C2410_HWECC option and adding a ecc_mode
> > > field in the drivers's platform data structure so it can be selectable
> > > via platform data.
> > > 
> > > Also setting this field to NAND_ECC_SOFT in all boards using this
> > > driver since none of them had CONFIG_MTD_NAND_S3C2410_HWECC enabled.
> > > 
> > > Signed-off-by: Sergio Prado <sergio.prado at e-labworks.com>
> > > ---
> > >  arch/arm/mach-s3c24xx/common-smdk.c            |   1 +
> > >  arch/arm/mach-s3c24xx/mach-anubis.c            |   1 +
> > >  arch/arm/mach-s3c24xx/mach-at2440evb.c         |   1 +
> > >  arch/arm/mach-s3c24xx/mach-bast.c              |   1 +
> > >  arch/arm/mach-s3c24xx/mach-gta02.c             |   1 +
> > >  arch/arm/mach-s3c24xx/mach-jive.c              |   1 +
> > >  arch/arm/mach-s3c24xx/mach-mini2440.c          |   1 +
> > >  arch/arm/mach-s3c24xx/mach-osiris.c            |   1 +
> > >  arch/arm/mach-s3c24xx/mach-qt2410.c            |   1 +
> > >  arch/arm/mach-s3c24xx/mach-rx1950.c            |   1 +
> > >  arch/arm/mach-s3c24xx/mach-rx3715.c            |   1 +
> > >  arch/arm/mach-s3c24xx/mach-vstms.c             |   1 +
> > >  arch/arm/mach-s3c64xx/mach-hmt.c               |   1 +
> > >  arch/arm/mach-s3c64xx/mach-mini6410.c          |   1 +
> > >  arch/arm/mach-s3c64xx/mach-real6410.c          |   1 +
> > >  drivers/mtd/nand/Kconfig                       |   9 --
> > >  drivers/mtd/nand/s3c2410.c                     | 119 +++++++++++++------------
> > >  include/linux/platform_data/mtd-nand-s3c2410.h |   6 +-
> > >  18 files changed, 79 insertions(+), 70 deletions(-)
> > >  
> > 
> > I acked this twice (v1 and v2)... and still you are ignoring them. I am
> > sorry, I am not gonna to ack this third time!
> > 
> > For v2 I acked also other patches but it it is not there as well...
> 
> I'll collect your acks (and Rob ones) when applying the patches. BTW,
> how should I proceed with patch 1? Do you want an topic branch
> containing this patch?

I don't expect much work around these files so the risk of conflicts is
rather small. You could put it on a topic branch just in case (so I
could pull in if needed) but I am fine with applying these to your tree
as is.

Best regards,
Krzysztof


From festevam at gmail.com  Sat Oct 22 09:15:22 2016
From: festevam at gmail.com (Fabio Estevam)
Date: Sat, 22 Oct 2016 14:15:22 -0200
Subject: [PATCH] mtd: nand: gpmi: disable the clocks on errors
Message-ID: <1477152922-6722-1-git-send-email-festevam@gmail.com>

From: Fabio Estevam <fabio.estevam at nxp.com>

We should disable the previously enabled GPMI clocks in the error paths.

Also, when gpmi_enable_clk() fails simply return the error
code immediately rather than jumping to to the 'err_out' label.

Signed-off-by: Fabio Estevam <fabio.estevam at nxp.com>
---
 drivers/mtd/nand/gpmi-nand/gpmi-lib.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
index 0f68a99..141bd70 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
@@ -161,7 +161,7 @@ int gpmi_init(struct gpmi_nand_data *this)
 
 	ret = gpmi_enable_clk(this);
 	if (ret)
-		goto err_out;
+		return ret;
 	ret = gpmi_reset_block(r->gpmi_regs, false);
 	if (ret)
 		goto err_out;
@@ -197,6 +197,7 @@ int gpmi_init(struct gpmi_nand_data *this)
 	gpmi_disable_clk(this);
 	return 0;
 err_out:
+	gpmi_disable_clk(this);
 	return ret;
 }
 
@@ -270,7 +271,7 @@ int bch_set_geometry(struct gpmi_nand_data *this)
 
 	ret = gpmi_enable_clk(this);
 	if (ret)
-		goto err_out;
+		return ret;
 
 	/*
 	* Due to erratum #2847 of the MX23, the BCH cannot be soft reset on this
@@ -308,6 +309,7 @@ int bch_set_geometry(struct gpmi_nand_data *this)
 	gpmi_disable_clk(this);
 	return 0;
 err_out:
+	gpmi_disable_clk(this);
 	return ret;
 }
 
-- 
2.7.4



From marex at denx.de  Sat Oct 22 13:33:29 2016
From: marex at denx.de (Marek Vasut)
Date: Sat, 22 Oct 2016 22:33:29 +0200
Subject: [PATCH v2 0/9] mtd: spi-nor: parse SFDP tables to setup (Q)SPI
 memories
In-Reply-To: <CAD6G_RR4Av8+szo9v2oucCFvwnow86gMVC-Ku_-Qfy18TVMGgA@mail.gmail.com>
References: <cover.1475668319.git.cyrille.pitchen@atmel.com>
 <CAD6G_RR4Av8+szo9v2oucCFvwnow86gMVC-Ku_-Qfy18TVMGgA@mail.gmail.com>
Message-ID: <c022e6fc-6bd7-d124-7233-e1e742049657@denx.de>

On 10/22/2016 01:00 PM, Jagan Teki wrote:
> On Wed, Oct 5, 2016 at 5:30 PM, Cyrille Pitchen
> <cyrille.pitchen at atmel.com> wrote:
>> Hi all,
>>
>> This series extends support of SPI protocols to new protocols such as
>> SPI x-2-2 and SPI x-4-4. Also spi_nor_scan() tries now to select the right
>> op codes, timing parameters (number of mode and dummy cycles) and erase
>> sector size by parsing the Serial Flash Discoverable Parameter (SFDP)
>> tables, when available, as defined in the JEDEC JESD216 specifications.
>>
>> When SFDP tables are not available, legacy settings are still used for
>> backward compatibility (SPI and earlier QSPI memories).
>>
>> Support of SPI memories >128Mbits is also improved by using the 4byte
>> address instruction set, when available. Using those dedicated op codes
>> is stateless as opposed to enter the 4byte address mode, hence a better
>> compatibility with some boot loaders which expect to use 3byte address
>> op codes.
> 
> The memories which are > 128Mbits should have 4-bytes addressing
> support based on my experience, do you think BAR is also required
> atleast from spi-nor side?

Yes, I believe BAR is still required for broken/dumb flash chips.
Not all chips > 16 MiB support dedicated 4-byte addressing opcodes :-(

-- 
Best regards,
Marek Vasut


From marek.vasut at gmail.com  Sat Oct 22 20:08:19 2016
From: marek.vasut at gmail.com (Marek Vasut)
Date: Sun, 23 Oct 2016 05:08:19 +0200
Subject: [PATCH] mtd: nand: gpmi: disable the clocks on errors
In-Reply-To: <1477152922-6722-1-git-send-email-festevam@gmail.com>
References: <1477152922-6722-1-git-send-email-festevam@gmail.com>
Message-ID: <73e38ebd-3612-94c3-46bf-dc6e29925ee3@gmail.com>

On 10/22/2016 06:15 PM, Fabio Estevam wrote:
> From: Fabio Estevam <fabio.estevam at nxp.com>
> 
> We should disable the previously enabled GPMI clocks in the error paths.
> 
> Also, when gpmi_enable_clk() fails simply return the error
> code immediately rather than jumping to to the 'err_out' label.
> 
> Signed-off-by: Fabio Estevam <fabio.estevam at nxp.com>

Reviewed-by: Marek Vasut <marex at denx.de>

> ---
>  drivers/mtd/nand/gpmi-nand/gpmi-lib.c | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
> index 0f68a99..141bd70 100644
> --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
> +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
> @@ -161,7 +161,7 @@ int gpmi_init(struct gpmi_nand_data *this)
>  
>  	ret = gpmi_enable_clk(this);
>  	if (ret)
> -		goto err_out;
> +		return ret;
>  	ret = gpmi_reset_block(r->gpmi_regs, false);
>  	if (ret)
>  		goto err_out;
> @@ -197,6 +197,7 @@ int gpmi_init(struct gpmi_nand_data *this)
>  	gpmi_disable_clk(this);
>  	return 0;
>  err_out:
> +	gpmi_disable_clk(this);
>  	return ret;
>  }
>  
> @@ -270,7 +271,7 @@ int bch_set_geometry(struct gpmi_nand_data *this)
>  
>  	ret = gpmi_enable_clk(this);
>  	if (ret)
> -		goto err_out;
> +		return ret;
>  
>  	/*
>  	* Due to erratum #2847 of the MX23, the BCH cannot be soft reset on this
> @@ -308,6 +309,7 @@ int bch_set_geometry(struct gpmi_nand_data *this)
>  	gpmi_disable_clk(this);
>  	return 0;
>  err_out:
> +	gpmi_disable_clk(this);
>  	return ret;
>  }
>  
> 


-- 
Best regards,
Marek Vasut


From punnaia at xilinx.com  Sun Oct 23 05:07:42 2016
From: punnaia at xilinx.com (punnaiah choudary kalluri)
Date: Sun, 23 Oct 2016 17:37:42 +0530
Subject: [v7,
 1/3] nand: pl353: Add basic driver for arm pl353 smc nand interface
In-Reply-To: <20161021234611.1f737144@bbrezillon>
References: <1433786918-21500-2-git-send-email-punnaia@xilinx.com>
 <20161021203322.GA28655@obsidianresearch.com>
 <20161021234611.1f737144@bbrezillon>
Message-ID: <CAGnW=Bb-pnJ9-xjcw-1dR-y+oKjNs53bgD+dh1LwsMTCmzdRmQ@mail.gmail.com>

Hi Boris and Jason,

 I am doing rework on these patches to accommodate recent changes with
 respect to ooblayout. Also some of the comments that i have received
from Boris as part of the arasan nand controller upstream patches will
apply to this driver. So, i will be releasing the next set of patches for this
driver soon and request your time for reviewing those patches.

for now, please ignore these patches.

Regards,
Punnaiah

On Sat, Oct 22, 2016 at 3:16 AM, Boris Brezillon
<boris.brezillon at free-electrons.com> wrote:
> On Fri, 21 Oct 2016 14:33:22 -0600
> Jason Gunthorpe <jgunthorpe at obsidianresearch.com> wrote:
>
>> On Mon, Jun 08, 2015 at 11:38:36PM +0530, Punnaiah Choudary Kalluri wrote:
>> > Add driver for arm pl353 static memory controller nand interface with
>> > HW ECC support. This controller is used in xilinx zynq soc for interfacing
>> > the nand flash memory.
>> >
>> > Signed-off-by: Punnaiah Choudary Kalluri <punnaia at xilinx.com>
>> > Changes in v7:
>> >  - Currently not implemented the memclk rate adjustments. I will
>> >    look into this later and once the basic driver is accepted.
>> >  - Fixed GPL licence ident
>> > Changes in v6:
>> >  - Fixed the checkpatch.pl reported warnings
>> >  - Using the address cycles information from the onfi param page
>> >    earlier it is hardcoded to 5 in driver
>> > Changes in v5:
>> >  - Configure the nand timing parameters as per the onfi spec
>> > Changes in v4:
>> >  - Updated the driver to sync with pl353_smc driver APIs
>> > Changes in v3:
>> >  - implemented the proper error codes
>> >  - further breakdown this patch to multiple sets
>> >  - added the controller and driver details to Documentation section
>> >  - updated the licenece to GPLv2
>> >  - reorganized the pl353_nand_ecc_init function
>> > Changes in v2:
>> >  - use "depends on" rather than "select" option in kconfig
>> >  - remove unused variable parts
>> >  - remove dummy helper and use writel_relaxed directly
>>
>> What is the status of getting this driver merged? I am interested in
>> this driver and can provide some help if there are still TODO items.
>
> I'll try to review it next week.
>
>>
>> At the very least I will test it, is there something newer than v7 out
>> there?
>>
>> Regards,
>> Jason
>>
>> ______________________________________________________
>> Linux MTD discussion mailing list
>> http://lists.infradead.org/mailman/listinfo/linux-mtd/
>


From richard at nod.at  Sun Oct 23 07:22:34 2016
From: richard at nod.at (Richard Weinberger)
Date: Sun, 23 Oct 2016 16:22:34 +0200
Subject: [GIT PULL] UBI/UBIFS fixes for 4.9-rc2
Message-ID: <21b545f1-0374-ab2c-03ac-93d8717f9ce3@nod.at>

Linus,

The following changes since commit c3f8f7fa8b19e274e7eb99dee428ad3a9b2ad8eb:

  Merge tag 'platform-drivers-x86-v4.9-2' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86 (2016-10-19 11:45:06 -0700)

are available in the git repository at:

  git://git.infradead.org/linux-ubifs.git tags/upstream-4.9-rc2

for you to fetch changes up to c83ed4c9dbb358b9e7707486e167e940d48bfeed:

  ubifs: Abort readdir upon error (2016-10-20 00:06:11 +0200)

----------------------------------------------------------------
This pull requests contains fixes for issues in both UBI and UBIFS:
- Fallout from the merge window, refactoring UBI code introduced some issues.
- Fixes for an UBIFS readdir bug which can cause getdents() to busy loop
  for ever and a bug in the UBIFS xattr code.

----------------------------------------------------------------
Colin Ian King (1):
      ubi: fix swapped arguments to call to ubi_alloc_aeb

Geert Uytterhoeven (1):
      UBI: Fix crash in try_recover_peb()

Richard Weinberger (3):
      ubifs: Rename ubifs_rename2
      ubifs: Fix xattr_names length in exit paths
      ubifs: Abort readdir upon error

 drivers/mtd/ubi/eba.c     |  1 +
 drivers/mtd/ubi/fastmap.c |  2 +-
 fs/ubifs/dir.c            | 20 +++++++++-----------
 fs/ubifs/xattr.c          |  2 ++
 4 files changed, 13 insertions(+), 12 deletions(-)


From richard at nod.at  Sun Oct 23 07:22:34 2016
From: richard at nod.at (Richard Weinberger)
Date: Sun, 23 Oct 2016 16:22:34 +0200
Subject: [GIT PULL] UBI/UBIFS fixes for 4.9-rc2
Message-ID: <21b545f1-0374-ab2c-03ac-93d8717f9ce3@nod.at>

Linus,

The following changes since commit c3f8f7fa8b19e274e7eb99dee428ad3a9b2ad8eb:

  Merge tag 'platform-drivers-x86-v4.9-2' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86 (2016-10-19 11:45:06 -0700)

are available in the git repository at:

  git://git.infradead.org/linux-ubifs.git tags/upstream-4.9-rc2

for you to fetch changes up to c83ed4c9dbb358b9e7707486e167e940d48bfeed:

  ubifs: Abort readdir upon error (2016-10-20 00:06:11 +0200)

----------------------------------------------------------------
This pull requests contains fixes for issues in both UBI and UBIFS:
- Fallout from the merge window, refactoring UBI code introduced some issues.
- Fixes for an UBIFS readdir bug which can cause getdents() to busy loop
  for ever and a bug in the UBIFS xattr code.

----------------------------------------------------------------
Colin Ian King (1):
      ubi: fix swapped arguments to call to ubi_alloc_aeb

Geert Uytterhoeven (1):
      UBI: Fix crash in try_recover_peb()

Richard Weinberger (3):
      ubifs: Rename ubifs_rename2
      ubifs: Fix xattr_names length in exit paths
      ubifs: Abort readdir upon error

 drivers/mtd/ubi/eba.c     |  1 +
 drivers/mtd/ubi/fastmap.c |  2 +-
 fs/ubifs/dir.c            | 20 +++++++++-----------
 fs/ubifs/xattr.c          |  2 ++
 4 files changed, 13 insertions(+), 12 deletions(-)


From marcin.krzeminski at nokia.com  Sun Oct 23 23:10:02 2016
From: marcin.krzeminski at nokia.com (Krzeminski, Marcin (Nokia - PL/Wroclaw))
Date: Mon, 24 Oct 2016 06:10:02 +0000
Subject: [PATCH] mtd: spi-nor: Add possibility to disable chip erase
In-Reply-To: <3b23706b-bf46-8d3b-e9b0-01194eec5e11@gmail.com>
References: <1477054546-2548-1-git-send-email-marcin.krzeminski@nokia.com>
 <3b23706b-bf46-8d3b-e9b0-01194eec5e11@gmail.com>
Message-ID: <AM4PR0701MB21309FFCFE8370E3153ED66AFEA90@AM4PR0701MB2130.eurprd07.prod.outlook.com>

Hi Marek,

> -----Original Message-----
> From: Marek Vasut [mailto:marek.vasut at gmail.com]
> Sent: Friday, October 21, 2016 7:53 PM
> To: Krzeminski, Marcin (Nokia - PL/Wroclaw)
> <marcin.krzeminski at nokia.com>; linux-mtd at lists.infradead.org
> Cc: computersforpeace at gmail.com; cyrille.pitchen at atmel.com; rfsw-
> patches at mlist.nokia.com; dwmw2 at infradead.org
> Subject: Re: [PATCH] mtd: spi-nor: Add possibility to disable chip erase
> 
> On 10/21/2016 02:55 PM, marcin.krzeminski at nokia.com wrote:
> > From: Marcin Krzeminski <marcin.krzeminski at nokia.com>
> >
> > n25q00 does not support chip erase command (0xC7), but spi-nor
> > framework still send if if user want to erase whole flash. This patch
> > adds option to disable chip erase command and enable in on n25q00.
> 
> That's true and it's a pretty nasty issue.
> Can you instead implement logic to send multiple die-erase commands ?
> They do make erasing faster afterall.
> 
As we talked I would like to have die erase. I post is after tests,
It will be a difference series since functionality will be different.
In my MT25Q00 difference between die erase and sector at time erase
is about 40 second.

Regards,
Marcin

> > Signed-off-by: Marcin Krzeminski <marcin.krzeminski at nokia.com>
> > ---
> >  drivers/mtd/spi-nor/spi-nor.c | 9 ++++++---
> >  include/linux/mtd/spi-nor.h   | 1 +
> >  2 files changed, 7 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/mtd/spi-nor/spi-nor.c
> > b/drivers/mtd/spi-nor/spi-nor.c index d0fc165..8338be1 100644
> > --- a/drivers/mtd/spi-nor/spi-nor.c
> > +++ b/drivers/mtd/spi-nor/spi-nor.c
> > @@ -75,6 +75,7 @@ struct flash_info {
> >  					 * bit. Must be used with
> >  					 * SPI_NOR_HAS_LOCK.
> >  					 */
> > +#define DISABLE_CE			BIT(10)	/*Some multi-die
> flash does not support CE */
> >  };
> >
> >  #define JEDEC_MFR(info)	((info)->id[0])
> > @@ -368,7 +369,7 @@ static int spi_nor_erase(struct mtd_info *mtd,
> struct erase_info *instr)
> >  		return ret;
> >
> >  	/* whole-chip erase? */
> > -	if (len == mtd->size) {
> > +	if (len == mtd->size && !(nor->flags & SNOR_F_DISABLE_CE)) {
> >  		unsigned long timeout;
> >
> >  		write_enable(nor);
> > @@ -886,8 +887,8 @@ static const struct flash_info spi_nor_ids[] = {
> >  	{ "n25q256a",    INFO(0x20ba19, 0, 64 * 1024,  512, SECT_4K |
> SPI_NOR_QUAD_READ) },
> >  	{ "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) },
> > +	{ "n25q00",      INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR
> | SPI_NOR_QUAD_READ | DISABLE_CE) },
> > +	{ "n25q00a",     INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR
> | SPI_NOR_QUAD_READ | DISABLE_CE) },
> >
> >  	/* PMC */
> >  	{ "pm25lv512",   INFO(0,        0, 32 * 1024,    2, SECT_4K_PMC) },
> > @@ -1395,6 +1396,8 @@ int spi_nor_scan(struct spi_nor *nor, const char
> *name, enum read_mode mode)
> >  		nor->flags |= SNOR_F_USE_FSR;
> >  	if (info->flags & SPI_NOR_HAS_TB)
> >  		nor->flags |= SNOR_F_HAS_SR_TB;
> > +	if (info->flags & DISABLE_CE)
> > +		nor->flags |= SNOR_F_DISABLE_CE;
> >
> >  #ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
> >  	/* prefer "small sector" erase if possible */ diff --git
> > a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index
> > c425c7b..2d0b967 100644
> > --- a/include/linux/mtd/spi-nor.h
> > +++ b/include/linux/mtd/spi-nor.h
> > @@ -119,6 +119,7 @@ enum spi_nor_ops {  enum spi_nor_option_flags {
> >  	SNOR_F_USE_FSR		= BIT(0),
> >  	SNOR_F_HAS_SR_TB	= BIT(1),
> > +	SNOR_F_DISABLE_CE	= BIT(2),
> >  };
> >
> >  /**
> >
> 
> 
> --
> Best regards,
> Marek Vasut


From richard at nod.at  Sun Oct 23 23:54:03 2016
From: richard at nod.at (Richard Weinberger)
Date: Mon, 24 Oct 2016 08:54:03 +0200
Subject: [PATCH 20/26] ubifs: Add support for encrypted symlinks
In-Reply-To: <20161021184231.GD90712@google.com>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
 <1477054121-10198-21-git-send-email-richard@nod.at>
 <20161021184231.GD90712@google.com>
Message-ID: <e251d6e6-514c-84ba-60df-143b16a0b020@nod.at>

Eric,

On 21.10.2016 20:42, Eric Biggers wrote:
> On Fri, Oct 21, 2016 at 02:48:35PM +0200, Richard Weinberger wrote:
>> +
>> +	if (!dentry)
>> +		return ERR_PTR(-ECHILD);
>> +
>> +	if (ubifs_crypt_is_encrypted(inode)) {
>> +		err = fscrypt_get_encryption_info(inode);
>> +		if (err)
>> +			return ERR_PTR(err);
>> +	} else
>> +		return ui->data;
>> +
> 
> This will make path lookups drop out of RCU mode when an unencrypted symlink is
> followed.  This can be avoided by checking for unencrypted symlinks first:

Oh! Thanks for pointing this out!

> 	if (!ubifs_crypt_is_encrypted(inode))
> 		return ui->data;
> 
> 	if (!dentry)
> 		return ERR_PTR(-ECHILD);
> 
> 	err = fscrypt_get_encryption_info(inode);
> 	if (err)
> 		return ERR_PTR(err);
> 
>> +
>> +	pstr.name[err] = '\0';
>> +
> 
> In 4.9, fscrypt_fname_{disk_to_usr,usr_to_disk} return 0 instead of the output
> length, so this will need to be changed to 'pstr.name[pstr.len] = '\0''.

Noted.

Thanks,
//richard


From richard at nod.at  Sun Oct 23 23:59:26 2016
From: richard at nod.at (Richard Weinberger)
Date: Mon, 24 Oct 2016 08:59:26 +0200
Subject: [PATCH 25/26] ubifs: Implement UBIFS_FLG_ENCRYPTION
In-Reply-To: <20161021183012.GC90712@google.com>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
 <1477054121-10198-26-git-send-email-richard@nod.at>
 <20161021183012.GC90712@google.com>
Message-ID: <58235996-2da6-259c-a02c-9e7fcb499d62@nod.at>

Eric,

On 21.10.2016 20:30, Eric Biggers wrote:
> On Fri, Oct 21, 2016 at 02:48:40PM +0200, Richard Weinberger wrote:
>> @@ -190,6 +191,10 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
>>  				   sizeof(policy)))
>>  			return -EFAULT;
>>  
>> +		err = ubifs_enable_encryption(c);
>> +		if (err)
>> +			return err;
>> +
>>  		err = fscrypt_process_policy(file, &policy);
> 
> Is ubifs_enable_encryption() being done with proper locking and authorization?

Anyone can encrypted files when UBIFS is build with that feature. Locking is fine
since the operation is atomic. (UBI LEB change).

> As-is, anyone can call this at any time if they can open some file on UBIFS.

That's what I had in mind.

> FYI, the approach being taken for ext4 is that the encryption feature flag has
> to be explicitly turned on before FS_IOC_SET_ENCRYPTION_POLICY will work.

So, on ext4 (f2fs too?) root has to enable to feature first before users
can use it?
IOW for ext4 the encryption flag means "file encryption is allowed", for UBIFS it
means "at least one file got encrypted on this fs".

I think I'll do what ext4 does to have common policies.
BTW: Are these policies documented somewhere?

Thanks,
//richard


From richard at nod.at  Mon Oct 24 00:00:03 2016
From: richard at nod.at (Richard Weinberger)
Date: Mon, 24 Oct 2016 09:00:03 +0200
Subject: [PATCH 15/26] ubifs: Implement encrypt/decrypt for all IO
In-Reply-To: <20161021182559.GB90712@google.com>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
 <1477054121-10198-16-git-send-email-richard@nod.at>
 <20161021182559.GB90712@google.com>
Message-ID: <ad408dbe-db9a-05f5-b3ee-8a650aceafb3@nod.at>

Eric,

On 21.10.2016 20:25, Eric Biggers wrote:
> On Fri, Oct 21, 2016 at 02:48:30PM +0200, Richard Weinberger wrote:
>> +
>> +	if (ubifs_crypt_is_encrypted(inode)) {
>> +		int clen = le16_to_cpu(dn->compr_size);
>> +
>> +		if (clen <= 0 || clen > UBIFS_BLOCK_SIZE || clen > dlen)
>> +			goto dump;
>> +
>> +		ubifs_assert(dlen <= UBIFS_BLOCK_SIZE);
>> +		err = fscrypt_decrypt_buffer(inode, &dn->data, &dn->data, dlen, block, GFP_NOFS);
>> +		if (err) {
>> +			ubifs_err(c, "fscrypt_decrypt_buffer failed: %i", err);
>> +			return err;
>> +		}
>> +
>> +		ubifs_assert(clen <= dlen);
>> +		dlen = clen;
>> +	}
>> +
> 
> There are several code blocks like this, calling either fscrypt_decrypt_buffer()
> or fscrypt_encrypt_buffer(), which seem to be mostly duplicated.  Is it possible
> to refactor them into helper functions?  There are also some lines well over 80
> characters.

Yes, that's already on my TODO.

Thanks,
//richard


From richard at nod.at  Mon Oct 24 00:03:56 2016
From: richard at nod.at (Richard Weinberger)
Date: Mon, 24 Oct 2016 09:03:56 +0200
Subject: [PATCH 26/26] ubifs: Raise write version to 5
In-Reply-To: <20161021174758.wz7xrulokicuhlht@thunk.org>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
 <1477054121-10198-27-git-send-email-richard@nod.at>
 <20161021173154.GB17121@google.com>
 <20161021174758.wz7xrulokicuhlht@thunk.org>
Message-ID: <b7909fac-9ebe-613c-77ca-0a7fcd494e46@nod.at>

Ted,

On 21.10.2016 19:47, Theodore Ts'o wrote:
> On Fri, Oct 21, 2016 at 10:31:54AM -0700, Michael Halcrow wrote:
>>> diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h
>>> index bdc7935a5e41..e8c23c9d4f4a 100644
>>> --- a/fs/ubifs/ubifs-media.h
>>> +++ b/fs/ubifs/ubifs-media.h
>>> @@ -46,7 +46,7 @@
>>>   * UBIFS went into mainline kernel with format version 4. The older formats
>>>   * were development formats.
>>>   */
>>> -#define UBIFS_FORMAT_VERSION 4
>>> +#define UBIFS_FORMAT_VERSION 5
>>
>> Alex Cope is working on a fix for file name encryption in ext4 so that
>> common plaintext prefixes don't result in common ciphertext prefixes.
>> Older kernels will not be able to read the new file names.
> 
> To be clear, this will be done in the context of a new encryption
> mode.  In terms of how Ubifs will handle things, that's going to
> depend on whether ubifs uses a single major version number or whether
> they have a feature bitmask like other filesystems, including ext4.

With write version 5, UBIFS has a real feature bitmask.
UBIFS has a feature bitmask since ever but never enforced it.
i.e. you could set bits which are unknown to UBIFS and it sill mounted.
Now UBIFS will refuse to mount when features are set which are not known/enabled
by this implementation.

Maybe I'll add another bitmap just for crypto do be able to support different cipher
modes.

Thanks,
//richard


From richard at nod.at  Mon Oct 24 00:05:42 2016
From: richard at nod.at (Richard Weinberger)
Date: Mon, 24 Oct 2016 09:05:42 +0200
Subject: [PATCH 01/26] fscrypto: Add buffer operations
In-Reply-To: <20161021132400.GA28880@infradead.org>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
 <1477054121-10198-2-git-send-email-richard@nod.at>
 <20161021130558.GA2411@infradead.org>
 <9c80d1d0-0237-606f-91ce-a004c3694aa5@nod.at>
 <20161021132400.GA28880@infradead.org>
Message-ID: <b7f1f92e-3e0f-ba91-fc36-dcf45c6d461d@nod.at>

Christoph,

On 21.10.2016 15:24, Christoph Hellwig wrote:
> On Fri, Oct 21, 2016 at 03:17:03PM +0200, Richard Weinberger wrote:
>> UBIFS works on kmalloc()'ed buffers where it constructs the NAND/NOR pages
>> which will be written to the MTD. JFFS2 does the same.
> 
> Yes, you can trivially do a virt_to_page on a kmalloc buffer.
> 
>> Another reason why I did the buffer functions is because fscrypt_encrypt_page()
>> always allocates a bounce page as temporary memory. For ext4 this is needed,
>> for UBIFS not.
>> UBIFS has already a construction buffer, especially since it also does compression.
> 
> We should defintively find a way to avoid that, but it's a separate
> issue from adding another API just to pass buffers.

Okay, I'll address this in v2 of my series.

Thanks,
//richard


From richard at nod.at  Mon Oct 24 00:08:13 2016
From: richard at nod.at (Richard Weinberger)
Date: Mon, 24 Oct 2016 09:08:13 +0200
Subject: UBIFS with dma on 4.6 kernel is not working
In-Reply-To: <20161021131505.GA25942@infradead.org>
References: <DA6901612C71B84D91459DE817C418AE26DF0F2B@XAP-PVEXMBX01.xlnx.xilinx.com>
 <519a83bf-1244-5151-b873-bb8e1f2db3c6@nod.at>
 <20161021125313.GA16754@infradead.org>
 <c0b0098d-3a68-3a4a-0b7e-a1d95dd4aafc@nod.at>
 <20161021131505.GA25942@infradead.org>
Message-ID: <3de2ca29-120b-b7a6-da55-47fe5e056f73@nod.at>

Christoph,

On 21.10.2016 15:15, Christoph Hellwig wrote:
> On Fri, Oct 21, 2016 at 03:07:57PM +0200, Richard Weinberger wrote:
>> Hmm, thought this is still problematic on VIVT architectures.
>> Boris tried to provide a solution for that some time ago:
>> http://www.spinics.net/lists/arm-kernel/msg494025.html
> 
> Things have been working fine for approx 10 years when using
> flush_kernel_vmap_range before doing I/O using the physical addresses and
> then invalidate_kernel_vmap_range when completing the I/O and going back
> to using the virtual mapping for XFS.
> 
> Of course all this assumes at least the higher level that did the
> vm_map_ram operation knows about this dance between virtually mapped and
> physiscal addresses. 

Good to know, I was clearly wrong.

Let's see whether the costs of flush_kernel_vmap_range and invalidate_kernel_vmap_range
are smaller than the speedup by DMA on embedded platforms.
We'll have to test it.

Thanks,
//richard


From jagan at openedev.com  Mon Oct 24 00:35:20 2016
From: jagan at openedev.com (Jagan Teki)
Date: Mon, 24 Oct 2016 13:05:20 +0530
Subject: [PATCH v2 1/9] mtd: spi-nor: improve macronix_quad_enable()
In-Reply-To: <ad5a4648bd2486d5c8e671312a0a717fa2a6b2b8.1475668319.git.cyrille.pitchen@atmel.com>
References: <cover.1475668319.git.cyrille.pitchen@atmel.com>
 <ad5a4648bd2486d5c8e671312a0a717fa2a6b2b8.1475668319.git.cyrille.pitchen@atmel.com>
Message-ID: <CAD6G_RRDFaJU=u5qvscYw+3KEb3GqzJEWwCjePhogQT6XZzaBQ@mail.gmail.com>

On Wed, Oct 5, 2016 at 5:30 PM, Cyrille Pitchen
<cyrille.pitchen at atmel.com> wrote:
> The patch checks whether the Quad Enable bit is already set in the Status
> Register. If so, the function exits immediately with a successful return
> code. Otherwise, a message is now printed telling we're setting the
> non-volatile bit.
>
> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>

Reviewed-by: Jagan Teki <jagan at openedev.com>

> ---
>  drivers/mtd/spi-nor/spi-nor.c | 5 +++++
>  1 file changed, 5 insertions(+)
>
> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
> index d0fc165d7d66..5c87b2d99507 100644
> --- a/drivers/mtd/spi-nor/spi-nor.c
> +++ b/drivers/mtd/spi-nor/spi-nor.c
> @@ -1211,6 +1211,11 @@ static int macronix_quad_enable(struct spi_nor *nor)
>         val = read_sr(nor);
>         if (val < 0)
>                 return val;
> +       if (val & SR_QUAD_EN_MX)
> +               return 0;
> +
> +       /* Update the Quad Enable bit. */
> +       dev_info(nor->dev, "setting Macronix Quad Enable (non-volatile) bit\n");
>         write_enable(nor);
>
>         write_sr(nor, val | SR_QUAD_EN_MX);

Safe to save ret and check the same as well.

thanks!
-- 
Jagan Teki
Free Software Engineer | www.openedev.com
U-Boot, Linux | Upstream Maintainer
Hyderabad, India.


From jagan at openedev.com  Mon Oct 24 00:41:29 2016
From: jagan at openedev.com (Jagan Teki)
Date: Mon, 24 Oct 2016 13:11:29 +0530
Subject: [PATCH v2 0/9] mtd: spi-nor: parse SFDP tables to setup (Q)SPI
 memories
In-Reply-To: <c022e6fc-6bd7-d124-7233-e1e742049657@denx.de>
References: <cover.1475668319.git.cyrille.pitchen@atmel.com>
 <CAD6G_RR4Av8+szo9v2oucCFvwnow86gMVC-Ku_-Qfy18TVMGgA@mail.gmail.com>
 <c022e6fc-6bd7-d124-7233-e1e742049657@denx.de>
Message-ID: <CAD6G_RQ2BjtF2cmPUJvYNk7KZZ6eTVAQsEqWs26xn710A4Dz-w@mail.gmail.com>

On Sun, Oct 23, 2016 at 2:03 AM, Marek Vasut <marex at denx.de> wrote:
> On 10/22/2016 01:00 PM, Jagan Teki wrote:
>> On Wed, Oct 5, 2016 at 5:30 PM, Cyrille Pitchen
>> <cyrille.pitchen at atmel.com> wrote:
>>> Hi all,
>>>
>>> This series extends support of SPI protocols to new protocols such as
>>> SPI x-2-2 and SPI x-4-4. Also spi_nor_scan() tries now to select the right
>>> op codes, timing parameters (number of mode and dummy cycles) and erase
>>> sector size by parsing the Serial Flash Discoverable Parameter (SFDP)
>>> tables, when available, as defined in the JEDEC JESD216 specifications.
>>>
>>> When SFDP tables are not available, legacy settings are still used for
>>> backward compatibility (SPI and earlier QSPI memories).
>>>
>>> Support of SPI memories >128Mbits is also improved by using the 4byte
>>> address instruction set, when available. Using those dedicated op codes
>>> is stateless as opposed to enter the 4byte address mode, hence a better
>>> compatibility with some boot loaders which expect to use 3byte address
>>> op codes.
>>
>> The memories which are > 128Mbits should have 4-bytes addressing
>> support based on my experience, do you think BAR is also required
>> atleast from spi-nor side?
>
> Yes, I believe BAR is still required for broken/dumb flash chips.
> Not all chips > 16 MiB support dedicated 4-byte addressing opcodes :-(

Do you have list for those broken chips? because I never find any
chips which has > 16 MiB with not support of 4-byte address opcodes
and I've seen the controller has dependable with BAR though it can
access > 16MiB ex: zynq qspi/

thanks!
-- 
Jagan Teki
Free Software Engineer | www.openedev.com
U-Boot, Linux | Upstream Maintainer
Hyderabad, India.


From jagan at openedev.com  Mon Oct 24 01:04:44 2016
From: jagan at openedev.com (Jagan Teki)
Date: Mon, 24 Oct 2016 13:34:44 +0530
Subject: [PATCH] mtd: spi-nor: Add support for N25Q256A13
In-Reply-To: <1475637910-2324-1-git-send-email-nobuhiro.iwamatsu.kw@hitachi.com>
References: <1475637910-2324-1-git-send-email-nobuhiro.iwamatsu.kw@hitachi.com>
Message-ID: <CAD6G_RT8s5=vDP2bc__SULyxt=NnqZrLDuepcUkxs75HG9=ZQg@mail.gmail.com>

On Wed, Oct 5, 2016 at 8:55 AM, Nobuhiro Iwamatsu
<nobuhiro.iwamatsu.kw at hitachi.com> wrote:
> Add Micron N25Q256A13 256Mbit NOR Flash in the list of supported
> devices. This chip is the same structure as the N25Q256A but ID
> is different.
>
> Signed-off-by: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.kw at hitachi.com>
> ---
>
>  drivers/mtd/spi-nor/spi-nor.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
> index d0fc165..ce67ccd 100644
> --- a/drivers/mtd/spi-nor/spi-nor.c
> +++ b/drivers/mtd/spi-nor/spi-nor.c
> @@ -884,6 +884,7 @@ static const struct flash_info spi_nor_ids[] = {
>         { "n25q128a11",  INFO(0x20bb18, 0, 64 * 1024,  256, SECT_4K | SPI_NOR_QUAD_READ) },
>         { "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024,  256, SECT_4K | SPI_NOR_QUAD_READ) },
>         { "n25q256a",    INFO(0x20ba19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_QUAD_READ) },
> +       { "n25q256a13",  INFO(0x20bb19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_QUAD_READ) },

Since the previous chips follow 'a' notation for bb chips, better to
use n25q256a for bb and n25q256 for ba

thanks!
-- 
Jagan Teki
Free Software Engineer | www.openedev.com
U-Boot, Linux | Upstream Maintainer
Hyderabad, India.


From jagan at openedev.com  Mon Oct 24 01:09:19 2016
From: jagan at openedev.com (Jagan Teki)
Date: Mon, 24 Oct 2016 13:39:19 +0530
Subject: [PATCH] mtd: spi-nor: Add support for mr25h40
In-Reply-To: <OS2PR01MB007355EE4F7CBD8647D65CD8DFC50@OS2PR01MB0073.jpnprd01.prod.outlook.com>
References: <OS2PR01MB007355EE4F7CBD8647D65CD8DFC50@OS2PR01MB0073.jpnprd01.prod.outlook.com>
Message-ID: <CAD6G_RRTiToQScvOSCyrUn7XR9oLhoi574FabypAfPtSoMRF9g@mail.gmail.com>

On Wed, Oct 5, 2016 at 1:52 PM, IWAMOTO Masahiko
<iwamoto at allied-telesis.co.jp> wrote:
>
> Add Everspin mr25h40 512KB MRAM to the list of supported chips.
>
> Signed-off-by: Masahiko Iwamoto <iwamoto at allied-telesis.co.jp>

Reviewed-by: Jagan Teki <jagan at openedev.com>

thanks!
-- 
Jagan Teki
Free Software Engineer | www.openedev.com
U-Boot, Linux | Upstream Maintainer
Hyderabad, India.


From jagan at openedev.com  Mon Oct 24 01:16:12 2016
From: jagan at openedev.com (Jagan Teki)
Date: Mon, 24 Oct 2016 13:46:12 +0530
Subject: [PATCHv1] mtd: spi-nor: add support for s25fl208k
In-Reply-To: <20161005085949.29804-1-sean.nyekjaer@prevas.dk>
References: <20161005085949.29804-1-sean.nyekjaer@prevas.dk>
Message-ID: <CAD6G_RSJPXj2qNM28ODnW94q6dpqfJSRrm3YK7HdNB8_DVUahQ@mail.gmail.com>

On Wed, Oct 5, 2016 at 2:29 PM, Sean Nyekjaer <sean.nyekjaer at prevas.dk> wrote:
> Signed-off-by: Sean Nyekjaer <sean.nyekjaer at prevas.dk>
> ---
> Changes: Fixed commit msg

Reviewed-by: Jagan Teki <jagan at openedev.com>

thanks!
-- 
Jagan Teki
Free Software Engineer | www.openedev.com
U-Boot, Linux | Upstream Maintainer
Hyderabad, India.


From Joel.Esponde at Honeywell.com  Mon Oct 24 01:29:32 2016
From: Joel.Esponde at Honeywell.com (Esponde, Joel)
Date: Mon, 24 Oct 2016 08:29:32 +0000
Subject: [PATCH] mtd: spi-nor: fixed spansion quad enable
In-Reply-To: <83e02f1d-2c58-10cc-567c-2a58a363767e@atmel.com>
References: <1476971026-9665-1-git-send-email-joel.esponde@honeywell.com>
 <56670303-e8e8-fb2c-e043-035c566f347c@atmel.com>
 <F6CD090A69E64C4289DC608E1C5D20242544AEF1@DE08W1305.global.ds.honeywell.com>
 <f45e1845-573f-d0b7-0f23-abd035f25945@atmel.com>
 <83e02f1d-2c58-10cc-567c-2a58a363767e@atmel.com>
Message-ID: <F6CD090A69E64C4289DC608E1C5D20242545486D@DE08W1305.global.ds.honeywell.com>

Hi Cyrille,

> -----Message d'origine-----
> De?: Cyrille Pitchen [mailto:cyrille.pitchen at atmel.com]
> Envoy??: vendredi 21 octobre 2016 15:45
> ??: Esponde, Joel <Joel.Esponde at Honeywell.com>; linux-
> mtd at lists.infradead.org
> Objet?: Re: [PATCH] mtd: spi-nor: fixed spansion quad enable
> 
> > That's a very good remark and I think the reason is that the current
> > implementation of spansion_quad_enable() suffers from a bug but this
> > one is almost harmless:
> >
> > I assume there is pull-up resistor on the MISO line:
> > spansion_quad_enable() sends a 35h command, which is not supported
> > hence ignored by some memories, then it reads a 1-byte value of FFh
> > due to the pull-up so we pass the test which checks that the Quad Enable
> bit has successfully been set.
> >
> > Then if we now add the same test before sending the Write Status (01h)
> > command with 2 bytes (SR1 then CR/SR2), we also read a FFh value for
> > the Configuration Register hence we skip the Write Status command
> > because we think the Quad Enable bit has already been set but if we
> > are using a brand new memory still using its factory settings the Quad
> > Enable has never been set and won't be set since we now skip the Write
> Status command.
> >
> > I think this what currently happens but I need to check with one of my
> > memory samples if I can find one which doesn't support the Read CR
> > command but I not sure to have such a sample...
> 
> The JESD216B specification clearly deals with 2 cases: a first one where the
> 35h command is not used, I guess because not supported, and a second case
> using both the 05h and 35h commands to read the SR1 and SR2/CR1 memory
> registers before writing both SR1 and SR2/CR1 with the 01h command.
> 
> However I can't provide any example of memory sample falling into the first
> case. I guess case 1 only applies to old and buggy memories and maybe not
> so used in production.
> Besides, your patch is great so I wonder whether it makes sense to reject it
> just because it might introduce a regression with some unidentified
> memories...
> If so, I think we could still find a workaround later to handle those very few
> (deprecated) parts.
> 
> The S25FL127S memory is still recommended by Cypress/Spansion for new
> designs.
> 

I cannot help here as I have only one part number of flash memory...
But from a performance point of view, it would be really great to have this pre test before writing quad enable bit to memory.
In my case, I will have to keep this patch because I cannot add useless 200ms delay at boot time.

Best regards,

Jo?l


From Joel.Esponde at Honeywell.com  Mon Oct 24 01:33:11 2016
From: Joel.Esponde at Honeywell.com (Esponde, Joel)
Date: Mon, 24 Oct 2016 08:33:11 +0000
Subject: [PATCH] mtd: spi-nor: fixed spansion quad enable
In-Reply-To: <f45e1845-573f-d0b7-0f23-abd035f25945@atmel.com>
References: <1476971026-9665-1-git-send-email-joel.esponde@honeywell.com>
 <56670303-e8e8-fb2c-e043-035c566f347c@atmel.com>
 <F6CD090A69E64C4289DC608E1C5D20242544AEF1@DE08W1305.global.ds.honeywell.com>
 <f45e1845-573f-d0b7-0f23-abd035f25945@atmel.com>
Message-ID: <F6CD090A69E64C4289DC608E1C5D20242545487D@DE08W1305.global.ds.honeywell.com>

Hi Cyrille,

> -----Message d'origine-----
> De?: Cyrille Pitchen [mailto:cyrille.pitchen at atmel.com]
> Envoy??: vendredi 21 octobre 2016 14:50
> ??: Esponde, Joel <Joel.Esponde at Honeywell.com>; linux-
> mtd at lists.infradead.org
> Objet?: Re: [PATCH] mtd: spi-nor: fixed spansion quad enable
> 
> >>> +	/* set SR & CR, enable quad I/O */
> >>>  	write_enable(nor);
> >>>
> >>>  	ret = write_sr_cr(nor, quad_en);
> >>>  	if (ret < 0) {
> >>> -		dev_err(nor->dev,
> >>> -			"error while writing configuration register\n");
> >>> +		dev_err(nor->dev, "error while writing SR and CR
> >> registers\n");
> >>>  		return -EINVAL;
> >>>  	}
> >>>
> >>> -	/* read back and check it */
> >>> +	ret = spi_nor_wait_till_ready(nor);
> >>> +	if (ret)
> >>> +		return ret;
> >>> +
> >
> > I think that this wait is required with every memories that store Quad
> Enable bit in a non-volatile way.
> > I am using today a stripped down kernel with a rootfs based on UBIFS.
> > When this bit is set, UBIFS will start reading the memory 100ms after.
> > As this bit writing step takes up to 200ms, spansion memory is not ready
> and UBIFS will fail when trying to read the content of the partition.
> > As UBIFS has a recovery mechanism, it will even broke the file system.
> >
> 
> I agree with you about adding the spi_nor_wait_till_ready() call. I plan to add
> it in my SFDP patch for the spansion_new_quad_enable(), if not done yet.
> 

Good news !!
Because I think that this part of the patch is the most critical.
Without this, you may broke your filesystem so this is a big issue.

Best regards,

Jo?l



From marex at denx.de  Mon Oct 24 04:41:49 2016
From: marex at denx.de (Marek Vasut)
Date: Mon, 24 Oct 2016 13:41:49 +0200
Subject: [PATCH v2 0/9] mtd: spi-nor: parse SFDP tables to setup (Q)SPI
 memories
In-Reply-To: <CAD6G_RQ2BjtF2cmPUJvYNk7KZZ6eTVAQsEqWs26xn710A4Dz-w@mail.gmail.com>
References: <cover.1475668319.git.cyrille.pitchen@atmel.com>
 <CAD6G_RR4Av8+szo9v2oucCFvwnow86gMVC-Ku_-Qfy18TVMGgA@mail.gmail.com>
 <c022e6fc-6bd7-d124-7233-e1e742049657@denx.de>
 <CAD6G_RQ2BjtF2cmPUJvYNk7KZZ6eTVAQsEqWs26xn710A4Dz-w@mail.gmail.com>
Message-ID: <e9eb9848-522d-2889-457b-d8060f89b352@denx.de>

On 10/24/2016 09:41 AM, Jagan Teki wrote:
> On Sun, Oct 23, 2016 at 2:03 AM, Marek Vasut <marex at denx.de> wrote:
>> On 10/22/2016 01:00 PM, Jagan Teki wrote:
>>> On Wed, Oct 5, 2016 at 5:30 PM, Cyrille Pitchen
>>> <cyrille.pitchen at atmel.com> wrote:
>>>> Hi all,
>>>>
>>>> This series extends support of SPI protocols to new protocols such as
>>>> SPI x-2-2 and SPI x-4-4. Also spi_nor_scan() tries now to select the right
>>>> op codes, timing parameters (number of mode and dummy cycles) and erase
>>>> sector size by parsing the Serial Flash Discoverable Parameter (SFDP)
>>>> tables, when available, as defined in the JEDEC JESD216 specifications.
>>>>
>>>> When SFDP tables are not available, legacy settings are still used for
>>>> backward compatibility (SPI and earlier QSPI memories).
>>>>
>>>> Support of SPI memories >128Mbits is also improved by using the 4byte
>>>> address instruction set, when available. Using those dedicated op codes
>>>> is stateless as opposed to enter the 4byte address mode, hence a better
>>>> compatibility with some boot loaders which expect to use 3byte address
>>>> op codes.
>>>
>>> The memories which are > 128Mbits should have 4-bytes addressing
>>> support based on my experience, do you think BAR is also required
>>> atleast from spi-nor side?
>>
>> Yes, I believe BAR is still required for broken/dumb flash chips.
>> Not all chips > 16 MiB support dedicated 4-byte addressing opcodes :-(
> 
> Do you have list for those broken chips?

No.

> because I never find any
> chips which has > 16 MiB with not support of 4-byte address opcodes
> and I've seen the controller has dependable with BAR though it can
> access > 16MiB ex: zynq qspi/

IIRC some of the 32 MiB micron chips were pretty flaky in that aspect,
they used the same opcodes for 4byte access as for 3byte access and
their behavior was switched by writing some non-volatile bit.

-- 
Best regards,
Marek Vasut


From Danesh.Daroui at ascom.com  Mon Oct 24 04:58:32 2016
From: Danesh.Daroui at ascom.com (Danesh Daroui)
Date: Mon, 24 Oct 2016 11:58:32 +0000
Subject: Failure on MTD sub-page test
In-Reply-To: <39BC08CB3FF4C84CB6397533D4FC7909015DE2F7@SEGOTEXCH02.ascom-Resource.ads>
References: <39BC08CB3FF4C84CB6397533D4FC7909015DDE3F@SEGOTEXCH02.ascom-Resource.ads>
 <1476448883.2342.924.camel@gmail.com>
 <39BC08CB3FF4C84CB6397533D4FC7909015DE2F7@SEGOTEXCH02.ascom-Resource.ads>
Message-ID: <39BC08CB3FF4C84CB6397533D4FC79095770AFB1@SEGOTEXCH02.ascom-Resource.ads>

Hi Artem,

I ran the tests this time without mouting the file system and now all tests except OOB has been passed. The result for OOB test is:

mtd_oobtest: MTD device: 0
mtd_oobtest: MTD device size 1073741824, eraseblock size 524288, page size 4096, count of eraseblocks 2048, pages per eraseblock 128, OOB size 128
mtd_oobtest: scanning for bad eraseblocks
mtd_oobtest: scanned 2048 eraseblocks, 0 are bad
mtd_oobtest: test 1 of 5
mtd_oobtest: erasing whole device
mtd_oobtest: erased 2048 eraseblocks
mtd_oobtest: writing OOBs of whole device
mtd_oobtest: written up to eraseblock 0
mtd_oobtest: written up to eraseblock 256
mtd_oobtest: written up to eraseblock 512
mtd_oobtest: written up to eraseblock 768
mtd_oobtest: written up to eraseblock 1024
mtd_oobtest: written up to eraseblock 1280
mtd_oobtest: written up to eraseblock 1536
mtd_oobtest: written up to eraseblock 1792
mtd_oobtest: written 2048 eraseblocks
mtd_oobtest: verifying all eraseblocks
mtd_oobtest: verified up to eraseblock 0
mtd_oobtest: verified up to eraseblock 256
mtd_oobtest: verified up to eraseblock 512
mtd_oobtest: verified up to eraseblock 768
mtd_oobtest: verified up to eraseblock 1024
mtd_oobtest: verified up to eraseblock 1280
mtd_oobtest: verified up to eraseblock 1536
mtd_oobtest: verified up to eraseblock 1792
mtd_oobtest: verified 2048 eraseblocks
mtd_oobtest: test 2 of 5
mtd_oobtest: erasing whole device
mtd_oobtest: erased 2048 eraseblocks
mtd_oobtest: writing OOBs of whole device
mtd_oobtest: written up to eraseblock 0
mtd_oobtest: written up to eraseblock 256
mtd_oobtest: written up to eraseblock 512
mtd_oobtest: written up to eraseblock 768
mtd_oobtest: written up to eraseblock 1024
mtd_oobtest: written up to eraseblock 1280
mtd_oobtest: written up to eraseblock 1536
mtd_oobtest: written up to eraseblock 1792
mtd_oobtest: written 2048 eraseblocks
mtd_oobtest: verifying all eraseblocks
mtd_oobtest: verified up to eraseblock 0
mtd_oobtest: error: verify failed at 0x5300000
mtd_oobtest: verified up to eraseblock 256
mtd_oobtest: verified up to eraseblock 512
mtd_oobtest: verified up to eraseblock 768
mtd_oobtest: verified up to eraseblock 1024
mtd_oobtest: verified up to eraseblock 1280
mtd_oobtest: verified up to eraseblock 1536
mtd_oobtest: verified up to eraseblock 1792
mtd_oobtest: verified 2048 eraseblocks
mtd_oobtest: test 3 of 5
mtd_oobtest: erasing whole device
mtd_oobtest: erased 2048 eraseblocks
mtd_oobtest: writing OOBs of whole device
mtd_oobtest: written up to eraseblock 0
mtd_oobtest: written up to eraseblock 256
mtd_oobtest: written up to eraseblock 512
mtd_oobtest: written up to eraseblock 768
mtd_oobtest: written up to eraseblock 1024
mtd_oobtest: written up to eraseblock 1280
mtd_oobtest: written up to eraseblock 1536
mtd_oobtest: written up to eraseblock 1792
mtd_oobtest: written 2048 eraseblocks
mtd_oobtest: verifying all eraseblocks
mtd_oobtest: verified up to eraseblock 0
mtd_oobtest: verified up to eraseblock 256
mtd_oobtest: verified up to eraseblock 512
mtd_oobtest: verified up to eraseblock 768
mtd_oobtest: verified up to eraseblock 1024
mtd_oobtest: verified up to eraseblock 1280
mtd_oobtest: verified up to eraseblock 1536
mtd_oobtest: verified up to eraseblock 1792
mtd_oobtest: verified 2048 eraseblocks
mtd_oobtest: test 4 of 5
mtd_oobtest: erasing whole device
mtd_oobtest: erased 2048 eraseblocks
mtd_oobtest: attempting to start write past end of OOB
mtd_oobtest: an error is expected...
mtd_oobtest: error occurred as expected
mtd_oobtest: attempting to start read past end of OOB
mtd_oobtest: an error is expected...
mtd_oobtest: error occurred as expected
mtd_oobtest: attempting to write past end of device
mtd_oobtest: an error is expected...
mtd_oobtest: error occurred as expected
mtd_oobtest: attempting to read past end of device
mtd_oobtest: an error is expected...
mtd_oobtest: error occurred as expected
mtd_oobtest: attempting to write past end of device
mtd_oobtest: an error is expected...
mtd_oobtest: error occurred as expected
mtd_oobtest: attempting to read past end of device
mtd_oobtest: an error is expected...
mtd_oobtest: error occurred as expected
mtd_oobtest: test 5 of 5
mtd_oobtest: erasing whole device
mtd_oobtest: erased 2048 eraseblocks
mtd_oobtest: writing OOBs of whole device
mtd_oobtest: written up to eraseblock 0
mtd_oobtest: written up to eraseblock 0
mtd_oobtest: written up to eraseblock 256
mtd_oobtest: written up to eraseblock 256
mtd_oobtest: written up to eraseblock 512
mtd_oobtest: written up to eraseblock 512
mtd_oobtest: written up to eraseblock 768
mtd_oobtest: written up to eraseblock 768
mtd_oobtest: written up to eraseblock 1024
mtd_oobtest: written up to eraseblock 1024
mtd_oobtest: written up to eraseblock 1280
mtd_oobtest: written up to eraseblock 1280
mtd_oobtest: written up to eraseblock 1536
mtd_oobtest: written up to eraseblock 1536
mtd_oobtest: written up to eraseblock 1792
mtd_oobtest: written up to eraseblock 1792
mtd_oobtest: written 2047 eraseblocks
mtd_oobtest: verifying all eraseblocks
mtd_oobtest: verified up to eraseblock 0
mtd_oobtest: verified up to eraseblock 256
mtd_oobtest: verified up to eraseblock 512
mtd_oobtest: verified up to eraseblock 768
mtd_oobtest: verified up to eraseblock 1024
mtd_oobtest: verified up to eraseblock 1280
mtd_oobtest: verified up to eraseblock 1536
mtd_oobtest: verified up to eraseblock 1792
mtd_oobtest: verified 2047 eraseblocks
mtd_oobtest: finished with 1 errors

The interesting thing is that the file system is forced to switch to read-only mode at startup due to checksum error and some corrupted data that cannot be verified. Now my question is, can failing OOB test explain this failure? I mean, if OOB test fails (like our case) then it is very likely that the device experience data integrity problem at start up since OOB or Out Of Band area contains meta data info for the file system and is the first part that is read and verified during start up so if it fails, it can force the file system into read-only mode to prevent further data corruption. Am I right?

Regards,

Danesh Daroui


-----Original Message-----
From: linux-mtd [mailto:linux-mtd-bounces at lists.infradead.org] On Behalf Of Danesh Daroui
Sent: den 14 oktober 2016 16:14
To: dedekind1 at gmail.com; linux-mtd at lists.infradead.org
Subject: RE: Failure on MTD sub-page test

Hi Artem,

Thanks for your reply. I can unmount the device and run the tests, but then how can we make sure whether the problem is in UBI/UBIFS layers or only MTD layer? Anyway, if we update the kernel, then both MTD drivers and UBI/UBIFS will be updated, am I right?

Regards,

Danesh Daroui

 
-----Original Message-----
From: Artem Bityutskiy [mailto:dedekind1 at gmail.com]
Sent: den 14 oktober 2016 14:41
To: Danesh Daroui <Danesh.Daroui at ascom.com>; linux-mtd at lists.infradead.org
Subject: Re: Failure on MTD sub-page test

On Tue, 2016-10-11 at 11:11 +0000, Danesh Daroui wrote:
> Hello,
> 
> We are using UBIFS which is shipped with the Kernel 2.6.39.4 on a NAND 
> Flash memory. When I run "mtd_debug info /dev/mtd0" following info are
> shown:
> 
> mtd.type = MTD_NANDFLASH
> mtd.flags = MTD_CAP_NANDFLASH
> mtd.size = 1073741824 (1G)
> mtd.erasesize = 524288 (512K)
> mtd.writesize = 4096 (4K)
> mtd.oobsize = 128
> regions = 0
> 
> Now the problem is that when I run mtd tests, only read and NAND ECC 
> tests are passed. Then all other tests fail on exactly page 21. For 
> instance this is the output when I run page test:

If mtd tests do not work, you need to focus on your MTD drivers and fix them.

> =================================================
> mtd_subpagetest: MTD device: 0
> mtd_subpagetest: MTD device size 1073741824, eraseblock size 524288, 
> page size 4096, subpage size 1024, count of eraseblocks 2048, pages
... snip ...
> mtd_subpagetest: verified up to eraseblock 1280
> mtd_subpagetest: verified up to eraseblock 1536
> mtd_subpagetest: verified up to eraseblock 1792 UBIFS error (pid
> 4243): ubifs_read_node: bad node type (255 but expected 1) UBIFS error 
> (pid 4243): ubifs_read_node: bad node at LEB 30:98088, LEB mapping 
> status 1 UBIFS error (pid 4243): do_readpage: cannot read page 21 of 
> inode 791, error -22

This is a bit confusing - why messages go together. Do you run mtd tests and also have the same mtd device mounted at the same time?

The tests hammer the MTD device directly, they do not go through UBI/UBIFS. So make sure UBI/UBIFS are not using the MTD device that you are testing.

Artem.

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/


From cyrille.pitchen at atmel.com  Mon Oct 24 05:09:15 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Mon, 24 Oct 2016 14:09:15 +0200
Subject: [PATCH v2 0/9] mtd: spi-nor: parse SFDP tables to setup (Q)SPI
 memories
In-Reply-To: <CAD6G_RQ2BjtF2cmPUJvYNk7KZZ6eTVAQsEqWs26xn710A4Dz-w@mail.gmail.com>
References: <cover.1475668319.git.cyrille.pitchen@atmel.com>
 <CAD6G_RR4Av8+szo9v2oucCFvwnow86gMVC-Ku_-Qfy18TVMGgA@mail.gmail.com>
 <c022e6fc-6bd7-d124-7233-e1e742049657@denx.de>
 <CAD6G_RQ2BjtF2cmPUJvYNk7KZZ6eTVAQsEqWs26xn710A4Dz-w@mail.gmail.com>
Message-ID: <558d668a-69b0-8066-b7da-090517d3161d@atmel.com>

Hi Jagan,

Le 24/10/2016 ? 09:41, Jagan Teki a ?crit :
> On Sun, Oct 23, 2016 at 2:03 AM, Marek Vasut <marex at denx.de> wrote:
>> On 10/22/2016 01:00 PM, Jagan Teki wrote:
>>> On Wed, Oct 5, 2016 at 5:30 PM, Cyrille Pitchen
>>> <cyrille.pitchen at atmel.com> wrote:
>>>> Hi all,
>>>>
>>>> This series extends support of SPI protocols to new protocols such as
>>>> SPI x-2-2 and SPI x-4-4. Also spi_nor_scan() tries now to select the right
>>>> op codes, timing parameters (number of mode and dummy cycles) and erase
>>>> sector size by parsing the Serial Flash Discoverable Parameter (SFDP)
>>>> tables, when available, as defined in the JEDEC JESD216 specifications.
>>>>
>>>> When SFDP tables are not available, legacy settings are still used for
>>>> backward compatibility (SPI and earlier QSPI memories).
>>>>
>>>> Support of SPI memories >128Mbits is also improved by using the 4byte
>>>> address instruction set, when available. Using those dedicated op codes
>>>> is stateless as opposed to enter the 4byte address mode, hence a better
>>>> compatibility with some boot loaders which expect to use 3byte address
>>>> op codes.
>>>
>>> The memories which are > 128Mbits should have 4-bytes addressing
>>> support based on my experience, do you think BAR is also required
>>> atleast from spi-nor side?
>>
>> Yes, I believe BAR is still required for broken/dumb flash chips.
>> Not all chips > 16 MiB support dedicated 4-byte addressing opcodes :-(
> 
> Do you have list for those broken chips? because I never find any
> chips which has > 16 MiB with not support of 4-byte address opcodes
> and I've seen the controller has dependable with BAR though it can
> access > 16MiB ex: zynq qspi/
> 
> thanks!
> 

Let's take the case of Micron n25q256* memories. Depending of the part number,
the 12h op code is associated with either 4-byte address Page Program 1-1-1
or 3-byte address Page Program 1-4-4.
Then considering parts where the 12h op code is used for 3-byte address Page
Program 1-4-4, there is no op code for a 4-byte address Page Program 1-1-1.

Note 15, extracted from the Micron n25q_256mb_3v_65nm.pdf datasheet, about
the 3-byte address Page Program 1-4-4 (Extended Quad Input Fast Program):
The code 38h is valid only for part numbers N25Q256A83ESF40x, N25Q256A83E1240x
and N25Q256A83ESFA0F; the code 12h is valid for the other part numbers.

Hence most of the Micron n25q256* memories has no op code for 4-byte address
Page Program 1-1-1.
Then we could use the 34h op code instead to perform 4-byte address Page
Program 1-1-4 but some SPI controllers might not support the SPI 1-1-4 protocol
for Page Program operations. Sp entering the 4-byte address mode or using
the BAR might still be the only solutions in those cases.

Also, I'm pretty sure some other SPI NOR memories support 4-byte address Fast
Read op codes but only 3-byte address op codes for Page Program and Sector
Erase. I will look at the datasheets I have to find and provide an example.


Best regards,

Cyrille


From boris.brezillon at free-electrons.com  Mon Oct 24 05:27:14 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Mon, 24 Oct 2016 14:27:14 +0200
Subject: [v7, 1/3] nand: pl353: Add basic driver for arm pl353 smc nand
 interface
In-Reply-To: <CAGnW=Bb-pnJ9-xjcw-1dR-y+oKjNs53bgD+dh1LwsMTCmzdRmQ@mail.gmail.com>
References: <1433786918-21500-2-git-send-email-punnaia@xilinx.com>
 <20161021203322.GA28655@obsidianresearch.com>
 <20161021234611.1f737144@bbrezillon>
 <CAGnW=Bb-pnJ9-xjcw-1dR-y+oKjNs53bgD+dh1LwsMTCmzdRmQ@mail.gmail.com>
Message-ID: <20161024142714.10902cf2@bbrezillon>

Hi Punnaih,

On Sun, 23 Oct 2016 17:37:42 +0530
punnaiah choudary kalluri <punnaia at xilinx.com> wrote:

> Hi Boris and Jason,
> 
>  I am doing rework on these patches to accommodate recent changes with
>  respect to ooblayout. Also some of the comments that i have received
> from Boris as part of the arasan nand controller upstream patches will
> apply to this driver. So, i will be releasing the next set of patches for this
> driver soon and request your time for reviewing those patches.
> 
> for now, please ignore these patches.

OK. Thanks for the heads up. I'll wait for your new version.

Regards,

Boris


From boris.brezillon at free-electrons.com  Mon Oct 24 05:31:12 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Mon, 24 Oct 2016 14:31:12 +0200
Subject: [PATCH] mtd: nand: gpmi: disable the clocks on errors
In-Reply-To: <1477152922-6722-1-git-send-email-festevam@gmail.com>
References: <1477152922-6722-1-git-send-email-festevam@gmail.com>
Message-ID: <20161024143112.66bb705a@bbrezillon>

On Sat, 22 Oct 2016 14:15:22 -0200
Fabio Estevam <festevam at gmail.com> wrote:

> From: Fabio Estevam <fabio.estevam at nxp.com>
> 
> We should disable the previously enabled GPMI clocks in the error paths.
> 
> Also, when gpmi_enable_clk() fails simply return the error
> code immediately rather than jumping to to the 'err_out' label.
> 
> Signed-off-by: Fabio Estevam <fabio.estevam at nxp.com>

Acked-by: Boris Brezillon <boris.brezillon at free-electrons.com>

Brian, can you take this patch in the MTD tree and queue it for the
next -rc?

> ---
>  drivers/mtd/nand/gpmi-nand/gpmi-lib.c | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
> index 0f68a99..141bd70 100644
> --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
> +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
> @@ -161,7 +161,7 @@ int gpmi_init(struct gpmi_nand_data *this)
>  
>  	ret = gpmi_enable_clk(this);
>  	if (ret)
> -		goto err_out;
> +		return ret;
>  	ret = gpmi_reset_block(r->gpmi_regs, false);
>  	if (ret)
>  		goto err_out;
> @@ -197,6 +197,7 @@ int gpmi_init(struct gpmi_nand_data *this)
>  	gpmi_disable_clk(this);
>  	return 0;
>  err_out:
> +	gpmi_disable_clk(this);
>  	return ret;
>  }
>  
> @@ -270,7 +271,7 @@ int bch_set_geometry(struct gpmi_nand_data *this)
>  
>  	ret = gpmi_enable_clk(this);
>  	if (ret)
> -		goto err_out;
> +		return ret;
>  
>  	/*
>  	* Due to erratum #2847 of the MX23, the BCH cannot be soft reset on this
> @@ -308,6 +309,7 @@ int bch_set_geometry(struct gpmi_nand_data *this)
>  	gpmi_disable_clk(this);
>  	return 0;
>  err_out:
> +	gpmi_disable_clk(this);
>  	return ret;
>  }
>  



From boris.brezillon at free-electrons.com  Mon Oct 24 05:35:26 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Mon, 24 Oct 2016 14:35:26 +0200
Subject: [PATCH] MAINTAINERS: add more people to the MTD maintainer team
Message-ID: <1477312526-7563-1-git-send-email-boris.brezillon@free-electrons.com>

Brian has been maintaining the MTD subsystem alone for several years
now, and maintaining such a subsystem can really be time consuming.

Create a maintainer team formed of the most active MTD contributors
to help Brian with this task, which will hopefully improve the
subsystem reactivity.

Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
Hi all,

I'm just trying to summarize what I understood the process would be,
don't hesitate to correct me if I'm wrong.

For each release we will assign a specific MTD maintainer which will be
responsible for taking MTD core patches and pulling spi-nor and nand PRs
into the MTD tree and eventually send one or several PRs to Linus.

For fixes that are submitted after -rc1, I usually ask Brian to apply
them directly into the MTD tree (I don't think there's a real need to
prepare spi-nor and nand PRs for fixes), so we can proceed the same
way: ask the maintainer assigned to this release to also take care of
applying fixes and sending PRs to Linus before each -rc.

If you have other ideas, or would like to proceed differently, don't
hesitate propose them.

Thanks,

Boris
---
 MAINTAINERS | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 1cd38a7e0064..cbf9583fdbe7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7912,6 +7912,10 @@ F:	mm/
 MEMORY TECHNOLOGY DEVICES (MTD)
 M:	David Woodhouse <dwmw2 at infradead.org>
 M:	Brian Norris <computersforpeace at gmail.com>
+M:	Boris Brezillon <boris.brezillon at free-electrons.com>
+M:	Marek Vasut <marek.vasut at gmail.com>
+M:	Richard Weinberger <richard at nod.at>
+M:	Cyrille Pitchen <cyrille.pitchen at atmel.com>
 L:	linux-mtd at lists.infradead.org
 W:	http://www.linux-mtd.infradead.org/
 Q:	http://patchwork.ozlabs.org/project/linux-mtd/list/
-- 
2.7.4



From marc_gonzalez at sigmadesigns.com  Mon Oct 24 05:48:24 2016
From: marc_gonzalez at sigmadesigns.com (Marc Gonzalez)
Date: Mon, 24 Oct 2016 14:48:24 +0200
Subject: [PATCH v6 0/4] Tango NAND Flash controller driver (and dependencies)
Message-ID: <580E0318.5020004@sigmadesigns.com>

This patch series imports a driver for the Tango NAND Flash controller
and a few dependent patches, included for easy reference.

Boris Brezillon (2):
  mtd: nand: Add a few more timings to nand_sdr_timings
  mtd: nand: Wait tCCS after a column change

Marc Gonzalez (2):
  mtd: nand: Actually apply the optimal timings
  mtd: nand: tango: import driver for tango chips

 drivers/mtd/nand/Kconfig        |   6 +
 drivers/mtd/nand/Makefile       |   1 +
 drivers/mtd/nand/nand_base.c    |  28 +-
 drivers/mtd/nand/nand_timings.c |  26 +-
 drivers/mtd/nand/tango_nand.c   | 654 ++++++++++++++++++++++++++++++++++++++++
 include/linux/mtd/nand.h        |  18 ++
 6 files changed, 730 insertions(+), 3 deletions(-)
 create mode 100644 drivers/mtd/nand/tango_nand.c


From marc_gonzalez at sigmadesigns.com  Mon Oct 24 05:50:16 2016
From: marc_gonzalez at sigmadesigns.com (Marc Gonzalez)
Date: Mon, 24 Oct 2016 14:50:16 +0200
Subject: [PATCH v6 1/4] mtd: nand: Add a few more timings to nand_sdr_timings
In-Reply-To: <580E0318.5020004@sigmadesigns.com>
References: <580E0318.5020004@sigmadesigns.com>
Message-ID: <580E0388.8010107@sigmadesigns.com>

From: Boris Brezillon <boris.brezillon at free-electrons.com>

Add the tR_max, tBERS_max, tPROG_max and tCCS_min timings to the
nand_sdr_timings struct.
Assign default/safe values for the statically defined timings, and
extract them from the ONFI parameter table if the NAND is ONFI
compliant.

Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/nand_timings.c | 26 +++++++++++++++++++++++++-
 include/linux/mtd/nand.h        |  8 ++++++++
 2 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/nand_timings.c
index 13a587407be3..f06312df3669 100644
--- a/drivers/mtd/nand/nand_timings.c
+++ b/drivers/mtd/nand/nand_timings.c
@@ -18,6 +18,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
 	{
 		.type = NAND_SDR_IFACE,
 		.timings.sdr = {
+			.tCCS_min = 500000,
+			.tR_max = 200000000,
 			.tADL_min = 400000,
 			.tALH_min = 20000,
 			.tALS_min = 50000,
@@ -58,6 +60,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
 	{
 		.type = NAND_SDR_IFACE,
 		.timings.sdr = {
+			.tCCS_min = 500000,
+			.tR_max = 200000000,
 			.tADL_min = 400000,
 			.tALH_min = 10000,
 			.tALS_min = 25000,
@@ -98,6 +102,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
 	{
 		.type = NAND_SDR_IFACE,
 		.timings.sdr = {
+			.tCCS_min = 500000,
+			.tR_max = 200000000,
 			.tADL_min = 400000,
 			.tALH_min = 10000,
 			.tALS_min = 15000,
@@ -138,6 +144,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
 	{
 		.type = NAND_SDR_IFACE,
 		.timings.sdr = {
+			.tCCS_min = 500000,
+			.tR_max = 200000000,
 			.tADL_min = 400000,
 			.tALH_min = 5000,
 			.tALS_min = 10000,
@@ -178,6 +186,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
 	{
 		.type = NAND_SDR_IFACE,
 		.timings.sdr = {
+			.tCCS_min = 500000,
+			.tR_max = 200000000,
 			.tADL_min = 400000,
 			.tALH_min = 5000,
 			.tALS_min = 10000,
@@ -218,6 +228,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
 	{
 		.type = NAND_SDR_IFACE,
 		.timings.sdr = {
+			.tCCS_min = 500000,
+			.tR_max = 200000000,
 			.tADL_min = 400000,
 			.tALH_min = 5000,
 			.tALS_min = 10000,
@@ -290,10 +302,22 @@ int onfi_init_data_interface(struct nand_chip *chip,
 	*iface = onfi_sdr_timings[timing_mode];
 
 	/*
-	 * TODO: initialize timings that cannot be deduced from timing mode:
+	 * Initialize timings that cannot be deduced from timing mode:
 	 * tR, tPROG, tCCS, ...
 	 * These information are part of the ONFI parameter page.
 	 */
+	if (chip->onfi_version) {
+		struct nand_onfi_params *params = &chip->onfi_params;
+		struct nand_sdr_timings *timings = &iface->timings.sdr;
+
+		/* microseconds -> picoseconds */
+		timings->tPROG_max = 1000000UL * le16_to_cpu(params->t_prog);
+		timings->tBERS_max = 1000000UL * le16_to_cpu(params->t_bers);
+		timings->tR_max = 1000000UL * le16_to_cpu(params->t_r);
+
+		/* nanoseconds -> picoseconds */
+		timings->tCCS_min = 1000UL * le16_to_cpu(params->t_ccs);
+	}
 
 	return 0;
 }
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index c5d3d5024fc8..6fe83bce83a6 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -584,6 +584,10 @@ struct nand_buffers {
  *
  * All these timings are expressed in picoseconds.
  *
+ * @tBERS_max: Block erase time
+ * @tCCS_min: Change column setup time
+ * @tPROG_max: Page program time
+ * @tR_max: Page read time
  * @tALH_min: ALE hold time
  * @tADL_min: ALE to data loading time
  * @tALS_min: ALE setup time
@@ -621,6 +625,10 @@ struct nand_buffers {
  * @tWW_min: WP# transition to WE# low
  */
 struct nand_sdr_timings {
+	u32 tBERS_max;
+	u32 tCCS_min;
+	u32 tPROG_max;
+	u32 tR_max;
 	u32 tALH_min;
 	u32 tADL_min;
 	u32 tALS_min;
-- 
2.9.0


From marc_gonzalez at sigmadesigns.com  Mon Oct 24 05:51:32 2016
From: marc_gonzalez at sigmadesigns.com (Marc Gonzalez)
Date: Mon, 24 Oct 2016 14:51:32 +0200
Subject: [PATCH v6 2/4] mtd: nand: Wait tCCS after a column change
In-Reply-To: <580E0318.5020004@sigmadesigns.com>
References: <580E0318.5020004@sigmadesigns.com>
Message-ID: <580E03D4.3090608@sigmadesigns.com>

From: Boris Brezillon <boris.brezillon at free-electrons.com>

Drivers implementing ->cmd_ctrl() and relying on the default ->cmdfunc()
implementation usually don't wait tCCS when a column change (RNDIN or
RNDOUT) is requested.
Add an option flag to ask the core to do so (note that we keep this as
an opt-in to avoid breaking existing implementations), and make use of
the ->data_interface information is available (otherwise, wait 500ns).

Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/nand_base.c | 26 +++++++++++++++++++++++++-
 include/linux/mtd/nand.h     | 10 ++++++++++
 2 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index e5718e5ecf92..0acb0070280a 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -709,6 +709,25 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
 	nand_wait_ready(mtd);
 }
 
+static void nand_ccs_delay(struct nand_chip *chip)
+{
+	/*
+	 * The controller already takes care of waiting for tCCS when the RNDIN
+	 * or RNDOUT command is sent, return directly.
+	 */
+	if (!(chip->options & NAND_WAIT_TCCS))
+		return;
+
+	/*
+	 * Wait tCCS_min if it is correctly defined, otherwise wait 500ns
+	 * (which should be safe for all NANDs).
+	 */
+	if (chip->data_interface && chip->data_interface->timings.sdr.tCCS_min)
+		ndelay(chip->data_interface->timings.sdr.tCCS_min / 1000);
+	else
+		ndelay(500);
+}
+
 /**
  * nand_command_lp - [DEFAULT] Send command to NAND large page device
  * @mtd: MTD device structure
@@ -773,10 +792,13 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
 	case NAND_CMD_ERASE1:
 	case NAND_CMD_ERASE2:
 	case NAND_CMD_SEQIN:
-	case NAND_CMD_RNDIN:
 	case NAND_CMD_STATUS:
 		return;
 
+	case NAND_CMD_RNDIN:
+		nand_ccs_delay(chip);
+		return;
+
 	case NAND_CMD_RESET:
 		if (chip->dev_ready)
 			break;
@@ -795,6 +817,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
 			       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
 		chip->cmd_ctrl(mtd, NAND_CMD_NONE,
 			       NAND_NCE | NAND_CTRL_CHANGE);
+
+		nand_ccs_delay(chip);
 		return;
 
 	case NAND_CMD_READ0:
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 6fe83bce83a6..970ceb948835 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -210,6 +210,16 @@ enum nand_ecc_algo {
  */
 #define NAND_USE_BOUNCE_BUFFER	0x00100000
 
+/*
+ * In case your controller is implementing ->cmd_ctrl() and is relying on the
+ * default ->cmdfunc() implementation, you may want to let the core handle the
+ * tCCS delay which is required when a column change (RNDIN or RNDOUT) is
+ * requested.
+ * If your controller already takes care of this delay, you don't need to set
+ * this flag.
+ */
+#define NAND_WAIT_TCCS		0x00200000
+
 /* Options set by nand scan */
 /* Nand scan has allocated controller struct */
 #define NAND_CONTROLLER_ALLOC	0x80000000
-- 
2.9.0


From marc_gonzalez at sigmadesigns.com  Mon Oct 24 05:54:47 2016
From: marc_gonzalez at sigmadesigns.com (Marc Gonzalez)
Date: Mon, 24 Oct 2016 14:54:47 +0200
Subject: [PATCH v6 3/4] mtd: nand: Actually apply the optimal timings
In-Reply-To: <580E0318.5020004@sigmadesigns.com>
References: <580E0318.5020004@sigmadesigns.com>
Message-ID: <580E0497.607@sigmadesigns.com>

Signed-off-by: Marc Gonzalez <marc_gonzalez at sigmadesigns.com>
---
 drivers/mtd/nand/nand_base.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 0acb0070280a..b311ebc4bebc 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1108,7 +1108,7 @@ static int nand_init_data_interface(struct nand_chip *chip)
 		}
 	}
 
-	return 0;
+	return nand_setup_data_interface(chip);
 }
 
 static void nand_release_data_interface(struct nand_chip *chip)
-- 
2.9.0


From marc_gonzalez at sigmadesigns.com  Mon Oct 24 05:55:16 2016
From: marc_gonzalez at sigmadesigns.com (Marc Gonzalez)
Date: Mon, 24 Oct 2016 14:55:16 +0200
Subject: [PATCH v6 4/4] mtd: nand: tango: import driver for tango chips
In-Reply-To: <580E0318.5020004@sigmadesigns.com>
References: <580E0318.5020004@sigmadesigns.com>
Message-ID: <580E04B4.7040102@sigmadesigns.com>

This driver supports the NAND Flash controller embedded in recent
Tango chips, such as SMP8758 and SMP8759.

Signed-off-by: Marc Gonzalez <marc_gonzalez at sigmadesigns.com>
---
 drivers/mtd/nand/Kconfig      |   6 +
 drivers/mtd/nand/Makefile     |   1 +
 drivers/mtd/nand/tango_nand.c | 654 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 661 insertions(+)
 create mode 100644 drivers/mtd/nand/tango_nand.c

diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 7b7a887b4709..844ab20a23a4 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -205,6 +205,12 @@ config MTD_NAND_S3C2410_CLKSTOP
 	  when the is NAND chip selected or released, but will save
 	  approximately 5mA of power when there is nothing happening.
 
+config MTD_NAND_TANGO
+	tristate "NAND Flash support for Tango chips"
+	depends on ARCH_TANGO
+	help
+	  Enables the NAND Flash controller on Tango chips.
+
 config MTD_NAND_DISKONCHIP
 	tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation)"
 	depends on HAS_IOMEM
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index cafde6f3d957..4904ad3614fb 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_MTD_NAND_DENALI_DT)	+= denali_dt.o
 obj-$(CONFIG_MTD_NAND_AU1550)		+= au1550nd.o
 obj-$(CONFIG_MTD_NAND_BF5XX)		+= bf5xx_nand.o
 obj-$(CONFIG_MTD_NAND_S3C2410)		+= s3c2410.o
+obj-$(CONFIG_MTD_NAND_TANGO)		+= tango_nand.o
 obj-$(CONFIG_MTD_NAND_DAVINCI)		+= davinci_nand.o
 obj-$(CONFIG_MTD_NAND_DISKONCHIP)	+= diskonchip.o
 obj-$(CONFIG_MTD_NAND_DOCG4)		+= docg4.o
diff --git a/drivers/mtd/nand/tango_nand.c b/drivers/mtd/nand/tango_nand.c
new file mode 100644
index 000000000000..375ca8e4a3aa
--- /dev/null
+++ b/drivers/mtd/nand/tango_nand.c
@@ -0,0 +1,654 @@
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/mtd/nand.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+
+/* Offsets relative to chip->base */
+#define PBUS_CMD	0
+#define PBUS_ADDR	4
+#define PBUS_DATA	8
+
+/* Offsets relative to reg_base */
+#define NFC_STATUS	0x00
+#define NFC_FLASH_CMD	0x04
+#define NFC_DEVICE_CFG	0x08
+#define NFC_TIMING1	0x0c
+#define NFC_TIMING2	0x10
+#define NFC_XFER_CFG	0x14
+#define NFC_PKT_0_CFG	0x18
+#define NFC_PKT_N_CFG	0x1c
+#define NFC_BB_CFG	0x20
+#define NFC_ADDR_PAGE	0x24
+#define NFC_ADDR_OFFSET	0x28
+#define NFC_XFER_STATUS	0x2c
+
+/* NFC_STATUS values */
+#define CMD_READY	BIT(31)
+
+/* NFC_FLASH_CMD values */
+#define NFC_READ	1
+#define NFC_WRITE	2
+
+/* NFC_XFER_STATUS values */
+#define PAGE_IS_EMPTY	BIT(16)
+
+/* Offsets relative to mem_base */
+#define METADATA	0x000
+#define ERROR_REPORT	0x1c0
+
+/*
+ * Error reports are split in two bytes:
+ * byte 0 for the first packet in the page (PKT_0)
+ * byte 1 for other packets in the page (PKT_N, for N > 0)
+ * ERR_COUNT_PKT_N is the max error count over all but the first packet.
+ */
+#define DECODE_OK_PKT_0(v)	(v & BIT(7))
+#define DECODE_OK_PKT_N(v)	(v & BIT(15))
+#define ERR_COUNT_PKT_0(v)	((v >> 0) & 0x3f)
+#define ERR_COUNT_PKT_N(v)	((v >> 8) & 0x3f)
+
+/* Offsets relative to pbus_base */
+#define PBUS_CS_CTRL	0x83c
+#define PBUS_PAD_MODE	0x8f0
+
+/* PBUS_CS_CTRL values */
+#define PBUS_IORDY	BIT(31)
+
+/*
+ * PBUS_PAD_MODE values
+ * In raw mode, the driver communicates directly with the NAND chips.
+ * In NFC mode, the NAND Flash controller manages the communication.
+ * We use NFC mode for read and write; raw mode for everything else.
+ */
+#define MODE_RAW	0
+#define MODE_NFC	BIT(31)
+
+#define METADATA_SIZE	4
+#define BBM_SIZE	6
+#define FIELD_ORDER	15
+
+#define MAX_CS		4
+
+struct tango_nfc {
+	struct nand_hw_control hw;
+	void __iomem *reg_base;
+	void __iomem *mem_base;
+	void __iomem *pbus_base;
+	struct tango_chip *chips[MAX_CS];
+	struct dma_chan *chan;
+	int freq_kHz;
+};
+
+#define to_tango_nfc(ptr) container_of(ptr, struct tango_nfc, hw)
+
+struct tango_chip {
+	struct nand_chip nand_chip;
+	void __iomem *base;
+	u32 timing1;
+	u32 timing2;
+	u32 xfer_cfg;
+	u32 pkt_0_cfg;
+	u32 pkt_n_cfg;
+	u32 bb_cfg;
+};
+
+#define to_tango_chip(ptr) container_of(ptr, struct tango_chip, nand_chip)
+
+#define XFER_CFG(cs, page_count, steps, metadata_size)	\
+	((cs) << 24 | (page_count) << 16 | (steps) << 8 | (metadata_size) << 0)
+
+#define PKT_CFG(size, strength) ((size) << 16 | (strength) << 0)
+
+#define BB_CFG(bb_offset, bb_size) ((bb_offset) << 16 | (bb_size) << 0)
+
+#define TIMING(t0, t1, t2, t3) (t0 << 24 | t1 << 16 | t2 << 8 | t3 << 0)
+
+static void tango_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+{
+	struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+
+	if (ctrl & NAND_CLE)
+		writeb_relaxed(dat, tchip->base + PBUS_CMD);
+
+	if (ctrl & NAND_ALE)
+		writeb_relaxed(dat, tchip->base + PBUS_ADDR);
+}
+
+static int tango_dev_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+
+	return readl_relaxed(nfc->pbus_base + PBUS_CS_CTRL) & PBUS_IORDY;
+}
+
+static uint8_t tango_read_byte(struct mtd_info *mtd)
+{
+	struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+
+	return readb_relaxed(tchip->base + PBUS_DATA);
+}
+
+static void tango_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+
+	ioread8_rep(tchip->base + PBUS_DATA, buf, len);
+}
+
+static void tango_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+	struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+
+	iowrite8_rep(tchip->base + PBUS_DATA, buf, len);
+}
+
+static void tango_select_chip(struct mtd_info *mtd, int idx)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+	struct tango_chip *tchip = to_tango_chip(chip);
+
+	if (idx < 0)
+		return; /* No "chip unselect" function */
+
+	writel_relaxed(tchip->timing1, nfc->reg_base + NFC_TIMING1);
+	writel_relaxed(tchip->timing2, nfc->reg_base + NFC_TIMING2);
+	writel_relaxed(tchip->xfer_cfg, nfc->reg_base + NFC_XFER_CFG);
+	writel_relaxed(tchip->pkt_0_cfg, nfc->reg_base + NFC_PKT_0_CFG);
+	writel_relaxed(tchip->pkt_n_cfg, nfc->reg_base + NFC_PKT_N_CFG);
+	writel_relaxed(tchip->bb_cfg, nfc->reg_base + NFC_BB_CFG);
+}
+
+/*
+ * The controller does not check for bitflips in erased pages,
+ * therefore software must check instead.
+ */
+static int check_erased_page(struct nand_chip *chip, u8 *buf)
+{
+	u8 *meta = chip->oob_poi + BBM_SIZE;
+	u8 *ecc = chip->oob_poi + BBM_SIZE + METADATA_SIZE;
+	const int ecc_size = chip->ecc.bytes;
+	const int pkt_size = chip->ecc.size;
+	int i, res, meta_len, bitflips = 0;
+
+	for (i = 0; i < chip->ecc.steps; ++i)
+	{
+		meta_len = i ? 0 : METADATA_SIZE;
+		res = nand_check_erased_ecc_chunk(buf, pkt_size, ecc, ecc_size,
+				meta, meta_len, chip->ecc.strength);
+		if (res < 0)
+			return res;
+
+		bitflips = max(res, bitflips);
+		buf += pkt_size;
+		ecc += ecc_size;
+	}
+
+	return bitflips;
+}
+
+static int decode_error_report(struct tango_nfc *nfc)
+{
+	u32 status, res;
+
+	status = readl_relaxed(nfc->reg_base + NFC_XFER_STATUS);
+	if (status & PAGE_IS_EMPTY)
+		return 0;
+
+	res = readl_relaxed(nfc->mem_base + ERROR_REPORT);
+
+	if (DECODE_OK_PKT_0(res) && DECODE_OK_PKT_N(res))
+		return max(ERR_COUNT_PKT_0(res), ERR_COUNT_PKT_N(res));
+
+	return -EBADMSG;
+}
+
+static void tango_dma_callback(void *arg)
+{
+	complete(arg);
+}
+
+static int do_dma(struct tango_nfc *nfc, int dir, int cmd,
+		const void *buf, int len, int page)
+{
+	struct dma_chan *chan = nfc->chan;
+	struct dma_async_tx_descriptor *desc;
+	struct scatterlist sg;
+	struct completion tx_done;
+	int err = -EIO;
+	u32 res, val;
+
+	sg_init_one(&sg, buf, len);
+	if (dma_map_sg(chan->device->dev, &sg, 1, dir) != 1)
+		return -EIO;
+
+	desc = dmaengine_prep_slave_sg(chan, &sg, 1, dir, DMA_PREP_INTERRUPT);
+	if (!desc)
+		goto dma_unmap;
+
+	desc->callback = tango_dma_callback;
+	desc->callback_param = &tx_done;
+	init_completion(&tx_done);
+
+	writel_relaxed(MODE_NFC, nfc->pbus_base + PBUS_PAD_MODE);
+
+	writel_relaxed(page, nfc->reg_base + NFC_ADDR_PAGE);
+	writel_relaxed(   0, nfc->reg_base + NFC_ADDR_OFFSET);
+	writel_relaxed( cmd, nfc->reg_base + NFC_FLASH_CMD);
+
+	dmaengine_submit(desc);
+	dma_async_issue_pending(chan);
+
+	res = wait_for_completion_timeout(&tx_done, HZ);
+	if (res > 0) {
+		void __iomem *addr = nfc->reg_base + NFC_STATUS;
+		err = readl_poll_timeout(addr, val, val & CMD_READY, 0, 1000);
+	}
+
+	writel_relaxed(MODE_RAW, nfc->pbus_base + PBUS_PAD_MODE);
+
+dma_unmap:
+	dma_unmap_sg(chan->device->dev, &sg, 1, dir);
+
+	return err;
+}
+
+static int tango_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+		uint8_t *buf, int oob_required, int page)
+{
+	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+	int err, res, len = mtd->writesize;
+
+	if (oob_required)
+		chip->ecc.read_oob(mtd, chip, page);
+
+	err = do_dma(nfc, DMA_FROM_DEVICE, NFC_READ, buf, len, page);
+	if (err)
+		return err;
+
+	res = decode_error_report(nfc);
+	if (res < 0) {
+		chip->ecc.read_oob_raw(mtd, chip, page);
+		res = check_erased_page(chip, buf);
+	}
+
+	return res;
+}
+
+static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+		const uint8_t *buf, int oob_required, int page)
+{
+	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+	int err, len = mtd->writesize;
+
+	writel_relaxed(0xffffffff, nfc->mem_base + METADATA);
+	err = do_dma(nfc, DMA_TO_DEVICE, NFC_WRITE, buf, len, page);
+	if (err)
+		return err;
+
+	if (oob_required)
+		return -ENOTSUPP; /* Sending PAGEPROG twice is forbidden */
+
+	return 0;
+}
+
+static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos)
+{
+	*pos += len;
+
+	if (*buf == NULL) /* skip over len bytes */
+		chip->cmdfunc(&chip->mtd, NAND_CMD_RNDOUT, *pos, -1);
+	else {
+		tango_read_buf(&chip->mtd, *buf, len);
+		*buf += len;
+	}
+}
+
+static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos)
+{
+	*pos += len;
+
+	if (*buf == NULL) /* skip over len bytes */
+		chip->cmdfunc(&chip->mtd, NAND_CMD_SEQIN, *pos, -1);
+	else {
+		tango_write_buf(&chip->mtd, *buf, len);
+		*buf += len;
+	}
+}
+
+/*
+ * Physical page layout (not drawn to scale)
+ *
+ * NB: Bad Block Marker area splits PKT_N in two (N1, N2).
+ *
+ * +---+-----------------+-------+-----+-----------+-----+----+-------+
+ * | M |      PKT_0      | ECC_0 | ... |     N1    | BBM | N2 | ECC_N |
+ * +---+-----------------+-------+-----+-----------+-----+----+-------+
+ *
+ * Logical page layout:
+ *
+ *       +-----+---+-------+-----+-------+
+ * oob = | BBM | M | ECC_0 | ... | ECC_N |
+ *       +-----+---+-------+-----+-------+
+ *
+ *       +-----------------+-----+-----------------+
+ * buf = |      PKT_0      | ... |      PKT_N      |
+ *       +-----------------+-----+-----------------+
+ */
+static int raw_read(struct nand_chip *chip, u8 *buf, u8 *oob)
+{
+	u8 *oob_orig = oob;
+	const int page_size = chip->mtd.writesize;
+	const int ecc_size = chip->ecc.bytes;
+	const int pkt_size = chip->ecc.size;
+	int pos = 0; /* position within physical page */
+	int rem = page_size; /* bytes remaining until BBM area */
+
+	if (oob != NULL)
+		oob += BBM_SIZE;
+
+	aux_read(chip, &oob, METADATA_SIZE, &pos);
+
+	while (rem > pkt_size) {
+		aux_read(chip, &buf, pkt_size, &pos);
+		aux_read(chip, &oob, ecc_size, &pos);
+		rem = page_size - pos;
+	}
+
+	aux_read(chip, &buf, rem, &pos);
+	aux_read(chip, &oob_orig, BBM_SIZE, &pos);
+	aux_read(chip, &buf, pkt_size - rem, &pos);
+	aux_read(chip, &oob, ecc_size, &pos);
+
+	return 0;
+}
+
+static int raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob)
+{
+	const u8 *oob_orig = oob;
+	const int page_size = chip->mtd.writesize;
+	const int ecc_size = chip->ecc.bytes;
+	const int pkt_size = chip->ecc.size;
+	int pos = 0; /* position within physical page */
+	int rem = page_size; /* bytes remaining until BBM area */
+
+	if (oob != NULL)
+		oob += BBM_SIZE;
+
+	aux_write(chip, &oob, METADATA_SIZE, &pos);
+
+	while (rem > pkt_size) {
+		aux_write(chip, &buf, pkt_size, &pos);
+		aux_write(chip, &oob, ecc_size, &pos);
+		rem = page_size - pos;
+	}
+
+	aux_write(chip, &buf, rem, &pos);
+	aux_write(chip, &oob_orig, BBM_SIZE, &pos);
+	aux_write(chip, &buf, pkt_size - rem, &pos);
+	aux_write(chip, &oob, ecc_size, &pos);
+
+	return 0;
+}
+
+static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+		uint8_t *buf, int oob_required, int page)
+{
+	return raw_read(chip, buf, chip->oob_poi);
+}
+
+static int tango_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+		const uint8_t *buf, int oob_required, int page)
+{
+	return raw_write(chip, buf, chip->oob_poi);
+}
+
+static int tango_read_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
+{
+	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+	return raw_read(chip, NULL, chip->oob_poi);
+}
+
+static int tango_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
+{
+	chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page);
+	raw_write(chip, NULL, chip->oob_poi);
+	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+	chip->waitfunc(mtd, chip);
+	return 0;
+}
+
+static int oob_ecc(struct mtd_info *mtd, int idx, struct mtd_oob_region *res)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+	if (idx >= ecc->steps)
+		return -ERANGE;
+
+	res->offset = BBM_SIZE + METADATA_SIZE + ecc->bytes * idx;
+	res->length = ecc->bytes;
+
+	return 0;
+}
+
+static int oob_free(struct mtd_info *mtd, int idx, struct mtd_oob_region *res)
+{
+	return -ERANGE; /* no free space in spare area */
+}
+
+static const struct mtd_ooblayout_ops tango_nand_ooblayout_ops = {
+	.ecc	= oob_ecc,
+	.free	= oob_free,
+};
+
+static u32 to_ticks(int kHz, int ps)
+{
+	return DIV_ROUND_UP_ULL((u64)kHz * ps, NSEC_PER_SEC);
+}
+
+static int tango_set_timings(struct mtd_info *mtd,
+		const struct nand_data_interface *conf, bool check_only)
+{
+	const struct nand_sdr_timings *sdr = nand_get_sdr_timings(conf);
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+	struct tango_chip *tchip = to_tango_chip(chip);
+	u32 Trdy, Textw, Twc, Twpw, Tacc, Thold, Trpw, Textr;
+	int kHz = nfc->freq_kHz;
+
+	if (IS_ERR(sdr))
+		return PTR_ERR(sdr);
+
+	if (check_only)
+		return 0;
+
+	Trdy = to_ticks(kHz, sdr->tCEA_max - sdr->tREA_max);
+	Textw = to_ticks(kHz, sdr->tWB_max);
+	Twc = to_ticks(kHz, sdr->tWC_min);
+	Twpw = to_ticks(kHz, sdr->tWC_min - sdr->tWP_min);
+
+	Tacc = to_ticks(kHz, sdr->tREA_max);
+	Thold = to_ticks(kHz, sdr->tREH_min);
+	Trpw = to_ticks(kHz, sdr->tRC_min - sdr->tREH_min);
+	Textr = to_ticks(kHz, sdr->tRHZ_max);
+
+	tchip->timing1 = TIMING(Trdy, Textw, Twc, Twpw);
+	tchip->timing2 = TIMING(Tacc, Thold, Trpw, Textr);
+
+	return 0;
+}
+
+static int chip_init(struct device *dev, struct device_node *np)
+{
+	int err, res;
+	u32 cs, ecc_bits;
+	struct mtd_info *mtd;
+	struct nand_chip *chip;
+	struct tango_chip *tchip;
+	struct nand_ecc_ctrl *ecc;
+	struct tango_nfc *nfc = dev_get_drvdata(dev);
+
+	tchip = devm_kzalloc(dev, sizeof(*tchip), GFP_KERNEL);
+	if (!tchip)
+		return -ENOMEM;
+
+	res = of_property_count_u32_elems(np, "reg");
+	if (res < 0)
+		return res;
+
+	if (res != 1)
+		return -ENOTSUPP; /* Multi-CS chips are not supported */
+
+	err = of_property_read_u32_index(np, "reg", 0, &cs);
+	if (err)
+		return err;
+
+	if (cs >= MAX_CS)
+		return -EINVAL;
+
+	chip = &tchip->nand_chip;
+	ecc = &chip->ecc;
+	mtd = &chip->mtd;
+
+	chip->read_byte = tango_read_byte;
+	chip->write_buf = tango_write_buf;
+	chip->read_buf = tango_read_buf;
+	chip->select_chip = tango_select_chip;
+	chip->cmd_ctrl = tango_cmd_ctrl;
+	chip->dev_ready = tango_dev_ready;
+	chip->setup_data_interface = tango_set_timings;
+	chip->options = 0
+		| NAND_USE_BOUNCE_BUFFER
+		| NAND_NO_SUBPAGE_WRITE
+		| NAND_WAIT_TCCS;
+	chip->controller = &nfc->hw;
+	tchip->base = nfc->pbus_base + (cs * 256);
+
+	nand_set_flash_node(chip, np);
+	mtd_set_ooblayout(mtd, &tango_nand_ooblayout_ops);
+	mtd->dev.parent = dev;
+
+	ecc->mode = NAND_ECC_HW;
+	ecc->algo = NAND_ECC_BCH;
+
+	err = nand_scan_ident(mtd, 1, NULL);
+	if (err)
+		return err;
+
+	ecc->read_page_raw = tango_read_page_raw;
+	ecc->write_page_raw = tango_write_page_raw;
+	ecc->read_page = tango_read_page;
+	ecc->write_page = tango_write_page;
+	ecc->read_oob = tango_read_oob;
+	ecc->write_oob = tango_write_oob;
+
+	ecc_bits = ecc->strength * FIELD_ORDER;
+	ecc->bytes = DIV_ROUND_UP(ecc_bits, BITS_PER_BYTE);
+
+	err = nand_scan_tail(mtd);
+	if (err)
+		return err;
+
+	tchip->xfer_cfg = XFER_CFG(cs, 1, ecc->steps, METADATA_SIZE);
+	tchip->pkt_0_cfg = PKT_CFG(ecc->size + METADATA_SIZE, ecc->strength);
+	tchip->pkt_n_cfg = PKT_CFG(ecc->size, ecc->strength);
+	tchip->bb_cfg = BB_CFG(mtd->writesize, BBM_SIZE);
+
+	err = mtd_device_register(mtd, NULL, 0);
+	if (err)
+		return err;
+
+	nfc->chips[cs] = tchip;
+
+	return 0;
+}
+
+static int tango_nand_remove(struct platform_device *pdev)
+{
+	int cs;
+	struct tango_nfc *nfc = platform_get_drvdata(pdev);
+
+	dma_release_channel(nfc->chan);
+
+	for (cs = 0; cs < MAX_CS; ++cs)
+		if (nfc->chips[cs] != NULL)
+			nand_release(&nfc->chips[cs]->nand_chip.mtd);
+
+	return 0;
+}
+
+static int tango_nand_probe(struct platform_device *pdev)
+{
+	struct clk *clk;
+	struct resource *res;
+	struct tango_nfc *nfc;
+	struct device_node *np;
+
+	nfc = devm_kzalloc(&pdev->dev, sizeof(*nfc), GFP_KERNEL);
+	if (!nfc)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	nfc->reg_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(nfc->reg_base))
+		return PTR_ERR(nfc->reg_base);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	nfc->mem_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(nfc->mem_base))
+		return PTR_ERR(nfc->mem_base);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	nfc->pbus_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(nfc->pbus_base))
+		return PTR_ERR(nfc->pbus_base);
+
+	clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	nfc->chan = dma_request_chan(&pdev->dev, "nfc_sbox");
+	if (IS_ERR(nfc->chan))
+		return PTR_ERR(nfc->chan);
+
+	platform_set_drvdata(pdev, nfc);
+	nand_hw_control_init(&nfc->hw);
+	nfc->freq_kHz = clk_get_rate(clk) / 1000;
+
+	for_each_child_of_node(pdev->dev.of_node, np) {
+		int err = chip_init(&pdev->dev, np);
+		if (err) {
+			tango_nand_remove(pdev);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+static const struct of_device_id tango_nand_ids[] = {
+	{ .compatible = "sigma,smp8758-nand" },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver tango_nand_driver = {
+	.probe	= tango_nand_probe,
+	.remove	= tango_nand_remove,
+	.driver	= {
+		.name		= "tango-nand",
+		.of_match_table	= tango_nand_ids,
+	},
+};
+
+module_platform_driver(tango_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sigma Designs");
+MODULE_DESCRIPTION("Tango4 NAND Flash controller driver");
-- 
2.9.0


From boris.brezillon at free-electrons.com  Mon Oct 24 06:02:01 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Mon, 24 Oct 2016 15:02:01 +0200
Subject: [PATCH v3 3/3] mtd: s3c2410: parse the device configuration
 from OF node
In-Reply-To: <1476999766-32526-4-git-send-email-sergio.prado@e-labworks.com>
References: <1476999766-32526-1-git-send-email-sergio.prado@e-labworks.com>
 <1476999766-32526-4-git-send-email-sergio.prado@e-labworks.com>
Message-ID: <20161024150201.01952f67@bbrezillon>

On Thu, 20 Oct 2016 19:42:46 -0200
Sergio Prado <sergio.prado at e-labworks.com> wrote:

> Allows configuring Samsung's s3c2410 memory controller using a
> devicetree.
> 
> Signed-off-by: Sergio Prado <sergio.prado at e-labworks.com>
> ---
>  drivers/mtd/nand/s3c2410.c                     | 158 ++++++++++++++++++++++---
>  include/linux/platform_data/mtd-nand-s3c2410.h |   1 +
>  2 files changed, 143 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
> index 371db0d48135..ec170be881bc 100644
> --- a/drivers/mtd/nand/s3c2410.c
> +++ b/drivers/mtd/nand/s3c2410.c
> @@ -39,6 +39,8 @@
>  #include <linux/slab.h>
>  #include <linux/clk.h>
>  #include <linux/cpufreq.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
>  
>  #include <linux/mtd/mtd.h>
>  #include <linux/mtd/nand.h>
> @@ -185,6 +187,22 @@ struct s3c2410_nand_info {
>  #endif
>  };
>  
> +struct s3c24XX_nand_devtype_data {
> +	enum s3c_cpu_type type;
> +};
> +
> +static const struct s3c24XX_nand_devtype_data s3c2410_nand_devtype_data = {
> +	.type = TYPE_S3C2410,
> +};
> +
> +static const struct s3c24XX_nand_devtype_data s3c2412_nand_devtype_data = {
> +	.type = TYPE_S3C2412,
> +};
> +
> +static const struct s3c24XX_nand_devtype_data s3c2440_nand_devtype_data = {
> +	.type = TYPE_S3C2440,
> +};
> +
>  /* conversion functions */
>  
>  static struct s3c2410_nand_mtd *s3c2410_nand_mtd_toours(struct mtd_info *mtd)
> @@ -794,6 +812,30 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
>  	return -ENODEV;
>  }
>  
> +static int s3c2410_nand_setup_data_interface(struct mtd_info *mtd,
> +					     const struct nand_data_interface *conf,
> +					     bool check_only)
> +{
> +	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
> +	struct s3c2410_platform_nand *pdata = info->platform;
> +	const struct nand_sdr_timings *timings;
> +	int tacls;
> +
> +	timings = nand_get_sdr_timings(conf);
> +	if (IS_ERR(timings))
> +		return -ENOTSUPP;
> +
> +	tacls = timings->tCLS_min - timings->tWP_min;
> +	if (tacls < 0)
> +		tacls = 0;
> +
> +	pdata->tacls  = DIV_ROUND_UP(tacls, 1000);
> +	pdata->twrph0 = DIV_ROUND_UP(timings->tWP_min, 1000);
> +	pdata->twrph1 = DIV_ROUND_UP(timings->tCLH_min, 1000);

You seem to only apply the timings in s3c2410_nand_setrate(), which is
only called at probe time or on a cpufreq even, but the core can change
timings at runtime (this is what happens each time you reset the chip).

To support that you have 2 options:
 - apply the timings in ->select_chip()
 - apply the timings here

> +
> +	return 0;
> +}
> +
>  /**
>   * s3c2410_nand_init_chip - initialise a single instance of an chip
>   * @info: The base NAND controller the chip is on.
> @@ -808,9 +850,12 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
>  				   struct s3c2410_nand_mtd *nmtd,
>  				   struct s3c2410_nand_set *set)
>  {
> +	struct device_node *np = info->device->of_node;
>  	struct nand_chip *chip = &nmtd->chip;
>  	void __iomem *regs = info->regs;
>  
> +	nand_set_flash_node(chip, set->of_node);
> +
>  	chip->write_buf    = s3c2410_nand_write_buf;
>  	chip->read_buf     = s3c2410_nand_read_buf;
>  	chip->select_chip  = s3c2410_nand_select_chip;
> @@ -819,6 +864,13 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
>  	chip->options	   = set->options;
>  	chip->controller   = &info->controller;
>  
> +	/*
> +	 * let's keep behavior unchanged for legacy boards booting via pdata and
> +	 * auto-detect timings only when booting with a device tree.
> +	 */
> +	if (np)
> +		chip->setup_data_interface = s3c2410_nand_setup_data_interface;
> +
>  	switch (info->cpu_type) {
>  	case TYPE_S3C2410:
>  		chip->IO_ADDR_W = regs + S3C2410_NFDATA;
> @@ -859,12 +911,9 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
>  	chip->ecc.mode = info->platform->ecc_mode;
>  
>  	/* If you use u-boot BBT creation code, specifying this flag will
> -	 * let the kernel fish out the BBT from the NAND, and also skip the
> -	 * full NAND scan that can take 1/2s or so. Little things... */
> -	if (set->flash_bbt) {
> +	 * let the kernel fish out the BBT from the NAND */
> +	if (set->flash_bbt)
>  		chip->bbt_options |= NAND_BBT_USE_FLASH;
> -		chip->options |= NAND_SKIP_BBTSCAN;
> -	}
>  }
>  
>  /**
> @@ -943,6 +992,77 @@ static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
>  		return -EINVAL;
>  	}
>  
> +	if (chip->bbt_options & NAND_BBT_USE_FLASH)
> +		chip->options |= NAND_SKIP_BBTSCAN;
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id s3c24xx_nand_dt_ids[] = {
> +	{
> +		.compatible = "samsung,s3c2410-nand",
> +		.data = &s3c2410_nand_devtype_data,
> +	}, {
> +		.compatible = "samsung,s3c2412-nand", /* also compatible with s3c6400 */
> +		.data = &s3c2412_nand_devtype_data,
> +	}, {
> +		.compatible = "samsung,s3c2440-nand",
> +		.data = &s3c2440_nand_devtype_data,
> +	},
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, s3c24xx_nand_dt_ids);
> +
> +static int s3c24xx_nand_probe_dt(struct platform_device *pdev)
> +{
> +	const struct s3c24XX_nand_devtype_data *devtype_data;
> +	struct s3c2410_platform_nand *pdata;
> +	struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
> +	struct device_node *np = pdev->dev.of_node, *child;
> +	struct s3c2410_nand_set *sets;
> +
> +	devtype_data = of_device_get_match_data(&pdev->dev);
> +	if (!devtype_data)
> +		return -ENODEV;
> +
> +	info->cpu_type = devtype_data->type;
> +
> +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
> +	if (!pdata)
> +		return -ENOMEM;
> +
> +	pdev->dev.platform_data = pdata;
> +
> +	pdata->nr_sets = of_get_child_count(np);
> +	if (!pdata->nr_sets)
> +		return 0;
> +
> +	sets = devm_kzalloc(&pdev->dev, sizeof(*sets) * pdata->nr_sets, GFP_KERNEL);
> +	if (!sets)
> +		return -ENOMEM;
> +
> +	pdata->sets = sets;
> +
> +	for_each_available_child_of_node(np, child) {
> +
> +		sets->name = (char *)child->name;
> +		sets->of_node = child;
> +		sets->nr_chips = 1;
> +
> +		of_node_get(child);
> +
> +		sets++;
> +	}
> +
> +	return 0;
> +}
> +
> +static int s3c24xx_nand_probe_pdata(struct platform_device *pdev)
> +{
> +	struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
> +
> +	info->cpu_type = platform_get_device_id(pdev)->driver_data;
> +
>  	return 0;
>  }
>  
> @@ -955,8 +1075,7 @@ static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
>  */
>  static int s3c24xx_nand_probe(struct platform_device *pdev)
>  {
> -	struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
> -	enum s3c_cpu_type cpu_type;
> +	struct s3c2410_platform_nand *plat;
>  	struct s3c2410_nand_info *info;
>  	struct s3c2410_nand_mtd *nmtd;
>  	struct s3c2410_nand_set *sets;
> @@ -966,8 +1085,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
>  	int nr_sets;
>  	int setno;
>  
> -	cpu_type = platform_get_device_id(pdev)->driver_data;
> -
>  	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
>  	if (info == NULL) {
>  		err = -ENOMEM;
> @@ -989,6 +1106,16 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
>  
>  	s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
>  
> +	if (pdev->dev.of_node)
> +		err = s3c24xx_nand_probe_dt(pdev);
> +	else
> +		err = s3c24xx_nand_probe_pdata(pdev);
> +
> +	if (err)
> +		goto exit_error;
> +
> +	plat = to_nand_plat(pdev);
> +
>  	/* allocate and map the resource */
>  
>  	/* currently we assume we have the one resource */
> @@ -997,7 +1124,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
>  
>  	info->device	= &pdev->dev;
>  	info->platform	= plat;
> -	info->cpu_type	= cpu_type;
>  
>  	info->regs = devm_ioremap_resource(&pdev->dev, res);
>  	if (IS_ERR(info->regs)) {
> @@ -1007,12 +1133,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
>  
>  	dev_dbg(&pdev->dev, "mapped registers at %p\n", info->regs);
>  
> -	/* initialise the hardware */
> -
> -	err = s3c2410_nand_inithw(info);
> -	if (err != 0)
> -		goto exit_error;
> -
>  	sets = (plat != NULL) ? plat->sets : NULL;
>  	nr_sets = (plat != NULL) ? plat->nr_sets : 1;
>  
> @@ -1056,6 +1176,11 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
>  			sets++;
>  	}
>  
> +	/* initialise the hardware */
> +	err = s3c2410_nand_inithw(info);
> +	if (err != 0)
> +		goto exit_error;
> +
>  	err = s3c2410_nand_cpufreq_register(info);
>  	if (err < 0) {
>  		dev_err(&pdev->dev, "failed to init cpufreq support\n");
> @@ -1156,6 +1281,7 @@ static int s3c24xx_nand_resume(struct platform_device *dev)
>  	.id_table	= s3c24xx_driver_ids,
>  	.driver		= {
>  		.name	= "s3c24xx-nand",
> +		.of_match_table = s3c24xx_nand_dt_ids,
>  	},
>  };
>  
> diff --git a/include/linux/platform_data/mtd-nand-s3c2410.h b/include/linux/platform_data/mtd-nand-s3c2410.h
> index 729af13d1773..f01659026b26 100644
> --- a/include/linux/platform_data/mtd-nand-s3c2410.h
> +++ b/include/linux/platform_data/mtd-nand-s3c2410.h
> @@ -40,6 +40,7 @@ struct s3c2410_nand_set {
>  	char			*name;
>  	int			*nr_map;
>  	struct mtd_partition	*partitions;
> +	struct device_node	*of_node;
>  };
>  
>  struct s3c2410_platform_nand {



From marcin.krzeminski at nokia.com  Mon Oct 24 06:03:31 2016
From: marcin.krzeminski at nokia.com (marcin.krzeminski at nokia.com)
Date: Mon, 24 Oct 2016 15:03:31 +0200
Subject: [PATCH 0/3] Introduce die erase command
Message-ID: <1477314214-17718-1-git-send-email-marcin.krzeminski@nokia.com>

From: Marcin Krzeminski <marcin.krzeminski at nokia.com>

This series introduce die erase command and new MT25Q00 Micron devices.

Marcin Krzeminski (3):
  mtd: spi-nor: Add die_cnt field and flags
  mtd: spi-nor: Implement die erase command logic
  mtd: spi-nor: Enable die erase for Micron 1GiB

 drivers/mtd/spi-nor/spi-nor.c | 128 ++++++++++++++++++++++++++++++++++++++----
 include/linux/mtd/spi-nor.h   |   5 ++
 2 files changed, 122 insertions(+), 11 deletions(-)

-- 
2.7.4



From marcin.krzeminski at nokia.com  Mon Oct 24 06:03:34 2016
From: marcin.krzeminski at nokia.com (marcin.krzeminski at nokia.com)
Date: Mon, 24 Oct 2016 15:03:34 +0200
Subject: [PATCH 3/3] mtd: spi-nor: Enable die erase for Micron 1GiB
In-Reply-To: <1477314214-17718-1-git-send-email-marcin.krzeminski@nokia.com>
References: <1477314214-17718-1-git-send-email-marcin.krzeminski@nokia.com>
Message-ID: <1477314214-17718-4-git-send-email-marcin.krzeminski@nokia.com>

From: Marcin Krzeminski <marcin.krzeminski at nokia.com>

Micron N25Q00 and MT25Q00 share same JEDEC Id,
but it seem can be properly recognized by second
ext_jedec id byte.

This commits extends n25q00 ids by adding ext
bytes and also adds mt25q00 family.
For MT25Q00 family, the number of dies is two, N25Q00
has it four. Logic to support that is added.

Signed-off-by: Marcin Krzeminski <marcin.krzeminski at nokia.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 36 ++++++++++++++++++++++++++++++++++--
 1 file changed, 34 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 17bbec0..b33ead6 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -218,6 +218,28 @@ static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info,
 		return nor->write_reg(nor, SPINOR_OP_BRWR, nor->cmd_buf, 1);
 	}
 }
+
+static void spi_nor_die_cnt(struct spi_nor *nor,
+		const struct flash_info *info)
+{
+	switch (JEDEC_MFR(info)) {
+	case SNOR_MFR_MICRON:
+		/* 1GiB devices */
+		if (info->id[2] == 0x21) {
+			/* MT25Q00 has 2 dies N25Q00 has 4 */
+			if (info->id[4] & BIT(6))
+				nor->die_cnt = 2;
+			else
+				nor->die_cnt = 4;
+		} else
+			nor->die_cnt = 0;
+	break;
+	default:
+		nor->die_cnt = 0;
+		break;
+	}
+}
+
 static inline int spi_nor_sr_ready(struct spi_nor *nor)
 {
 	int sr = read_sr(nor);
@@ -970,8 +992,14 @@ static const struct flash_info spi_nor_ids[] = {
 	{ "n25q256a",    INFO(0x20ba19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_QUAD_READ) },
 	{ "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) },
+	{ "n25q00",      INFO(0x20ba21, 0x1000, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | DIE_ERASE) },
+	{ "n25q00a",     INFO(0x20bb21, 0x1000, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | DIE_ERASE) },
+	{ "n25q00",      INFO(0x20ba21, 0x1004, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | DIE_ERASE) },
+	{ "n25q00a",     INFO(0x20bb21, 0x1004, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | DIE_ERASE) },
+	{ "mt25ql01g",   INFO(0x20ba21, 0x1044, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | DIE_ERASE) },
+	{ "mt25qu01g",   INFO(0x20bb21, 0x1044, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | DIE_ERASE) },
+	{ "mt25ql01g",   INFO(0x20ba21, 0x1040, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | DIE_ERASE) },
+	{ "mt25qu01g",   INFO(0x20bb21, 0x1040, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | DIE_ERASE) },
 
 	/* PMC */
 	{ "pm25lv512",   INFO(0,        0, 32 * 1024,    2, SECT_4K_PMC) },
@@ -1479,6 +1507,10 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 		nor->flags |= SNOR_F_USE_FSR;
 	if (info->flags & SPI_NOR_HAS_TB)
 		nor->flags |= SNOR_F_HAS_SR_TB;
+	if (info->flags & DIE_ERASE) {
+		nor->flags |= SNOR_F_DIE_ERASE;
+		spi_nor_die_cnt(nor, info);
+	}
 
 #ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
 	/* prefer "small sector" erase if possible */
-- 
2.7.4



From marcin.krzeminski at nokia.com  Mon Oct 24 06:03:32 2016
From: marcin.krzeminski at nokia.com (marcin.krzeminski at nokia.com)
Date: Mon, 24 Oct 2016 15:03:32 +0200
Subject: [PATCH 1/3] mtd: spi-nor: Add die_cnt field and flags
In-Reply-To: <1477314214-17718-1-git-send-email-marcin.krzeminski@nokia.com>
References: <1477314214-17718-1-git-send-email-marcin.krzeminski@nokia.com>
Message-ID: <1477314214-17718-2-git-send-email-marcin.krzeminski@nokia.com>

From: Marcin Krzeminski <marcin.krzeminski at nokia.com>

This commit adds new field and flags that could
be used to signalize that chip support die erase
command.

If DIE_ERASE flag will be selected but die_cnt field
will be 0 chip will not use chip erase command.

Signed-off-by: Marcin Krzeminski <marcin.krzeminski at nokia.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 18 ++++++++++++++++++
 include/linux/mtd/spi-nor.h   |  5 +++++
 2 files changed, 23 insertions(+)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index d0fc165..3afe207 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -75,6 +75,7 @@ struct flash_info {
 					 * bit. Must be used with
 					 * SPI_NOR_HAS_LOCK.
 					 */
+#define DIE_ERASE			BIT(10)	/* Support for die erase cmd */
 };
 
 #define JEDEC_MFR(info)	((info)->id[0])
@@ -295,6 +296,23 @@ static int erase_chip(struct spi_nor *nor)
 	return nor->write_reg(nor, SPINOR_OP_CHIP_ERASE, NULL, 0);
 }
 
+static int spi_nor_die_erase(struct spi_nor *nor, u32 addr)
+{
+	u8 buf[SPI_NOR_MAX_ADDR_WIDTH];
+	int i;
+
+	dev_dbg(nor->dev, "erase @ 0x%X\n", addr);
+
+	write_enable(nor);
+
+	for (i = nor->addr_width - 1; i >= 0; i--) {
+		buf[i] = addr & 0xff;
+		addr >>= 8;
+	}
+
+	return nor->write_reg(nor, SPINOR_OP_DIE_ERASE, buf, nor->addr_width);
+}
+
 static int spi_nor_lock_and_prep(struct spi_nor *nor, enum spi_nor_ops ops)
 {
 	int ret = 0;
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index c425c7b..80154b2 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -50,6 +50,7 @@
 #define SPINOR_OP_BE_4K_PMC	0xd7	/* Erase 4KiB block on PMC chips */
 #define SPINOR_OP_BE_32K	0x52	/* Erase 32KiB block */
 #define SPINOR_OP_CHIP_ERASE	0xc7	/* Erase whole flash chip */
+#define SPINOR_OP_DIE_ERASE	0xc4	/* Erase whole die within chip */
 #define SPINOR_OP_SE		0xd8	/* Sector erase (usually 64KiB) */
 #define SPINOR_OP_RDID		0x9f	/* Read JEDEC ID */
 #define SPINOR_OP_RDCR		0x35	/* Read configuration register */
@@ -119,6 +120,7 @@ enum spi_nor_ops {
 enum spi_nor_option_flags {
 	SNOR_F_USE_FSR		= BIT(0),
 	SNOR_F_HAS_SR_TB	= BIT(1),
+	SNOR_F_DIE_ERASE	= BIT(2),
 };
 
 /**
@@ -136,6 +138,8 @@ enum spi_nor_option_flags {
  * @sst_write_second:	used by the SST write operation
  * @flags:		flag options for the current SPI-NOR (SNOR_F_*)
  * @cmd_buf:		used by the write_reg
+ * @die_cnt:		number of dies in chip, if and SNOR_F_DIE_ERASE
+ * 			flasg is enabled CE command will be disabled
  * @prepare:		[OPTIONAL] do some preparations for the
  *			read/write/erase/lock/unlock operations
  * @unprepare:		[OPTIONAL] do some post work after the
@@ -167,6 +171,7 @@ struct spi_nor {
 	bool			sst_write_second;
 	u32			flags;
 	u8			cmd_buf[SPI_NOR_MAX_CMD_SIZE];
+	u32			die_cnt;
 
 	int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);
 	void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops);
-- 
2.7.4



From marcin.krzeminski at nokia.com  Mon Oct 24 06:03:33 2016
From: marcin.krzeminski at nokia.com (marcin.krzeminski at nokia.com)
Date: Mon, 24 Oct 2016 15:03:33 +0200
Subject: [PATCH 2/3] mtd: spi-nor: Implement die erase command logic
In-Reply-To: <1477314214-17718-1-git-send-email-marcin.krzeminski@nokia.com>
References: <1477314214-17718-1-git-send-email-marcin.krzeminski@nokia.com>
Message-ID: <1477314214-17718-3-git-send-email-marcin.krzeminski@nokia.com>

From: Marcin Krzeminski <marcin.krzeminski at nokia.com>

This commit implements die erase logic.
Sector at a time procedure is moved to function,
then erase algorithm will try to use die erase cmd
if size and address cover one or more dies.

Signed-off-by: Marcin Krzeminski <marcin.krzeminski at nokia.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 90 +++++++++++++++++++++++++++++++++++++------
 1 file changed, 78 insertions(+), 12 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 3afe207..17bbec0 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -360,6 +360,29 @@ static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
 	return nor->write_reg(nor, nor->erase_opcode, buf, nor->addr_width);
 }
 
+static inline int spi_nor_sector_at_time_erase(struct mtd_info *mtd, u32 addr, u32 len)
+{
+	struct spi_nor *nor = mtd_to_spi_nor(mtd);
+	int ret = 0;
+
+	while (len) {
+		write_enable(nor);
+
+		ret = spi_nor_erase_sector(nor, addr);
+		if (ret)
+			return ret;
+
+		addr += mtd->erasesize;
+		len -= mtd->erasesize;
+
+		ret = spi_nor_wait_till_ready(nor);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
 /*
  * Erase an address range on the nor chip.  The address range may extend
  * one or more erase sectors.  Return an error is there is a problem erasing.
@@ -367,9 +390,11 @@ static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
 static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
 	struct spi_nor *nor = mtd_to_spi_nor(mtd);
-	u32 addr, len;
+	u32 addr, len, die_no, die_size;
 	uint32_t rem;
 	int ret;
+	unsigned long timeout;
+	u8 die_erase = nor->die_cnt && SNOR_F_DIE_ERASE;
 
 	dev_dbg(nor->dev, "at 0x%llx, len %lld\n", (long long)instr->addr,
 			(long long)instr->len);
@@ -386,7 +411,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
 		return ret;
 
 	/* whole-chip erase? */
-	if (len == mtd->size) {
+	if (len == mtd->size && !die_erase) {
 		unsigned long timeout;
 
 		write_enable(nor);
@@ -416,17 +441,58 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
 
 	/* "sector"-at-a-time erase */
 	} else {
-		while (len) {
-			write_enable(nor);
-
-			ret = spi_nor_erase_sector(nor, addr);
-			if (ret)
+		if (die_erase) {
+			die_size = div_u64_rem(mtd->size, nor->die_cnt, &rem);
+			if (rem) {
+				ret = -EINVAL;
 				goto erase_err;
-
-			addr += mtd->erasesize;
-			len -= mtd->erasesize;
-
-			ret = spi_nor_wait_till_ready(nor);
+			}
+			while (len) {
+				die_no = div_u64_rem(addr, die_size, &rem);
+
+				/* Check if address is aligned to die begin*/
+				if (!rem) {
+					/* die erase? */
+					if (len >= die_size) {
+						ret = spi_nor_die_erase(nor, addr);
+						if (ret)
+							goto erase_err;
+
+						len -= die_size;
+						addr += die_size;
+
+						timeout = max(CHIP_ERASE_2MB_READY_WAIT_JIFFIES,
+								CHIP_ERASE_2MB_READY_WAIT_JIFFIES *
+								(unsigned long)(die_size / SZ_2M));
+						ret = spi_nor_wait_till_ready_with_timeout(nor, timeout);
+						if (ret)
+							goto erase_err;
+					} else {
+						ret = spi_nor_sector_at_time_erase(mtd, addr, len);
+						if (ret)
+							goto erase_err;
+						len = 0;
+					}
+				} else {
+					/* check if end address cover at least one die */
+					if (div64_ul(addr + len, die_size) > ++die_no) {
+						/* align to next die */
+						rem = die_size - rem;
+						ret = spi_nor_sector_at_time_erase(mtd, addr, rem);
+						if (ret)
+							goto erase_err;
+						len -= rem;
+						addr += rem;
+					} else {
+						ret = spi_nor_sector_at_time_erase(mtd, addr, len);
+						if (ret)
+							goto erase_err;
+						len = 0;
+					}
+				}
+			}
+		} else {
+			ret = spi_nor_sector_at_time_erase(mtd, addr, len);
 			if (ret)
 				goto erase_err;
 		}
-- 
2.7.4



From cyrille.pitchen at atmel.com  Mon Oct 24 06:06:39 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Mon, 24 Oct 2016 15:06:39 +0200
Subject: [PATCH] MAINTAINERS: add more people to the MTD maintainer team
In-Reply-To: <1477312526-7563-1-git-send-email-boris.brezillon@free-electrons.com>
References: <1477312526-7563-1-git-send-email-boris.brezillon@free-electrons.com>
Message-ID: <9e70dbc8-d234-fdb4-b7a6-0cfd91aca1cf@atmel.com>

Hi Boris,

Le 24/10/2016 ? 14:35, Boris Brezillon a ?crit :
> Brian has been maintaining the MTD subsystem alone for several years
> now, and maintaining such a subsystem can really be time consuming.
> 
> Create a maintainer team formed of the most active MTD contributors
> to help Brian with this task, which will hopefully improve the
> subsystem reactivity.
> 
> Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
Acked-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>

thanks! :)

Cyrille
> ---
> Hi all,
> 
> I'm just trying to summarize what I understood the process would be,
> don't hesitate to correct me if I'm wrong.
> 
> For each release we will assign a specific MTD maintainer which will be
> responsible for taking MTD core patches and pulling spi-nor and nand PRs
> into the MTD tree and eventually send one or several PRs to Linus.
> 
> For fixes that are submitted after -rc1, I usually ask Brian to apply
> them directly into the MTD tree (I don't think there's a real need to
> prepare spi-nor and nand PRs for fixes), so we can proceed the same
> way: ask the maintainer assigned to this release to also take care of
> applying fixes and sending PRs to Linus before each -rc.
> 
> If you have other ideas, or would like to proceed differently, don't
> hesitate propose them.
> 
> Thanks,
> 
> Boris
> ---
>  MAINTAINERS | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 1cd38a7e0064..cbf9583fdbe7 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -7912,6 +7912,10 @@ F:	mm/
>  MEMORY TECHNOLOGY DEVICES (MTD)
>  M:	David Woodhouse <dwmw2 at infradead.org>
>  M:	Brian Norris <computersforpeace at gmail.com>
> +M:	Boris Brezillon <boris.brezillon at free-electrons.com>
> +M:	Marek Vasut <marek.vasut at gmail.com>
> +M:	Richard Weinberger <richard at nod.at>
> +M:	Cyrille Pitchen <cyrille.pitchen at atmel.com>
>  L:	linux-mtd at lists.infradead.org
>  W:	http://www.linux-mtd.infradead.org/
>  Q:	http://patchwork.ozlabs.org/project/linux-mtd/list/
> 



From marek.vasut at gmail.com  Mon Oct 24 06:07:11 2016
From: marek.vasut at gmail.com (Marek Vasut)
Date: Mon, 24 Oct 2016 15:07:11 +0200
Subject: [PATCHv1] mtd: spi-nor: add support for s25fl208k
In-Reply-To: <CAD6G_RSJPXj2qNM28ODnW94q6dpqfJSRrm3YK7HdNB8_DVUahQ@mail.gmail.com>
References: <20161005085949.29804-1-sean.nyekjaer@prevas.dk>
 <CAD6G_RSJPXj2qNM28ODnW94q6dpqfJSRrm3YK7HdNB8_DVUahQ@mail.gmail.com>
Message-ID: <3536a9c3-9821-a7ee-7589-c329394894b9@gmail.com>

On 10/24/2016 10:16 AM, Jagan Teki wrote:
> On Wed, Oct 5, 2016 at 2:29 PM, Sean Nyekjaer <sean.nyekjaer at prevas.dk> wrote:
>> Signed-off-by: Sean Nyekjaer <sean.nyekjaer at prevas.dk>
>> ---
>> Changes: Fixed commit msg
> 
> Reviewed-by: Jagan Teki <jagan at openedev.com>
> 
> thanks!
> 
Acked-by: Marek Vasut <marex at denx.de>

-- 
Best regards,
Marek Vasut


From marek.vasut at gmail.com  Mon Oct 24 06:07:33 2016
From: marek.vasut at gmail.com (Marek Vasut)
Date: Mon, 24 Oct 2016 15:07:33 +0200
Subject: [PATCH] mtd: spi-nor: Add support for mr25h40
In-Reply-To: <CAD6G_RRTiToQScvOSCyrUn7XR9oLhoi574FabypAfPtSoMRF9g@mail.gmail.com>
References: <OS2PR01MB007355EE4F7CBD8647D65CD8DFC50@OS2PR01MB0073.jpnprd01.prod.outlook.com>
 <CAD6G_RRTiToQScvOSCyrUn7XR9oLhoi574FabypAfPtSoMRF9g@mail.gmail.com>
Message-ID: <452adce6-5f94-03bd-4752-becfe6429c1c@gmail.com>

On 10/24/2016 10:09 AM, Jagan Teki wrote:
> On Wed, Oct 5, 2016 at 1:52 PM, IWAMOTO Masahiko
> <iwamoto at allied-telesis.co.jp> wrote:
>>
>> Add Everspin mr25h40 512KB MRAM to the list of supported chips.
>>
>> Signed-off-by: Masahiko Iwamoto <iwamoto at allied-telesis.co.jp>
> 
> Reviewed-by: Jagan Teki <jagan at openedev.com>
> 
> thanks!
> 
Acked-by: Marek Vasut <marex at denx.de>

-- 
Best regards,
Marek Vasut


From marek.vasut at gmail.com  Mon Oct 24 06:09:12 2016
From: marek.vasut at gmail.com (Marek Vasut)
Date: Mon, 24 Oct 2016 15:09:12 +0200
Subject: [PATCH] mtd: spi-nor: Add support for N25Q256A13
In-Reply-To: <CAD6G_RT8s5=vDP2bc__SULyxt=NnqZrLDuepcUkxs75HG9=ZQg@mail.gmail.com>
References: <1475637910-2324-1-git-send-email-nobuhiro.iwamatsu.kw@hitachi.com>
 <CAD6G_RT8s5=vDP2bc__SULyxt=NnqZrLDuepcUkxs75HG9=ZQg@mail.gmail.com>
Message-ID: <25b5dc82-a5fa-1d0f-8915-60b121a65751@gmail.com>

On 10/24/2016 10:04 AM, Jagan Teki wrote:
> On Wed, Oct 5, 2016 at 8:55 AM, Nobuhiro Iwamatsu
> <nobuhiro.iwamatsu.kw at hitachi.com> wrote:
>> Add Micron N25Q256A13 256Mbit NOR Flash in the list of supported
>> devices. This chip is the same structure as the N25Q256A but ID
>> is different.
>>
>> Signed-off-by: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.kw at hitachi.com>
>> ---
>>
>>  drivers/mtd/spi-nor/spi-nor.c | 1 +
>>  1 file changed, 1 insertion(+)
>>
>> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
>> index d0fc165..ce67ccd 100644
>> --- a/drivers/mtd/spi-nor/spi-nor.c
>> +++ b/drivers/mtd/spi-nor/spi-nor.c
>> @@ -884,6 +884,7 @@ static const struct flash_info spi_nor_ids[] = {
>>         { "n25q128a11",  INFO(0x20bb18, 0, 64 * 1024,  256, SECT_4K | SPI_NOR_QUAD_READ) },
>>         { "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024,  256, SECT_4K | SPI_NOR_QUAD_READ) },
>>         { "n25q256a",    INFO(0x20ba19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_QUAD_READ) },
>> +       { "n25q256a13",  INFO(0x20bb19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_QUAD_READ) },
> 
> Since the previous chips follow 'a' notation for bb chips, better to
> use n25q256a for bb and n25q256 for ba

Do you mind expanding on this? I don't understand the remark.


-- 
Best regards,
Marek Vasut


From marek.vasut at gmail.com  Mon Oct 24 06:10:07 2016
From: marek.vasut at gmail.com (Marek Vasut)
Date: Mon, 24 Oct 2016 15:10:07 +0200
Subject: [PATCH] mtd: spi-nor: Add possibility to disable chip erase
In-Reply-To: <AM4PR0701MB21309FFCFE8370E3153ED66AFEA90@AM4PR0701MB2130.eurprd07.prod.outlook.com>
References: <1477054546-2548-1-git-send-email-marcin.krzeminski@nokia.com>
 <3b23706b-bf46-8d3b-e9b0-01194eec5e11@gmail.com>
 <AM4PR0701MB21309FFCFE8370E3153ED66AFEA90@AM4PR0701MB2130.eurprd07.prod.outlook.com>
Message-ID: <f70cf025-c8ef-1c9a-f8cc-2104e6752b13@gmail.com>

On 10/24/2016 08:10 AM, Krzeminski, Marcin (Nokia - PL/Wroclaw) wrote:
> Hi Marek,
> 
>> -----Original Message-----
>> From: Marek Vasut [mailto:marek.vasut at gmail.com]
>> Sent: Friday, October 21, 2016 7:53 PM
>> To: Krzeminski, Marcin (Nokia - PL/Wroclaw)
>> <marcin.krzeminski at nokia.com>; linux-mtd at lists.infradead.org
>> Cc: computersforpeace at gmail.com; cyrille.pitchen at atmel.com; rfsw-
>> patches at mlist.nokia.com; dwmw2 at infradead.org
>> Subject: Re: [PATCH] mtd: spi-nor: Add possibility to disable chip erase
>>
>> On 10/21/2016 02:55 PM, marcin.krzeminski at nokia.com wrote:
>>> From: Marcin Krzeminski <marcin.krzeminski at nokia.com>
>>>
>>> n25q00 does not support chip erase command (0xC7), but spi-nor
>>> framework still send if if user want to erase whole flash. This patch
>>> adds option to disable chip erase command and enable in on n25q00.
>>
>> That's true and it's a pretty nasty issue.
>> Can you instead implement logic to send multiple die-erase commands ?
>> They do make erasing faster afterall.
>>
> As we talked I would like to have die erase. I post is after tests,
> It will be a difference series since functionality will be different.
> In my MT25Q00 difference between die erase and sector at time erase
> is about 40 second.

Cool, thanks!

-- 
Best regards,
Marek Vasut


From marek.vasut at gmail.com  Mon Oct 24 06:11:05 2016
From: marek.vasut at gmail.com (Marek Vasut)
Date: Mon, 24 Oct 2016 15:11:05 +0200
Subject: [PATCH] MAINTAINERS: add more people to the MTD maintainer team
In-Reply-To: <9e70dbc8-d234-fdb4-b7a6-0cfd91aca1cf@atmel.com>
References: <1477312526-7563-1-git-send-email-boris.brezillon@free-electrons.com>
 <9e70dbc8-d234-fdb4-b7a6-0cfd91aca1cf@atmel.com>
Message-ID: <47e71461-8a9a-0db3-63ff-dc9016c6d9b1@gmail.com>

On 10/24/2016 03:06 PM, Cyrille Pitchen wrote:
> Hi Boris,
> 
> Le 24/10/2016 ? 14:35, Boris Brezillon a ?crit :
>> Brian has been maintaining the MTD subsystem alone for several years
>> now, and maintaining such a subsystem can really be time consuming.
>>
>> Create a maintainer team formed of the most active MTD contributors
>> to help Brian with this task, which will hopefully improve the
>> subsystem reactivity.
>>
>> Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
> Acked-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
> 
> thanks! :)

Acked-by: Marek Vasut <marek.vasut at gmail.com>

Thanks

-- 
Best regards,
Marek Vasut


From festevam at gmail.com  Mon Oct 24 06:14:30 2016
From: festevam at gmail.com (Fabio Estevam)
Date: Mon, 24 Oct 2016 11:14:30 -0200
Subject: [PATCH] mtd: nand: gpmi: disable the clocks on errors
In-Reply-To: <20161024143112.66bb705a@bbrezillon>
References: <1477152922-6722-1-git-send-email-festevam@gmail.com>
 <20161024143112.66bb705a@bbrezillon>
Message-ID: <CAOMZO5C79vHrSewFrzox=WBb8W8n_p2gd2jFML-xh51APf24Cw@mail.gmail.com>

[Adding Brian on Cc]

On Mon, Oct 24, 2016 at 10:31 AM, Boris Brezillon
<boris.brezillon at free-electrons.com> wrote:
> On Sat, 22 Oct 2016 14:15:22 -0200
> Fabio Estevam <festevam at gmail.com> wrote:
>
>> From: Fabio Estevam <fabio.estevam at nxp.com>
>>
>> We should disable the previously enabled GPMI clocks in the error paths.
>>
>> Also, when gpmi_enable_clk() fails simply return the error
>> code immediately rather than jumping to to the 'err_out' label.
>>
>> Signed-off-by: Fabio Estevam <fabio.estevam at nxp.com>
>
> Acked-by: Boris Brezillon <boris.brezillon at free-electrons.com>
>
> Brian, can you take this patch in the MTD tree and queue it for the
> next -rc?


From jagan at openedev.com  Mon Oct 24 06:21:20 2016
From: jagan at openedev.com (Jagan Teki)
Date: Mon, 24 Oct 2016 18:51:20 +0530
Subject: [PATCH] mtd: spi-nor: Add support for N25Q256A13
In-Reply-To: <25b5dc82-a5fa-1d0f-8915-60b121a65751@gmail.com>
References: <1475637910-2324-1-git-send-email-nobuhiro.iwamatsu.kw@hitachi.com>
 <CAD6G_RT8s5=vDP2bc__SULyxt=NnqZrLDuepcUkxs75HG9=ZQg@mail.gmail.com>
 <25b5dc82-a5fa-1d0f-8915-60b121a65751@gmail.com>
Message-ID: <CAD6G_RSTKULAU6v=W=GS-x10x206oMTjd6kfNhDuNc=jwqN93g@mail.gmail.com>

On Mon, Oct 24, 2016 at 6:39 PM, Marek Vasut <marek.vasut at gmail.com> wrote:
> On 10/24/2016 10:04 AM, Jagan Teki wrote:
>> On Wed, Oct 5, 2016 at 8:55 AM, Nobuhiro Iwamatsu
>> <nobuhiro.iwamatsu.kw at hitachi.com> wrote:
>>> Add Micron N25Q256A13 256Mbit NOR Flash in the list of supported
>>> devices. This chip is the same structure as the N25Q256A but ID
>>> is different.
>>>
>>> Signed-off-by: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.kw at hitachi.com>
>>> ---
>>>
>>>  drivers/mtd/spi-nor/spi-nor.c | 1 +
>>>  1 file changed, 1 insertion(+)
>>>
>>> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
>>> index d0fc165..ce67ccd 100644
>>> --- a/drivers/mtd/spi-nor/spi-nor.c
>>> +++ b/drivers/mtd/spi-nor/spi-nor.c
>>> @@ -884,6 +884,7 @@ static const struct flash_info spi_nor_ids[] = {
>>>         { "n25q128a11",  INFO(0x20bb18, 0, 64 * 1024,  256, SECT_4K | SPI_NOR_QUAD_READ) },
>>>         { "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024,  256, SECT_4K | SPI_NOR_QUAD_READ) },
>>>         { "n25q256a",    INFO(0x20ba19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_QUAD_READ) },
>>> +       { "n25q256a13",  INFO(0x20bb19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_QUAD_READ) },
>>
>> Since the previous chips follow 'a' notation for bb chips, better to
>> use n25q256a for bb and n25q256 for ba
>
> Do you mind expanding on this? I don't understand the remark.

{ "n25q064",     INFO(0x20ba17,
{ "n25q064a",   INFO(0x20bb17,

What I am saying is n25q256a is should be n25q256 and the new addition
can be n25q256a

thanks!
-- 
Jagan Teki
Free Software Engineer | www.openedev.com
U-Boot, Linux | Upstream Maintainer
Hyderabad, India.


From tytso at mit.edu  Mon Oct 24 06:48:16 2016
From: tytso at mit.edu (Theodore Ts'o)
Date: Mon, 24 Oct 2016 09:48:16 -0400
Subject: [PATCH 25/26] ubifs: Implement UBIFS_FLG_ENCRYPTION
In-Reply-To: <58235996-2da6-259c-a02c-9e7fcb499d62@nod.at>
References: <1477054121-10198-1-git-send-email-richard@nod.at>
 <1477054121-10198-26-git-send-email-richard@nod.at>
 <20161021183012.GC90712@google.com>
 <58235996-2da6-259c-a02c-9e7fcb499d62@nod.at>
Message-ID: <20161024134816.sihgrniryifo6n63@thunk.org>

On Mon, Oct 24, 2016 at 08:59:26AM +0200, Richard Weinberger wrote:
> 
> So, on ext4 (f2fs too?) root has to enable to feature first before users
> can use it?
> IOW for ext4 the encryption flag means "file encryption is allowed", for UBIFS it
> means "at least one file got encrypted on this fs".

Historically there have been one or two feature flags which ext4 has
enabled automatically, behind the system administrator's back.  We've
since decided that's a bad thing to do, and so it's a file system
level policy not to do this.

An example of why this can cause problems is if a system administrator
boots a rescue CD that happens to use a newer kernel, and that newer
kernel (plus potentially an updated userspace on said rescue CD)
silently the feature flag to enable some feature (say, the first time
we have files larger than 2GB, for example), and then when the system
administrator books back into their RHEL or SLES kernel, they can no
longer mount the file system.

So ext4 has a policy now that we won't do that, since it's unfriendly
to system administrators.  That's a general rule, and not one which is
specific to encryption.  That way you can create a file system, and
for the most part, modulo some really old, ancient flags which
hopefully all Linux systems understand (I don't *think* there are any
RHEL 2.x systems out there still :-), if a feature flag is not
enabled, the kernel will return an error if you try to use some
feature which is not enabled, instead of silently enabling it behind
the user and/or sysadmin's back.

I believe xfs may have a similar policy, and for similar reasons.
(Actually, I'm not sure if xfs supports enabling features after the
file system has been created at all; certainly Red Hat has a
distro-level policy of not supporting features added post-mkfs,
although I don't know how much that is enforced at the open source
coding level.  At one point there were some grumbles that Red Hat
might want to disable some of tune2fs's features of enabling features
post-mkfs time, but I think they've settled for just laughing at users
who show up with bug reports after they converted a file system from
ext3 to ext4.  :-)

> I think I'll do what ext4 does to have common policies.

If you want to, feel free; but if there is good reason for Ubifs to
want to be more flexible, I think there is room for differences at
this level.

The specific reason why we do this probably doesn't matter so much on
embedded systems --- although I will note that many/most handset
manufacturers have a policy of not supporting any new features that
require new *kernel* fatures after the device has been released,
because they don't want to deal with potential upgrade problems and
device instabilities issues; users tend to get unhappy when their
phones get bricked after an upgrade.

Cheers,

						- Ted


From cyrille.pitchen at atmel.com  Mon Oct 24 06:54:46 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Mon, 24 Oct 2016 15:54:46 +0200
Subject: [PATCH 1/3] mtd: spi-nor: Add die_cnt field and flags
In-Reply-To: <1477314214-17718-2-git-send-email-marcin.krzeminski@nokia.com>
References: <1477314214-17718-1-git-send-email-marcin.krzeminski@nokia.com>
 <1477314214-17718-2-git-send-email-marcin.krzeminski@nokia.com>
Message-ID: <0386ac08-f41e-1e10-d0e6-a16624bba952@atmel.com>

Hi Marcin,

Le 24/10/2016 ? 15:03, marcin.krzeminski at nokia.com a ?crit :
> From: Marcin Krzeminski <marcin.krzeminski at nokia.com>
> 
> This commit adds new field and flags that could
> be used to signalize that chip support die erase
> command.
> 
> If DIE_ERASE flag will be selected but die_cnt field
> will be 0 chip will not use chip erase command.
> 
> Signed-off-by: Marcin Krzeminski <marcin.krzeminski at nokia.com>
> ---
>  drivers/mtd/spi-nor/spi-nor.c | 18 ++++++++++++++++++
>  include/linux/mtd/spi-nor.h   |  5 +++++
>  2 files changed, 23 insertions(+)
> 
> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
> index d0fc165..3afe207 100644
> --- a/drivers/mtd/spi-nor/spi-nor.c
> +++ b/drivers/mtd/spi-nor/spi-nor.c
> @@ -75,6 +75,7 @@ struct flash_info {
>  					 * bit. Must be used with
>  					 * SPI_NOR_HAS_LOCK.
>  					 */
> +#define DIE_ERASE			BIT(10)	/* Support for die erase cmd */
>  };
>  
>  #define JEDEC_MFR(info)	((info)->id[0])
> @@ -295,6 +296,23 @@ static int erase_chip(struct spi_nor *nor)
>  	return nor->write_reg(nor, SPINOR_OP_CHIP_ERASE, NULL, 0);
>  }
>  
> +static int spi_nor_die_erase(struct spi_nor *nor, u32 addr)
> +{
> +	u8 buf[SPI_NOR_MAX_ADDR_WIDTH];
> +	int i;
> +
> +	dev_dbg(nor->dev, "erase @ 0x%X\n", addr);
> +
> +	write_enable(nor);
> +
> +	for (i = nor->addr_width - 1; i >= 0; i--) {
> +		buf[i] = addr & 0xff;
> +		addr >>= 8;
> +	}
> +
> +	return nor->write_reg(nor, SPINOR_OP_DIE_ERASE, buf, nor->addr_width);

If think you should first check whether nor->erase() is implemented by the SPI
controller driver and call it instead of nor->write_reg().

For instance, some SPI controllers are mapped to the system memory to speed
up Fast Read operations. In which case, they could also enable data cache to
fasten even more the read operations.

So when the spi-nor framework calls nor->erase() or nor->write(), those
handlers might need to invalidate the cache before performing the next read.

This is just an example but generally speaking, don't forget the nor->erase()
handler! :)


> +}
> +
>  static int spi_nor_lock_and_prep(struct spi_nor *nor, enum spi_nor_ops ops)
>  {
>  	int ret = 0;
> diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
> index c425c7b..80154b2 100644
> --- a/include/linux/mtd/spi-nor.h
> +++ b/include/linux/mtd/spi-nor.h
> @@ -50,6 +50,7 @@
>  #define SPINOR_OP_BE_4K_PMC	0xd7	/* Erase 4KiB block on PMC chips */
>  #define SPINOR_OP_BE_32K	0x52	/* Erase 32KiB block */
>  #define SPINOR_OP_CHIP_ERASE	0xc7	/* Erase whole flash chip */
> +#define SPINOR_OP_DIE_ERASE	0xc4	/* Erase whole die within chip */
>  #define SPINOR_OP_SE		0xd8	/* Sector erase (usually 64KiB) */
>  #define SPINOR_OP_RDID		0x9f	/* Read JEDEC ID */
>  #define SPINOR_OP_RDCR		0x35	/* Read configuration register */
> @@ -119,6 +120,7 @@ enum spi_nor_ops {
>  enum spi_nor_option_flags {
>  	SNOR_F_USE_FSR		= BIT(0),
>  	SNOR_F_HAS_SR_TB	= BIT(1),
> +	SNOR_F_DIE_ERASE	= BIT(2),
>  };
>  
>  /**
> @@ -136,6 +138,8 @@ enum spi_nor_option_flags {
>   * @sst_write_second:	used by the SST write operation
>   * @flags:		flag options for the current SPI-NOR (SNOR_F_*)
>   * @cmd_buf:		used by the write_reg
> + * @die_cnt:		number of dies in chip, if and SNOR_F_DIE_ERASE

The 1st flag is missing between "if" and "and", isn't it?
> + * 			flasg is enabled CE command will be disabled

typo: s/flasg/flags/
>   * @prepare:		[OPTIONAL] do some preparations for the
>   *			read/write/erase/lock/unlock operations
>   * @unprepare:		[OPTIONAL] do some post work after the
> @@ -167,6 +171,7 @@ struct spi_nor {
>  	bool			sst_write_second;
>  	u32			flags;
>  	u8			cmd_buf[SPI_NOR_MAX_CMD_SIZE];
> +	u32			die_cnt;
>  
>  	int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);
>  	void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops);
> 

Best regards,

Cyrille


From cyrille.pitchen at atmel.com  Mon Oct 24 07:07:57 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Mon, 24 Oct 2016 16:07:57 +0200
Subject: [PATCH v2 0/9] mtd: spi-nor: parse SFDP tables to setup (Q)SPI
 memories
In-Reply-To: <558d668a-69b0-8066-b7da-090517d3161d@atmel.com>
References: <cover.1475668319.git.cyrille.pitchen@atmel.com>
 <CAD6G_RR4Av8+szo9v2oucCFvwnow86gMVC-Ku_-Qfy18TVMGgA@mail.gmail.com>
 <c022e6fc-6bd7-d124-7233-e1e742049657@denx.de>
 <CAD6G_RQ2BjtF2cmPUJvYNk7KZZ6eTVAQsEqWs26xn710A4Dz-w@mail.gmail.com>
 <558d668a-69b0-8066-b7da-090517d3161d@atmel.com>
Message-ID: <1181d557-c149-8dfd-7fd1-bc83056541cf@atmel.com>

Le 24/10/2016 ? 14:09, Cyrille Pitchen a ?crit :
> Hi Jagan,
> 
> Le 24/10/2016 ? 09:41, Jagan Teki a ?crit :
>> On Sun, Oct 23, 2016 at 2:03 AM, Marek Vasut <marex at denx.de> wrote:
>>> On 10/22/2016 01:00 PM, Jagan Teki wrote:
>>>> On Wed, Oct 5, 2016 at 5:30 PM, Cyrille Pitchen
>>>> <cyrille.pitchen at atmel.com> wrote:
>>>>> Hi all,
>>>>>
>>>>> This series extends support of SPI protocols to new protocols such as
>>>>> SPI x-2-2 and SPI x-4-4. Also spi_nor_scan() tries now to select the right
>>>>> op codes, timing parameters (number of mode and dummy cycles) and erase
>>>>> sector size by parsing the Serial Flash Discoverable Parameter (SFDP)
>>>>> tables, when available, as defined in the JEDEC JESD216 specifications.
>>>>>
>>>>> When SFDP tables are not available, legacy settings are still used for
>>>>> backward compatibility (SPI and earlier QSPI memories).
>>>>>
>>>>> Support of SPI memories >128Mbits is also improved by using the 4byte
>>>>> address instruction set, when available. Using those dedicated op codes
>>>>> is stateless as opposed to enter the 4byte address mode, hence a better
>>>>> compatibility with some boot loaders which expect to use 3byte address
>>>>> op codes.
>>>>
>>>> The memories which are > 128Mbits should have 4-bytes addressing
>>>> support based on my experience, do you think BAR is also required
>>>> atleast from spi-nor side?
>>>
>>> Yes, I believe BAR is still required for broken/dumb flash chips.
>>> Not all chips > 16 MiB support dedicated 4-byte addressing opcodes :-(
>>
>> Do you have list for those broken chips? because I never find any
>> chips which has > 16 MiB with not support of 4-byte address opcodes
>> and I've seen the controller has dependable with BAR though it can
>> access > 16MiB ex: zynq qspi/
>>
>> thanks!
>>
> 
> Let's take the case of Micron n25q256* memories. Depending of the part number,
> the 12h op code is associated with either 4-byte address Page Program 1-1-1
> or 3-byte address Page Program 1-4-4.
> Then considering parts where the 12h op code is used for 3-byte address Page
> Program 1-4-4, there is no op code for a 4-byte address Page Program 1-1-1.
> 
> Note 15, extracted from the Micron n25q_256mb_3v_65nm.pdf datasheet, about
> the 3-byte address Page Program 1-4-4 (Extended Quad Input Fast Program):
> The code 38h is valid only for part numbers N25Q256A83ESF40x, N25Q256A83E1240x
> and N25Q256A83ESFA0F; the code 12h is valid for the other part numbers.
> 
> Hence most of the Micron n25q256* memories has no op code for 4-byte address
> Page Program 1-1-1.
> Then we could use the 34h op code instead to perform 4-byte address Page
> Program 1-1-4 but some SPI controllers might not support the SPI 1-1-4 protocol
> for Page Program operations. Sp entering the 4-byte address mode or using
> the BAR might still be the only solutions in those cases.
> 
> Also, I'm pretty sure some other SPI NOR memories support 4-byte address Fast
> Read op codes but only 3-byte address op codes for Page Program and Sector
> Erase. I will look at the datasheets I have to find and provide an example.
> 
>

Even worse, let's take the example for Macronix MX25L25635* and MX25L25673*:
they both share the very same JEDEC ID. The older part (35) doesn't support
the 4-byte address instruction set at all whereas the newer part (73) does.

> Best regards,
> 
> Cyrille
> 



From richard at nod.at  Mon Oct 24 07:39:28 2016
From: richard at nod.at (Richard Weinberger)
Date: Mon, 24 Oct 2016 16:39:28 +0200
Subject: [PATCH] MAINTAINERS: add more people to the MTD maintainer team
In-Reply-To: <1477312526-7563-1-git-send-email-boris.brezillon@free-electrons.com>
References: <1477312526-7563-1-git-send-email-boris.brezillon@free-electrons.com>
Message-ID: <b4ddcef0-d8c2-e1b4-6c46-e8f0d96d9cdd@nod.at>

Boris,

On 24.10.2016 14:35, Boris Brezillon wrote:
> Brian has been maintaining the MTD subsystem alone for several years
> now, and maintaining such a subsystem can really be time consuming.
> 
> Create a maintainer team formed of the most active MTD contributors
> to help Brian with this task, which will hopefully improve the
> subsystem reactivity.
> 
> Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
> ---
> Hi all,
> 
> I'm just trying to summarize what I understood the process would be,
> don't hesitate to correct me if I'm wrong.
> 
> For each release we will assign a specific MTD maintainer which will be
> responsible for taking MTD core patches and pulling spi-nor and nand PRs
> into the MTD tree and eventually send one or several PRs to Linus.
> 
> For fixes that are submitted after -rc1, I usually ask Brian to apply
> them directly into the MTD tree (I don't think there's a real need to
> prepare spi-nor and nand PRs for fixes), so we can proceed the same
> way: ask the maintainer assigned to this release to also take care of
> applying fixes and sending PRs to Linus before each -rc.
> 
> If you have other ideas, or would like to proceed differently, don't
> hesitate propose them.

Sounds good to me.
Acked-by: Richard Weinberger <richard at nod.at>

Thanks,
//richard


From boris.brezillon at free-electrons.com  Mon Oct 24 07:46:20 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Mon, 24 Oct 2016 16:46:20 +0200
Subject: [PATCH] mtd: nand: Fix data interface configuration logic
Message-ID: <1477320380-11062-1-git-send-email-boris.brezillon@free-electrons.com>

When changing from one data interface setting to another, one has to
ensure a specific sequence which is described in the ONFI spec.

One of these constraints is that the CE line has go high after a reset
before a command can be sent with the new data interface setting, which
is not guaranteed by the current implementation.

Rework the nand_reset() function and all the call sites to make sure the
CE line is asserted and released when required.

Also make sure to actually apply the new data interface setting on the
first die.

Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
Fixes: d8e725dd8311 ("mtd: nand: automate NAND timings selection")
---
 drivers/mtd/nand/nand_base.c | 60 +++++++++++++++++++++++++++++++-------------
 include/linux/mtd/nand.h     |  2 +-
 2 files changed, 43 insertions(+), 19 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index e5718e5ecf92..3bde96a3f7bf 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1095,10 +1095,11 @@ static void nand_release_data_interface(struct nand_chip *chip)
 /**
  * nand_reset - Reset and initialize a NAND device
  * @chip: The NAND chip
+ * @chipnr: Internal die id
  *
  * Returns 0 for success or negative error code otherwise
  */
-int nand_reset(struct nand_chip *chip)
+int nand_reset(struct nand_chip *chip, int chipnr)
 {
 	struct mtd_info *mtd = nand_to_mtd(chip);
 	int ret;
@@ -1107,9 +1108,17 @@ int nand_reset(struct nand_chip *chip)
 	if (ret)
 		return ret;
 
+	/*
+	 * The CS line has to be released before we can apply the new NAND
+	 * interface settings, hence this weird ->select_chip() dance.
+	 */
+	chip->select_chip(mtd, chipnr);
 	chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+	chip->select_chip(mtd, -1);
 
+	chip->select_chip(mtd, chipnr);
 	ret = nand_setup_data_interface(chip);
+	chip->select_chip(mtd, -1);
 	if (ret)
 		return ret;
 
@@ -1185,8 +1194,6 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 	/* Shift to get chip number */
 	chipnr = ofs >> chip->chip_shift;
 
-	chip->select_chip(mtd, chipnr);
-
 	/*
 	 * Reset the chip.
 	 * If we want to check the WP through READ STATUS and check the bit 7
@@ -1194,7 +1201,9 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 	 * some operation can also clear the bit 7 of status register
 	 * eg. erase/program a locked block
 	 */
-	nand_reset(chip);
+	nand_reset(chip, chipnr);
+
+	chip->select_chip(mtd, chipnr);
 
 	/* Check, if it is write protected */
 	if (nand_check_wp(mtd)) {
@@ -1244,8 +1253,6 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 	/* Shift to get chip number */
 	chipnr = ofs >> chip->chip_shift;
 
-	chip->select_chip(mtd, chipnr);
-
 	/*
 	 * Reset the chip.
 	 * If we want to check the WP through READ STATUS and check the bit 7
@@ -1253,7 +1260,9 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 	 * some operation can also clear the bit 7 of status register
 	 * eg. erase/program a locked block
 	 */
-	nand_reset(chip);
+	nand_reset(chip, chipnr);
+
+	chip->select_chip(mtd, chipnr);
 
 	/* Check, if it is write protected */
 	if (nand_check_wp(mtd)) {
@@ -2940,10 +2949,6 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
 	}
 
 	chipnr = (int)(to >> chip->chip_shift);
-	chip->select_chip(mtd, chipnr);
-
-	/* Shift to get page */
-	page = (int)(to >> chip->page_shift);
 
 	/*
 	 * Reset the chip. Some chips (like the Toshiba TC5832DC found in one
@@ -2951,7 +2956,12 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
 	 * if we don't do this. I have no clue why, but I seem to have 'fixed'
 	 * it in the doc2000 driver in August 1999.  dwmw2.
 	 */
-	nand_reset(chip);
+	nand_reset(chip, chipnr);
+
+	chip->select_chip(mtd, chipnr);
+
+	/* Shift to get page */
+	page = (int)(to >> chip->page_shift);
 
 	/* Check, if it is write protected */
 	if (nand_check_wp(mtd)) {
@@ -3984,14 +3994,14 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
 	int i, maf_idx;
 	u8 id_data[8];
 
-	/* Select the device */
-	chip->select_chip(mtd, 0);
-
 	/*
 	 * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
 	 * after power-up.
 	 */
-	nand_reset(chip);
+	nand_reset(chip, 0);
+
+	/* Select the device */
+	chip->select_chip(mtd, 0);
 
 	/* Send the command for reading device ID */
 	chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
@@ -4329,17 +4339,31 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
 		return PTR_ERR(type);
 	}
 
+	/* Initialize the ->data_interface field. */
 	ret = nand_init_data_interface(chip);
 	if (ret)
 		return ret;
 
+	/*
+	 * Setup the data interface correctly on the chip and controller side.
+	 * This explicit call to nand_setup_data_interface() is only required
+	 * for the first die, because nand_reset() has been called before
+	 * ->data_interface and ->default_onfi_timing_mode were set.
+	 * For the other dies, nand_reset() will automatically switch to the
+	 * best mode for us.
+	 */
+	ret = nand_setup_data_interface(chip);
+	if (ret)
+		return ret;
+
 	chip->select_chip(mtd, -1);
 
 	/* Check for a chip array */
 	for (i = 1; i < maxchips; i++) {
-		chip->select_chip(mtd, i);
 		/* See comment in nand_get_flash_type for reset */
-		nand_reset(chip);
+		nand_reset(chip, i);
+
+		chip->select_chip(mtd, i);
 		/* Send the command for reading device ID */
 		chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
 		/* Read manufacturer and device IDs */
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index c5d3d5024fc8..d8905a229f34 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -1184,7 +1184,7 @@ int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
 			   int page);
 
 /* Reset and initialize a NAND device */
-int nand_reset(struct nand_chip *chip);
+int nand_reset(struct nand_chip *chip, int chipnr);
 
 /* Free resources held by the NAND device */
 void nand_cleanup(struct nand_chip *chip);
-- 
2.7.4



From xhnjupt at gmail.com  Mon Oct 24 07:49:29 2016
From: xhnjupt at gmail.com (Han Xu)
Date: Mon, 24 Oct 2016 22:49:29 +0800
Subject: [PATCH] mtd: nand: gpmi: disable the clocks on errors
In-Reply-To: <73e38ebd-3612-94c3-46bf-dc6e29925ee3@gmail.com>
References: <1477152922-6722-1-git-send-email-festevam@gmail.com>
 <73e38ebd-3612-94c3-46bf-dc6e29925ee3@gmail.com>
Message-ID: <20161024144929.GA31816@shlinux2>

On Sun, Oct 23, 2016 at 05:08:19AM +0200, Marek Vasut wrote:
> On 10/22/2016 06:15 PM, Fabio Estevam wrote:
> > From: Fabio Estevam <fabio.estevam at nxp.com>
> > 
> > We should disable the previously enabled GPMI clocks in the error paths.
> > 
> > Also, when gpmi_enable_clk() fails simply return the error
> > code immediately rather than jumping to to the 'err_out' label.
> > 
> > Signed-off-by: Fabio Estevam <fabio.estevam at nxp.com>
> 
> Reviewed-by: Marek Vasut <marex at denx.de>
> 

Acked-by: Han Xu<han.xu at nxp.com>

> > ---
> >  drivers/mtd/nand/gpmi-nand/gpmi-lib.c | 6 ++++--
> >  1 file changed, 4 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
> > index 0f68a99..141bd70 100644
> > --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
> > +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
> > @@ -161,7 +161,7 @@ int gpmi_init(struct gpmi_nand_data *this)
> >  
> >  	ret = gpmi_enable_clk(this);
> >  	if (ret)
> > -		goto err_out;
> > +		return ret;
> >  	ret = gpmi_reset_block(r->gpmi_regs, false);
> >  	if (ret)
> >  		goto err_out;
> > @@ -197,6 +197,7 @@ int gpmi_init(struct gpmi_nand_data *this)
> >  	gpmi_disable_clk(this);
> >  	return 0;
> >  err_out:
> > +	gpmi_disable_clk(this);
> >  	return ret;
> >  }
> >  
> > @@ -270,7 +271,7 @@ int bch_set_geometry(struct gpmi_nand_data *this)
> >  
> >  	ret = gpmi_enable_clk(this);
> >  	if (ret)
> > -		goto err_out;
> > +		return ret;
> >  
> >  	/*
> >  	* Due to erratum #2847 of the MX23, the BCH cannot be soft reset on this
> > @@ -308,6 +309,7 @@ int bch_set_geometry(struct gpmi_nand_data *this)
> >  	gpmi_disable_clk(this);
> >  	return 0;
> >  err_out:
> > +	gpmi_disable_clk(this);
> >  	return ret;
> >  }
> >  
> > 
> 
> 
> -- 
> Best regards,
> Marek Vasut
> 
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/


From boris.brezillon at free-electrons.com  Mon Oct 24 08:10:26 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Mon, 24 Oct 2016 17:10:26 +0200
Subject: [PATCH v6 4/4] mtd: nand: tango: import driver for tango chips
In-Reply-To: <580E04B4.7040102@sigmadesigns.com>
References: <580E0318.5020004@sigmadesigns.com>
 <580E04B4.7040102@sigmadesigns.com>
Message-ID: <20161024171026.710d0f6a@bbrezillon>

Hi Marc,

On Mon, 24 Oct 2016 14:55:16 +0200
Marc Gonzalez <marc_gonzalez at sigmadesigns.com> wrote:

> This driver supports the NAND Flash controller embedded in recent
> Tango chips, such as SMP8758 and SMP8759.

A few comments below (most of them are about coding style).

> 
> Signed-off-by: Marc Gonzalez <marc_gonzalez at sigmadesigns.com>
> ---
>  drivers/mtd/nand/Kconfig      |   6 +
>  drivers/mtd/nand/Makefile     |   1 +
>  drivers/mtd/nand/tango_nand.c | 654 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 661 insertions(+)
>  create mode 100644 drivers/mtd/nand/tango_nand.c
> 
> diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
> index 7b7a887b4709..844ab20a23a4 100644
> --- a/drivers/mtd/nand/Kconfig
> +++ b/drivers/mtd/nand/Kconfig
> @@ -205,6 +205,12 @@ config MTD_NAND_S3C2410_CLKSTOP
>  	  when the is NAND chip selected or released, but will save
>  	  approximately 5mA of power when there is nothing happening.
>  
> +config MTD_NAND_TANGO
> +	tristate "NAND Flash support for Tango chips"
> +	depends on ARCH_TANGO
> +	help
> +	  Enables the NAND Flash controller on Tango chips.
> +
>  config MTD_NAND_DISKONCHIP
>  	tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation)"
>  	depends on HAS_IOMEM
> diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
> index cafde6f3d957..4904ad3614fb 100644
> --- a/drivers/mtd/nand/Makefile
> +++ b/drivers/mtd/nand/Makefile
> @@ -16,6 +16,7 @@ obj-$(CONFIG_MTD_NAND_DENALI_DT)	+= denali_dt.o
>  obj-$(CONFIG_MTD_NAND_AU1550)		+= au1550nd.o
>  obj-$(CONFIG_MTD_NAND_BF5XX)		+= bf5xx_nand.o
>  obj-$(CONFIG_MTD_NAND_S3C2410)		+= s3c2410.o
> +obj-$(CONFIG_MTD_NAND_TANGO)		+= tango_nand.o
>  obj-$(CONFIG_MTD_NAND_DAVINCI)		+= davinci_nand.o
>  obj-$(CONFIG_MTD_NAND_DISKONCHIP)	+= diskonchip.o
>  obj-$(CONFIG_MTD_NAND_DOCG4)		+= docg4.o
> diff --git a/drivers/mtd/nand/tango_nand.c b/drivers/mtd/nand/tango_nand.c
> new file mode 100644
> index 000000000000..375ca8e4a3aa
> --- /dev/null
> +++ b/drivers/mtd/nand/tango_nand.c
> @@ -0,0 +1,654 @@
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include <linux/clk.h>
> +#include <linux/iopoll.h>
> +#include <linux/module.h>
> +#include <linux/mtd/nand.h>
> +#include <linux/dmaengine.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/platform_device.h>
> +
> +/* Offsets relative to chip->base */
> +#define PBUS_CMD	0
> +#define PBUS_ADDR	4
> +#define PBUS_DATA	8
> +
> +/* Offsets relative to reg_base */
> +#define NFC_STATUS	0x00
> +#define NFC_FLASH_CMD	0x04
> +#define NFC_DEVICE_CFG	0x08
> +#define NFC_TIMING1	0x0c
> +#define NFC_TIMING2	0x10
> +#define NFC_XFER_CFG	0x14
> +#define NFC_PKT_0_CFG	0x18
> +#define NFC_PKT_N_CFG	0x1c
> +#define NFC_BB_CFG	0x20
> +#define NFC_ADDR_PAGE	0x24
> +#define NFC_ADDR_OFFSET	0x28
> +#define NFC_XFER_STATUS	0x2c
> +
> +/* NFC_STATUS values */
> +#define CMD_READY	BIT(31)
> +
> +/* NFC_FLASH_CMD values */
> +#define NFC_READ	1
> +#define NFC_WRITE	2
> +
> +/* NFC_XFER_STATUS values */
> +#define PAGE_IS_EMPTY	BIT(16)
> +
> +/* Offsets relative to mem_base */
> +#define METADATA	0x000
> +#define ERROR_REPORT	0x1c0
> +
> +/*
> + * Error reports are split in two bytes:
> + * byte 0 for the first packet in the page (PKT_0)
> + * byte 1 for other packets in the page (PKT_N, for N > 0)
> + * ERR_COUNT_PKT_N is the max error count over all but the first packet.
> + */
> +#define DECODE_OK_PKT_0(v)	(v & BIT(7))
> +#define DECODE_OK_PKT_N(v)	(v & BIT(15))
> +#define ERR_COUNT_PKT_0(v)	((v >> 0) & 0x3f)
> +#define ERR_COUNT_PKT_N(v)	((v >> 8) & 0x3f)
> +
> +/* Offsets relative to pbus_base */
> +#define PBUS_CS_CTRL	0x83c
> +#define PBUS_PAD_MODE	0x8f0
> +
> +/* PBUS_CS_CTRL values */
> +#define PBUS_IORDY	BIT(31)
> +
> +/*
> + * PBUS_PAD_MODE values
> + * In raw mode, the driver communicates directly with the NAND chips.
> + * In NFC mode, the NAND Flash controller manages the communication.
> + * We use NFC mode for read and write; raw mode for everything else.
> + */
> +#define MODE_RAW	0
> +#define MODE_NFC	BIT(31)
> +
> +#define METADATA_SIZE	4
> +#define BBM_SIZE	6
> +#define FIELD_ORDER	15
> +
> +#define MAX_CS		4
> +
> +struct tango_nfc {
> +	struct nand_hw_control hw;
> +	void __iomem *reg_base;
> +	void __iomem *mem_base;
> +	void __iomem *pbus_base;
> +	struct tango_chip *chips[MAX_CS];
> +	struct dma_chan *chan;
> +	int freq_kHz;
> +};
> +
> +#define to_tango_nfc(ptr) container_of(ptr, struct tango_nfc, hw)
> +
> +struct tango_chip {
> +	struct nand_chip nand_chip;
> +	void __iomem *base;
> +	u32 timing1;
> +	u32 timing2;
> +	u32 xfer_cfg;
> +	u32 pkt_0_cfg;
> +	u32 pkt_n_cfg;
> +	u32 bb_cfg;
> +};
> +
> +#define to_tango_chip(ptr) container_of(ptr, struct tango_chip, nand_chip)
> +
> +#define XFER_CFG(cs, page_count, steps, metadata_size)	\
> +	((cs) << 24 | (page_count) << 16 | (steps) << 8 | (metadata_size) << 0)
> +
> +#define PKT_CFG(size, strength) ((size) << 16 | (strength) << 0)
> +
> +#define BB_CFG(bb_offset, bb_size) ((bb_offset) << 16 | (bb_size) << 0)
> +
> +#define TIMING(t0, t1, t2, t3) (t0 << 24 | t1 << 16 | t2 << 8 | t3 << 0)

Wrap tX params with parenthesis to make sure the shift operation is
applied to the correct value (for example, if t0 = a + b, then the
resulting operation will be a + (b << 24) instead of (a + b) << 24 if
you don't put those parenthesis).

> +
> +static void tango_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
> +{
> +	struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
> +
> +	if (ctrl & NAND_CLE)
> +		writeb_relaxed(dat, tchip->base + PBUS_CMD);
> +
> +	if (ctrl & NAND_ALE)
> +		writeb_relaxed(dat, tchip->base + PBUS_ADDR);
> +}
> +
> +static int tango_dev_ready(struct mtd_info *mtd)
> +{
> +	struct nand_chip *chip = mtd_to_nand(mtd);
> +	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
> +
> +	return readl_relaxed(nfc->pbus_base + PBUS_CS_CTRL) & PBUS_IORDY;
> +}
> +
> +static uint8_t tango_read_byte(struct mtd_info *mtd)
> +{
> +	struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
> +
> +	return readb_relaxed(tchip->base + PBUS_DATA);
> +}
> +
> +static void tango_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
> +{
> +	struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
> +
> +	ioread8_rep(tchip->base + PBUS_DATA, buf, len);
> +}
> +
> +static void tango_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
> +{
> +	struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
> +
> +	iowrite8_rep(tchip->base + PBUS_DATA, buf, len);
> +}
> +
> +static void tango_select_chip(struct mtd_info *mtd, int idx)
> +{
> +	struct nand_chip *chip = mtd_to_nand(mtd);
> +	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
> +	struct tango_chip *tchip = to_tango_chip(chip);
> +
> +	if (idx < 0)
> +		return; /* No "chip unselect" function */
> +
> +	writel_relaxed(tchip->timing1, nfc->reg_base + NFC_TIMING1);
> +	writel_relaxed(tchip->timing2, nfc->reg_base + NFC_TIMING2);
> +	writel_relaxed(tchip->xfer_cfg, nfc->reg_base + NFC_XFER_CFG);
> +	writel_relaxed(tchip->pkt_0_cfg, nfc->reg_base + NFC_PKT_0_CFG);
> +	writel_relaxed(tchip->pkt_n_cfg, nfc->reg_base + NFC_PKT_N_CFG);
> +	writel_relaxed(tchip->bb_cfg, nfc->reg_base + NFC_BB_CFG);
> +}
> +
> +/*
> + * The controller does not check for bitflips in erased pages,
> + * therefore software must check instead.
> + */
> +static int check_erased_page(struct nand_chip *chip, u8 *buf)
> +{
> +	u8 *meta = chip->oob_poi + BBM_SIZE;
> +	u8 *ecc = chip->oob_poi + BBM_SIZE + METADATA_SIZE;
> +	const int ecc_size = chip->ecc.bytes;
> +	const int pkt_size = chip->ecc.size;
> +	int i, res, meta_len, bitflips = 0;
> +
> +	for (i = 0; i < chip->ecc.steps; ++i)
> +	{
> +		meta_len = i ? 0 : METADATA_SIZE;
> +		res = nand_check_erased_ecc_chunk(buf, pkt_size, ecc, ecc_size,
> +				meta, meta_len, chip->ecc.strength);
> +		if (res < 0)
> +			return res;
> +
> +		bitflips = max(res, bitflips);
> +		buf += pkt_size;
> +		ecc += ecc_size;
> +	}
> +
> +	return bitflips;
> +}
> +
> +static int decode_error_report(struct tango_nfc *nfc)
> +{
> +	u32 status, res;
> +
> +	status = readl_relaxed(nfc->reg_base + NFC_XFER_STATUS);
> +	if (status & PAGE_IS_EMPTY)
> +		return 0;
> +
> +	res = readl_relaxed(nfc->mem_base + ERROR_REPORT);
> +
> +	if (DECODE_OK_PKT_0(res) && DECODE_OK_PKT_N(res))
> +		return max(ERR_COUNT_PKT_0(res), ERR_COUNT_PKT_N(res));
> +
> +	return -EBADMSG;
> +}
> +
> +static void tango_dma_callback(void *arg)
> +{
> +	complete(arg);
> +}
> +
> +static int do_dma(struct tango_nfc *nfc, int dir, int cmd,
> +		const void *buf, int len, int page)
> +{
> +	struct dma_chan *chan = nfc->chan;
> +	struct dma_async_tx_descriptor *desc;
> +	struct scatterlist sg;
> +	struct completion tx_done;
> +	int err = -EIO;
> +	u32 res, val;
> +
> +	sg_init_one(&sg, buf, len);
> +	if (dma_map_sg(chan->device->dev, &sg, 1, dir) != 1)
> +		return -EIO;
> +
> +	desc = dmaengine_prep_slave_sg(chan, &sg, 1, dir, DMA_PREP_INTERRUPT);
> +	if (!desc)
> +		goto dma_unmap;
> +
> +	desc->callback = tango_dma_callback;
> +	desc->callback_param = &tx_done;
> +	init_completion(&tx_done);
> +
> +	writel_relaxed(MODE_NFC, nfc->pbus_base + PBUS_PAD_MODE);
> +
> +	writel_relaxed(page, nfc->reg_base + NFC_ADDR_PAGE);
> +	writel_relaxed(   0, nfc->reg_base + NFC_ADDR_OFFSET);
> +	writel_relaxed( cmd, nfc->reg_base + NFC_FLASH_CMD);

A vestige of you weird alignment policy ;). Please fix that.

> +
> +	dmaengine_submit(desc);
> +	dma_async_issue_pending(chan);
> +
> +	res = wait_for_completion_timeout(&tx_done, HZ);
> +	if (res > 0) {
> +		void __iomem *addr = nfc->reg_base + NFC_STATUS;
> +		err = readl_poll_timeout(addr, val, val & CMD_READY, 0, 1000);
> +	}

I'd still prefer:

	if (res > 0)
		err = readl_poll_timeout(addr, val, val & CMD_READY, 0,
					 1000);

> +
> +	writel_relaxed(MODE_RAW, nfc->pbus_base + PBUS_PAD_MODE);
> +
> +dma_unmap:
> +	dma_unmap_sg(chan->device->dev, &sg, 1, dir);
> +
> +	return err;
> +}
> +
> +static int tango_read_page(struct mtd_info *mtd, struct nand_chip *chip,
> +		uint8_t *buf, int oob_required, int page)
> +{
> +	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
> +	int err, res, len = mtd->writesize;
> +
> +	if (oob_required)
> +		chip->ecc.read_oob(mtd, chip, page);
> +
> +	err = do_dma(nfc, DMA_FROM_DEVICE, NFC_READ, buf, len, page);
> +	if (err)
> +		return err;
> +
> +	res = decode_error_report(nfc);
> +	if (res < 0) {
> +		chip->ecc.read_oob_raw(mtd, chip, page);
> +		res = check_erased_page(chip, buf);
> +	}

You should not return an error, when the ECC engine detected
uncorrectable errors. You should just increment ecc->failed.

> +
> +	return res;
> +}
> +
> +static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip,
> +		const uint8_t *buf, int oob_required, int page)
> +{
> +	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
> +	int err, len = mtd->writesize;
> +
> +	writel_relaxed(0xffffffff, nfc->mem_base + METADATA);
> +	err = do_dma(nfc, DMA_TO_DEVICE, NFC_WRITE, buf, len, page);
> +	if (err)
> +		return err;
> +
> +	if (oob_required)
> +		return -ENOTSUPP; /* Sending PAGEPROG twice is forbidden */

Please put the comment before the oob_required test.
You should probably test that before lauching the DMA transfer.

> +
> +	return 0;
> +}
> +
> +static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos)
> +{
> +	*pos += len;
> +
> +	if (*buf == NULL) /* skip over len bytes */
> +		chip->cmdfunc(&chip->mtd, NAND_CMD_RNDOUT, *pos, -1);
> +	else {
> +		tango_read_buf(&chip->mtd, *buf, len);
> +		*buf += len;
> +	}

	if (*buf == NULL) {
		/* skip over len bytes */
		chip->cmdfunc(&chip->mtd, NAND_CMD_RNDOUT, *pos, -1);
	} else {
		tango_read_buf(&chip->mtd, *buf, len);
		*buf += len;
	}

> +}
> +
> +static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos)
> +{
> +	*pos += len;
> +
> +	if (*buf == NULL) /* skip over len bytes */
> +		chip->cmdfunc(&chip->mtd, NAND_CMD_SEQIN, *pos, -1);
> +	else {
> +		tango_write_buf(&chip->mtd, *buf, len);
> +		*buf += len;
> +	}

Ditto.

> +}
> +
> +/*
> + * Physical page layout (not drawn to scale)
> + *
> + * NB: Bad Block Marker area splits PKT_N in two (N1, N2).
> + *
> + * +---+-----------------+-------+-----+-----------+-----+----+-------+
> + * | M |      PKT_0      | ECC_0 | ... |     N1    | BBM | N2 | ECC_N |
> + * +---+-----------------+-------+-----+-----------+-----+----+-------+
> + *
> + * Logical page layout:
> + *
> + *       +-----+---+-------+-----+-------+
> + * oob = | BBM | M | ECC_0 | ... | ECC_N |
> + *       +-----+---+-------+-----+-------+
> + *
> + *       +-----------------+-----+-----------------+
> + * buf = |      PKT_0      | ... |      PKT_N      |
> + *       +-----------------+-----+-----------------+
> + */
> +static int raw_read(struct nand_chip *chip, u8 *buf, u8 *oob)
> +{
> +	u8 *oob_orig = oob;
> +	const int page_size = chip->mtd.writesize;
> +	const int ecc_size = chip->ecc.bytes;
> +	const int pkt_size = chip->ecc.size;
> +	int pos = 0; /* position within physical page */
> +	int rem = page_size; /* bytes remaining until BBM area */
> +
> +	if (oob != NULL)
> +		oob += BBM_SIZE;
> +
> +	aux_read(chip, &oob, METADATA_SIZE, &pos);
> +
> +	while (rem > pkt_size) {
> +		aux_read(chip, &buf, pkt_size, &pos);
> +		aux_read(chip, &oob, ecc_size, &pos);
> +		rem = page_size - pos;
> +	}
> +
> +	aux_read(chip, &buf, rem, &pos);
> +	aux_read(chip, &oob_orig, BBM_SIZE, &pos);
> +	aux_read(chip, &buf, pkt_size - rem, &pos);
> +	aux_read(chip, &oob, ecc_size, &pos);
> +
> +	return 0;
> +}
> +
> +static int raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob)
> +{
> +	const u8 *oob_orig = oob;
> +	const int page_size = chip->mtd.writesize;
> +	const int ecc_size = chip->ecc.bytes;
> +	const int pkt_size = chip->ecc.size;
> +	int pos = 0; /* position within physical page */
> +	int rem = page_size; /* bytes remaining until BBM area */
> +
> +	if (oob != NULL)
> +		oob += BBM_SIZE;
> +
> +	aux_write(chip, &oob, METADATA_SIZE, &pos);
> +
> +	while (rem > pkt_size) {
> +		aux_write(chip, &buf, pkt_size, &pos);
> +		aux_write(chip, &oob, ecc_size, &pos);
> +		rem = page_size - pos;
> +	}
> +
> +	aux_write(chip, &buf, rem, &pos);
> +	aux_write(chip, &oob_orig, BBM_SIZE, &pos);
> +	aux_write(chip, &buf, pkt_size - rem, &pos);
> +	aux_write(chip, &oob, ecc_size, &pos);
> +
> +	return 0;
> +}
> +
> +static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
> +		uint8_t *buf, int oob_required, int page)
> +{
> +	return raw_read(chip, buf, chip->oob_poi);
> +}
> +
> +static int tango_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
> +		const uint8_t *buf, int oob_required, int page)
> +{
> +	return raw_write(chip, buf, chip->oob_poi);
> +}
> +
> +static int tango_read_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
> +{
> +	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
> +	return raw_read(chip, NULL, chip->oob_poi);
> +}
> +
> +static int tango_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
> +{
> +	chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page);
> +	raw_write(chip, NULL, chip->oob_poi);
> +	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
> +	chip->waitfunc(mtd, chip);
> +	return 0;
> +}
> +
> +static int oob_ecc(struct mtd_info *mtd, int idx, struct mtd_oob_region *res)
> +{
> +	struct nand_chip *chip = mtd_to_nand(mtd);
> +	struct nand_ecc_ctrl *ecc = &chip->ecc;
> +
> +	if (idx >= ecc->steps)
> +		return -ERANGE;
> +
> +	res->offset = BBM_SIZE + METADATA_SIZE + ecc->bytes * idx;
> +	res->length = ecc->bytes;
> +
> +	return 0;
> +}
> +
> +static int oob_free(struct mtd_info *mtd, int idx, struct mtd_oob_region *res)
> +{
> +	return -ERANGE; /* no free space in spare area */
> +}
> +
> +static const struct mtd_ooblayout_ops tango_nand_ooblayout_ops = {
> +	.ecc	= oob_ecc,
> +	.free	= oob_free,
> +};
> +
> +static u32 to_ticks(int kHz, int ps)
> +{
> +	return DIV_ROUND_UP_ULL((u64)kHz * ps, NSEC_PER_SEC);
> +}
> +
> +static int tango_set_timings(struct mtd_info *mtd,
> +		const struct nand_data_interface *conf, bool check_only)
> +{
> +	const struct nand_sdr_timings *sdr = nand_get_sdr_timings(conf);
> +	struct nand_chip *chip = mtd_to_nand(mtd);
> +	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
> +	struct tango_chip *tchip = to_tango_chip(chip);
> +	u32 Trdy, Textw, Twc, Twpw, Tacc, Thold, Trpw, Textr;
> +	int kHz = nfc->freq_kHz;
> +
> +	if (IS_ERR(sdr))
> +		return PTR_ERR(sdr);
> +
> +	if (check_only)
> +		return 0;
> +
> +	Trdy = to_ticks(kHz, sdr->tCEA_max - sdr->tREA_max);
> +	Textw = to_ticks(kHz, sdr->tWB_max);
> +	Twc = to_ticks(kHz, sdr->tWC_min);
> +	Twpw = to_ticks(kHz, sdr->tWC_min - sdr->tWP_min);
> +
> +	Tacc = to_ticks(kHz, sdr->tREA_max);
> +	Thold = to_ticks(kHz, sdr->tREH_min);
> +	Trpw = to_ticks(kHz, sdr->tRC_min - sdr->tREH_min);
> +	Textr = to_ticks(kHz, sdr->tRHZ_max);
> +
> +	tchip->timing1 = TIMING(Trdy, Textw, Twc, Twpw);
> +	tchip->timing2 = TIMING(Tacc, Thold, Trpw, Textr);
> +
> +	return 0;
> +}
> +
> +static int chip_init(struct device *dev, struct device_node *np)
> +{
> +	int err, res;
> +	u32 cs, ecc_bits;
> +	struct mtd_info *mtd;
> +	struct nand_chip *chip;
> +	struct tango_chip *tchip;
> +	struct nand_ecc_ctrl *ecc;
> +	struct tango_nfc *nfc = dev_get_drvdata(dev);
> +
> +	tchip = devm_kzalloc(dev, sizeof(*tchip), GFP_KERNEL);
> +	if (!tchip)
> +		return -ENOMEM;
> +
> +	res = of_property_count_u32_elems(np, "reg");
> +	if (res < 0)
> +		return res;
> +
> +	if (res != 1)
> +		return -ENOTSUPP; /* Multi-CS chips are not supported */
> +
> +	err = of_property_read_u32_index(np, "reg", 0, &cs);
> +	if (err)
> +		return err;
> +
> +	if (cs >= MAX_CS)
> +		return -EINVAL;
> +
> +	chip = &tchip->nand_chip;
> +	ecc = &chip->ecc;
> +	mtd = &chip->mtd;
> +
> +	chip->read_byte = tango_read_byte;
> +	chip->write_buf = tango_write_buf;
> +	chip->read_buf = tango_read_buf;
> +	chip->select_chip = tango_select_chip;
> +	chip->cmd_ctrl = tango_cmd_ctrl;
> +	chip->dev_ready = tango_dev_ready;
> +	chip->setup_data_interface = tango_set_timings;
> +	chip->options = 0
> +		| NAND_USE_BOUNCE_BUFFER
> +		| NAND_NO_SUBPAGE_WRITE
> +		| NAND_WAIT_TCCS;

	chip->options = NAND_USE_BOUNCE_BUFFER |?NAND_NO_SUBPAGE_WRITE |
			NAND_WAIT_TCCS;

> +	chip->controller = &nfc->hw;
> +	tchip->base = nfc->pbus_base + (cs * 256);
> +
> +	nand_set_flash_node(chip, np);
> +	mtd_set_ooblayout(mtd, &tango_nand_ooblayout_ops);
> +	mtd->dev.parent = dev;
> +
> +	ecc->mode = NAND_ECC_HW;
> +	ecc->algo = NAND_ECC_BCH;

You only support HW ECC, so please put these two line after
nand_scan_ident(). Otherwise, the DT parsing done in nand_base.c might
override the ->mode and ->algo values.

> +
> +	err = nand_scan_ident(mtd, 1, NULL);
> +	if (err)
> +		return err;
> +
> +	ecc->read_page_raw = tango_read_page_raw;
> +	ecc->write_page_raw = tango_write_page_raw;
> +	ecc->read_page = tango_read_page;
> +	ecc->write_page = tango_write_page;
> +	ecc->read_oob = tango_read_oob;
> +	ecc->write_oob = tango_write_oob;
> +
> +	ecc_bits = ecc->strength * FIELD_ORDER;
> +	ecc->bytes = DIV_ROUND_UP(ecc_bits, BITS_PER_BYTE);
> +
> +	err = nand_scan_tail(mtd);
> +	if (err)
> +		return err;
> +
> +	tchip->xfer_cfg = XFER_CFG(cs, 1, ecc->steps, METADATA_SIZE);
> +	tchip->pkt_0_cfg = PKT_CFG(ecc->size + METADATA_SIZE, ecc->strength);
> +	tchip->pkt_n_cfg = PKT_CFG(ecc->size, ecc->strength);
> +	tchip->bb_cfg = BB_CFG(mtd->writesize, BBM_SIZE);
> +
> +	err = mtd_device_register(mtd, NULL, 0);
> +	if (err)
> +		return err;
> +
> +	nfc->chips[cs] = tchip;
> +
> +	return 0;
> +}
> +
> +static int tango_nand_remove(struct platform_device *pdev)
> +{
> +	int cs;
> +	struct tango_nfc *nfc = platform_get_drvdata(pdev);
> +
> +	dma_release_channel(nfc->chan);
> +
> +	for (cs = 0; cs < MAX_CS; ++cs)
> +		if (nfc->chips[cs] != NULL)
> +			nand_release(&nfc->chips[cs]->nand_chip.mtd);

Please add curly braces around the for loop.

> +
> +	return 0;
> +}
> +
> +static int tango_nand_probe(struct platform_device *pdev)
> +{
> +	struct clk *clk;
> +	struct resource *res;
> +	struct tango_nfc *nfc;
> +	struct device_node *np;
> +
> +	nfc = devm_kzalloc(&pdev->dev, sizeof(*nfc), GFP_KERNEL);
> +	if (!nfc)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	nfc->reg_base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(nfc->reg_base))
> +		return PTR_ERR(nfc->reg_base);
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> +	nfc->mem_base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(nfc->mem_base))
> +		return PTR_ERR(nfc->mem_base);
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
> +	nfc->pbus_base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(nfc->pbus_base))
> +		return PTR_ERR(nfc->pbus_base);
> +
> +	clk = clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(clk))
> +		return PTR_ERR(clk);
> +
> +	nfc->chan = dma_request_chan(&pdev->dev, "nfc_sbox");
> +	if (IS_ERR(nfc->chan))
> +		return PTR_ERR(nfc->chan);
> +
> +	platform_set_drvdata(pdev, nfc);
> +	nand_hw_control_init(&nfc->hw);
> +	nfc->freq_kHz = clk_get_rate(clk) / 1000;
> +
> +	for_each_child_of_node(pdev->dev.of_node, np) {
> +		int err = chip_init(&pdev->dev, np);
> +		if (err) {
> +			tango_nand_remove(pdev);
> +			return err;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id tango_nand_ids[] = {
> +	{ .compatible = "sigma,smp8758-nand" },
> +	{ /* sentinel */ }
> +};
> +
> +static struct platform_driver tango_nand_driver = {
> +	.probe	= tango_nand_probe,
> +	.remove	= tango_nand_remove,
> +	.driver	= {
> +		.name		= "tango-nand",
> +		.of_match_table	= tango_nand_ids,
> +	},
> +};
> +
> +module_platform_driver(tango_nand_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Sigma Designs");
> +MODULE_DESCRIPTION("Tango4 NAND Flash controller driver");



From arnd at arndb.de  Mon Oct 24 08:28:35 2016
From: arnd at arndb.de (Arnd Bergmann)
Date: Mon, 24 Oct 2016 17:28:35 +0200
Subject: [PATCH] mtd: ichxrom: maybe-uninitialized with gcc-4.9
Message-ID: <20161024152853.2673518-1-arnd@arndb.de>

pci_read_config_word() might fail and not initialize its output,
as pointed out by older versions of gcc when using the -Wmaybe-unintialized
flag:

drivers/mtd/maps/ichxrom.c: In function ?ichxrom_cleanup?:
drivers/mtd/maps/ichxrom.c:63:2: error: ?word? is used uninitialized in this function [-Werror=uninitialized]

This is apparently a correct warning, though it does not show up
with newer compilers. Changing the code to not attempt to write
back uninitialized data into PCI config space is a correct
fix for the problem and avoids the warning.

Signed-off-by: Arnd Bergmann <arnd at arndb.de>
---
 drivers/mtd/maps/ichxrom.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c
index e17d02ae03f0..976d42f63aef 100644
--- a/drivers/mtd/maps/ichxrom.c
+++ b/drivers/mtd/maps/ichxrom.c
@@ -57,10 +57,12 @@ static void ichxrom_cleanup(struct ichxrom_window *window)
 {
 	struct ichxrom_map_info *map, *scratch;
 	u16 word;
+	int ret;
 
 	/* Disable writes through the rom window */
-	pci_read_config_word(window->pdev, BIOS_CNTL, &word);
-	pci_write_config_word(window->pdev, BIOS_CNTL, word & ~1);
+	ret = pci_read_config_word(window->pdev, BIOS_CNTL, &word);
+	if (!ret)
+		pci_write_config_word(window->pdev, BIOS_CNTL, word & ~1);
 	pci_dev_put(window->pdev);
 
 	/* Free all of the mtd devices */
-- 
2.9.0



From cyrille.pitchen at atmel.com  Mon Oct 24 09:34:37 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Mon, 24 Oct 2016 18:34:37 +0200
Subject: [PATCH v3 0/9] mtd: spi-nor: parse SFDP tables to setup (Q)SPI
 memories
Message-ID: <cover.1477325128.git.cyrille.pitchen@atmel.com>

Hi all,

This series extends support of SPI protocols to new protocols such as
SPI x-2-2 and SPI x-4-4. Also spi_nor_scan() tries now to select the right
op codes, timing parameters (number of mode and dummy cycles) and erase
sector size by parsing the Serial Flash Discoverable Parameter (SFDP)
tables, when available, as defined in the JEDEC JESD216 specifications.

When SFDP tables are not available, legacy settings are still used for
backward compatibility (SPI and earlier QSPI memories).

Support of SPI memories >128Mbits is also improved by using the 4byte
address instruction set, when available. Using those dedicated op codes
is stateless as opposed to enter the 4byte address mode, hence a better
compatibility with some boot loaders which expect to use 3byte address
op codes.


This series was tested on a Atmel sama5d2 xplained board with the
atmel-qspi.c driver. Except for SST memories, the SPI bus clock was set
to 83MHz. The config MTD_SPI_NOR_USE_4K_SECTORS was selected.

For my tests, I used some shell scripts using mtd_debug and sha1sum to
check the data integrity.

e.g:
#!/bin/sh

mtd_debug erase /dev/mtd5 0 0x780000
mtd_debug write /dev/mtd5 0 7674703 sama5d4_doc11238.pdf
mtd_debug read /dev/mtd5 0 7674703 sama5d4_tmp.pdf

sha1sum sama5d4_doc11238.pdf sama5d4_tmp.pdf


Depending on the actual memory size, I may have used other partitions
(/dev/mtd4) and input file size (2880044 and 320044 bytes).


The series was tested with the following QSPI memories:

Spansion/Cypress:
- s25fl127s	OK
- s25fl512s	OK
- s25fl164k	OK

Micron:
- n25q128a	OK
- n25q512	OK
- n25q01g	OK

Macronix:
- mx25v1635f	OK
- mx25l3235f	OK
- mx25l3273f	OK
- mx25l6433f	OK
- mx25l6473f	OK
- mx25l12835f	OK
- mx25l12845g	OK
- mx25l12873g	OK
- mx25l25645g	OK
- mx25l25673g	OK
- mx25l51245g	OK
- mx66l1g45g	OK (1)

SST:
- sst26vf016b	OK (2)
- sst26vf032b	OK (2)
- sst26vf064b	OK (2)

(1): requires patch 8
(2): requires patch 9, the SPI bus clock frequency was decreased down to 55.3MHz


Best regards,

Cyrille

ChangeLog:

v2 -> v3
- tested with new samples: Micron n25q512, n25q01g and Macronix
  mx25v1635f, mx25l3235f, mx25l3273f.
- add "Reviewed-by: Jagan Teki <jagan at openedev.com>" on patch 1.
- add "Tested-by: Vignesh R <vigneshr at ti.com>" on patch 2.
- fix some checkpatch warnings.
- add call of spi_nor_wait_till_ready() in spansion_new_quad_enable() 
  and sr2_bit7_quad_enable(), as suggested by Joel Esponde on patch 6.
- test JESD216 rev A (minor 5) instead of rev B (minor 6) with the return
  code of spi_nor_parse_sfdp() from spi_nor_init_params() on patch 6.
  The seven additional DWORDs of the Basic Flash Parameter Table were
  introduced in rev A, not rev B, so the 15th DWORD was already available
  in rev A. The 15th DWORD provides us with the Quad Enable Requirements
  (QER) bits.
  Basic Flash Parameter Table size:
  + JESD216 :  9 DWORDS
  + JESD216A: 16 DWORDS
  + JESD216B: 16 DWORDS

v1 -> v2
- fix patch 3 to resolve compiler errors on hisi-sfc.c and cadence-quadspi.c
  drivers


Cyrille Pitchen (9):
  mtd: spi-nor: improve macronix_quad_enable()
  mtd: spi-nor: add an alternative method to support memory >16MiB
  mtd: spi-nor: add support of SPI protocols like SPI 1-2-2 and SPI
    1-4-4
  mtd: spi-nor: remove unused set_quad_mode() function
  mtd: m25p80: add support of dual and quad spi protocols to all
    commands
  mtd: spi-nor: parse Serial Flash Discoverable Parameters (SFDP) tables
  mtd: spi-nor: parse SFDP 4-byte Address Instruction Table
  mtd: spi-nor: add support to Macronix mx66l1g45g
  mtd: spi-nor: add support to SST sst26* QSPI memories

 drivers/mtd/devices/m25p80.c            |  204 ++++--
 drivers/mtd/devices/serial_flash_cmds.h |    7 -
 drivers/mtd/devices/st_spi_fsm.c        |   28 +-
 drivers/mtd/spi-nor/atmel-quadspi.c     |   83 ++-
 drivers/mtd/spi-nor/cadence-quadspi.c   |   18 +-
 drivers/mtd/spi-nor/fsl-quadspi.c       |    8 +-
 drivers/mtd/spi-nor/hisi-sfc.c          |   32 +-
 drivers/mtd/spi-nor/mtk-quadspi.c       |   16 +-
 drivers/mtd/spi-nor/nxp-spifi.c         |   21 +-
 drivers/mtd/spi-nor/spi-nor.c           | 1026 ++++++++++++++++++++++++++++---
 include/linux/mtd/spi-nor.h             |  165 ++++-
 11 files changed, 1372 insertions(+), 236 deletions(-)

-- 
2.7.4



From cyrille.pitchen at atmel.com  Mon Oct 24 09:34:38 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Mon, 24 Oct 2016 18:34:38 +0200
Subject: [PATCH v3 1/9] mtd: spi-nor: improve macronix_quad_enable()
In-Reply-To: <cover.1477325128.git.cyrille.pitchen@atmel.com>
References: <cover.1477325128.git.cyrille.pitchen@atmel.com>
Message-ID: <c63d3715903e640c7ea5328614bd4468688b761d.1477325128.git.cyrille.pitchen@atmel.com>

The patch checks whether the Quad Enable bit is already set in the Status
Register. If so, the function exits immediately with a successful return
code. Otherwise, a message is now printed telling we're setting the
non-volatile bit.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
Reviewed-by: Jagan Teki <jagan at openedev.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index d0fc165d7d66..5c87b2d99507 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1211,6 +1211,11 @@ static int macronix_quad_enable(struct spi_nor *nor)
 	val = read_sr(nor);
 	if (val < 0)
 		return val;
+	if (val & SR_QUAD_EN_MX)
+		return 0;
+
+	/* Update the Quad Enable bit. */
+	dev_info(nor->dev, "setting Macronix Quad Enable (non-volatile) bit\n");
 	write_enable(nor);
 
 	write_sr(nor, val | SR_QUAD_EN_MX);
-- 
2.7.4



From cyrille.pitchen at atmel.com  Mon Oct 24 09:34:39 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Mon, 24 Oct 2016 18:34:39 +0200
Subject: [PATCH v3 2/9] mtd: spi-nor: add an alternative method to support
 memory >16MiB
In-Reply-To: <cover.1477325128.git.cyrille.pitchen@atmel.com>
References: <cover.1477325128.git.cyrille.pitchen@atmel.com>
Message-ID: <87ace1a307f4d9899a84108de999a2eeb151da1a.1477325128.git.cyrille.pitchen@atmel.com>

This patch provides an alternative mean to support memory above 16MiB
(128Mib) by replacing 3byte address op codes by their associated 4byte
address versions.

Using the dedicated 4byte address op codes doesn't change the internal
state of the SPI NOR memory as opposed to using other means such as
updating a Base Address Register (BAR) and sending command to enter/leave
the 4byte mode.

Hence when a CPU reset occurs, early bootloaders don't need to be aware
of BAR value or 4byte mode being enabled: they can still access the first
16MiB of the SPI NOR memory using the regular 3byte address op codes.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
Tested-by: Vignesh R <vigneshr at ti.com>
---
 drivers/mtd/devices/serial_flash_cmds.h |   7 ---
 drivers/mtd/devices/st_spi_fsm.c        |  28 ++++-----
 drivers/mtd/spi-nor/spi-nor.c           | 104 +++++++++++++++++++++++++-------
 include/linux/mtd/spi-nor.h             |  22 +++++--
 4 files changed, 113 insertions(+), 48 deletions(-)

diff --git a/drivers/mtd/devices/serial_flash_cmds.h b/drivers/mtd/devices/serial_flash_cmds.h
index f59a125295d0..8b81e15105dd 100644
--- a/drivers/mtd/devices/serial_flash_cmds.h
+++ b/drivers/mtd/devices/serial_flash_cmds.h
@@ -18,19 +18,12 @@
 #define SPINOR_OP_RDVCR		0x85
 
 /* JEDEC Standard - Serial Flash Discoverable Parmeters (SFDP) Commands */
-#define SPINOR_OP_READ_1_2_2	0xbb	/* DUAL I/O READ */
-#define SPINOR_OP_READ_1_4_4	0xeb	/* QUAD I/O READ */
-
 #define SPINOR_OP_WRITE		0x02	/* PAGE PROGRAM */
 #define SPINOR_OP_WRITE_1_1_2	0xa2	/* DUAL INPUT PROGRAM */
 #define SPINOR_OP_WRITE_1_2_2	0xd2	/* DUAL INPUT EXT PROGRAM */
 #define SPINOR_OP_WRITE_1_1_4	0x32	/* QUAD INPUT PROGRAM */
 #define SPINOR_OP_WRITE_1_4_4	0x12	/* QUAD INPUT EXT PROGRAM */
 
-/* READ commands with 32-bit addressing */
-#define SPINOR_OP_READ4_1_2_2	0xbc
-#define SPINOR_OP_READ4_1_4_4	0xec
-
 /* Configuration flags */
 #define FLASH_FLAG_SINGLE	0x000000ff
 #define FLASH_FLAG_READ_WRITE	0x00000001
diff --git a/drivers/mtd/devices/st_spi_fsm.c b/drivers/mtd/devices/st_spi_fsm.c
index 5454b4113589..804313a33f2b 100644
--- a/drivers/mtd/devices/st_spi_fsm.c
+++ b/drivers/mtd/devices/st_spi_fsm.c
@@ -507,13 +507,13 @@ static struct seq_rw_config n25q_read3_configs[] = {
  *	- 'FAST' variants configured for 8 dummy cycles (see note above.)
  */
 static struct seq_rw_config n25q_read4_configs[] = {
-	{FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ4_1_4_4,	0, 4, 4, 0x00, 0, 8},
-	{FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ4_1_1_4,	0, 1, 4, 0x00, 0, 8},
-	{FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ4_1_2_2,	0, 2, 2, 0x00, 0, 8},
-	{FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ4_1_1_2,	0, 1, 2, 0x00, 0, 8},
-	{FLASH_FLAG_READ_FAST,	SPINOR_OP_READ4_FAST,	0, 1, 1, 0x00, 0, 8},
-	{FLASH_FLAG_READ_WRITE, SPINOR_OP_READ4,	0, 1, 1, 0x00, 0, 0},
-	{0x00,			0,			0, 0, 0, 0x00, 0, 0},
+	{FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ_1_4_4_4B, 0, 4, 4, 0x00, 0, 8},
+	{FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ_1_1_4_4B, 0, 1, 4, 0x00, 0, 8},
+	{FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ_1_2_2_4B, 0, 2, 2, 0x00, 0, 8},
+	{FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ_1_1_2_4B, 0, 1, 2, 0x00, 0, 8},
+	{FLASH_FLAG_READ_FAST,	SPINOR_OP_READ_FAST_4B,  0, 1, 1, 0x00, 0, 8},
+	{FLASH_FLAG_READ_WRITE, SPINOR_OP_READ_4B,       0, 1, 1, 0x00, 0, 0},
+	{0x00,			0,                       0, 0, 0, 0x00, 0, 0},
 };
 
 /*
@@ -553,13 +553,13 @@ static int stfsm_mx25_en_32bit_addr_seq(struct stfsm_seq *seq)
  * entering a state that is incompatible with the SPIBoot Controller.
  */
 static struct seq_rw_config stfsm_s25fl_read4_configs[] = {
-	{FLASH_FLAG_READ_1_4_4,  SPINOR_OP_READ4_1_4_4,  0, 4, 4, 0x00, 2, 4},
-	{FLASH_FLAG_READ_1_1_4,  SPINOR_OP_READ4_1_1_4,  0, 1, 4, 0x00, 0, 8},
-	{FLASH_FLAG_READ_1_2_2,  SPINOR_OP_READ4_1_2_2,  0, 2, 2, 0x00, 4, 0},
-	{FLASH_FLAG_READ_1_1_2,  SPINOR_OP_READ4_1_1_2,  0, 1, 2, 0x00, 0, 8},
-	{FLASH_FLAG_READ_FAST,   SPINOR_OP_READ4_FAST,   0, 1, 1, 0x00, 0, 8},
-	{FLASH_FLAG_READ_WRITE,  SPINOR_OP_READ4,        0, 1, 1, 0x00, 0, 0},
-	{0x00,                   0,                      0, 0, 0, 0x00, 0, 0},
+	{FLASH_FLAG_READ_1_4_4,  SPINOR_OP_READ_1_4_4_4B,  0, 4, 4, 0x00, 2, 4},
+	{FLASH_FLAG_READ_1_1_4,  SPINOR_OP_READ_1_1_4_4B,  0, 1, 4, 0x00, 0, 8},
+	{FLASH_FLAG_READ_1_2_2,  SPINOR_OP_READ_1_2_2_4B,  0, 2, 2, 0x00, 4, 0},
+	{FLASH_FLAG_READ_1_1_2,  SPINOR_OP_READ_1_1_2_4B,  0, 1, 2, 0x00, 0, 8},
+	{FLASH_FLAG_READ_FAST,   SPINOR_OP_READ_FAST_4B,   0, 1, 1, 0x00, 0, 8},
+	{FLASH_FLAG_READ_WRITE,  SPINOR_OP_READ_4B,        0, 1, 1, 0x00, 0, 0},
+	{0x00,                   0,                        0, 0, 0, 0x00, 0, 0},
 };
 
 static struct seq_rw_config stfsm_s25fl_write4_configs[] = {
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 5c87b2d99507..423448c1c7a8 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -75,6 +75,10 @@ struct flash_info {
 					 * bit. Must be used with
 					 * SPI_NOR_HAS_LOCK.
 					 */
+#define SPI_NOR_4B_OPCODES	BIT(10)	/*
+					 * Use dedicated 4byte address op codes
+					 * to support memory size above 128Mib.
+					 */
 };
 
 #define JEDEC_MFR(info)	((info)->id[0])
@@ -188,6 +192,81 @@ static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd)
 	return mtd->priv;
 }
 
+
+struct spi_nor_address_entry {
+	u8	src_opcode;
+	u8	dst_opcode;
+};
+
+static u8 spi_nor_convert_opcode(u8 opcode,
+				 const struct spi_nor_address_entry *entries,
+				 size_t num_entries)
+{
+	int min, max;
+
+	min = 0;
+	max = num_entries - 1;
+	while (min <= max) {
+		int mid = (min + max) >> 1;
+		const struct spi_nor_address_entry *entry = &entries[mid];
+
+		if (opcode == entry->src_opcode)
+			return entry->dst_opcode;
+
+		if (opcode < entry->src_opcode)
+			max = mid - 1;
+		else
+			min = mid + 1;
+	}
+
+	/* No conversion found */
+	return opcode;
+}
+
+static u8 spi_nor_3to4_opcode(u8 opcode)
+{
+	/* MUST be sorted by 3byte opcode */
+#define ENTRY_3TO4(_opcode)	{ _opcode, _opcode##_4B }
+	static const struct spi_nor_address_entry spi_nor_3to4_table[] = {
+		ENTRY_3TO4(SPINOR_OP_PP),		/* 0x02 */
+		ENTRY_3TO4(SPINOR_OP_READ),		/* 0x03 */
+		ENTRY_3TO4(SPINOR_OP_READ_FAST),	/* 0x0b */
+		ENTRY_3TO4(SPINOR_OP_BE_4K),		/* 0x20 */
+		ENTRY_3TO4(SPINOR_OP_PP_1_1_4),		/* 0x32 */
+		ENTRY_3TO4(SPINOR_OP_PP_1_4_4),		/* 0x38 */
+		ENTRY_3TO4(SPINOR_OP_READ_1_1_2),	/* 0x3b */
+		ENTRY_3TO4(SPINOR_OP_BE_32K),		/* 0x52 */
+		ENTRY_3TO4(SPINOR_OP_READ_1_1_4),	/* 0x6b */
+		ENTRY_3TO4(SPINOR_OP_READ_1_2_2),	/* 0xbb */
+		ENTRY_3TO4(SPINOR_OP_SE),		/* 0xd8 */
+		ENTRY_3TO4(SPINOR_OP_READ_1_4_4),	/* 0xeb */
+	};
+#undef ENTRY_3TO4
+
+	return spi_nor_convert_opcode(opcode, spi_nor_3to4_table,
+				      ARRAY_SIZE(spi_nor_3to4_table));
+}
+
+static void spi_nor_set_4byte_opcodes(struct spi_nor *nor,
+				      const struct flash_info *info)
+{
+	/* Do some manufacturer fixups first */
+	switch (JEDEC_MFR(info)) {
+	case SNOR_MFR_SPANSION:
+		/* No small sector erase for 4-byte command set */
+		nor->erase_opcode = SPINOR_OP_SE;
+		nor->mtd.erasesize = info->sector_size;
+		break;
+
+	default:
+		break;
+	}
+
+	nor->read_opcode	= spi_nor_3to4_opcode(nor->read_opcode);
+	nor->program_opcode	= spi_nor_3to4_opcode(nor->program_opcode);
+	nor->erase_opcode	= spi_nor_3to4_opcode(nor->erase_opcode);
+}
+
 /* Enable/disable 4-byte addressing mode. */
 static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info,
 			    int enable)
@@ -1476,27 +1555,10 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 	else if (mtd->size > 0x1000000) {
 		/* enable 4-byte addressing if the device exceeds 16MiB */
 		nor->addr_width = 4;
-		if (JEDEC_MFR(info) == SNOR_MFR_SPANSION) {
-			/* Dedicated 4-byte command set */
-			switch (nor->flash_read) {
-			case SPI_NOR_QUAD:
-				nor->read_opcode = SPINOR_OP_READ4_1_1_4;
-				break;
-			case SPI_NOR_DUAL:
-				nor->read_opcode = SPINOR_OP_READ4_1_1_2;
-				break;
-			case SPI_NOR_FAST:
-				nor->read_opcode = SPINOR_OP_READ4_FAST;
-				break;
-			case SPI_NOR_NORMAL:
-				nor->read_opcode = SPINOR_OP_READ4;
-				break;
-			}
-			nor->program_opcode = SPINOR_OP_PP_4B;
-			/* No small sector erase for 4-byte command set */
-			nor->erase_opcode = SPINOR_OP_SE_4B;
-			mtd->erasesize = info->sector_size;
-		} else
+		if (JEDEC_MFR(info) == SNOR_MFR_SPANSION ||
+		    info->flags & SPI_NOR_4B_OPCODES)
+			spi_nor_set_4byte_opcodes(nor, info);
+		else
 			set_4byte(nor, info, 1);
 	} else {
 		nor->addr_width = 3;
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index c425c7b4c2a0..8b02fd7864d0 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -43,9 +43,13 @@
 #define SPINOR_OP_WRSR		0x01	/* Write status register 1 byte */
 #define SPINOR_OP_READ		0x03	/* Read data bytes (low frequency) */
 #define SPINOR_OP_READ_FAST	0x0b	/* Read data bytes (high frequency) */
-#define SPINOR_OP_READ_1_1_2	0x3b	/* Read data bytes (Dual SPI) */
-#define SPINOR_OP_READ_1_1_4	0x6b	/* Read data bytes (Quad SPI) */
+#define SPINOR_OP_READ_1_1_2	0x3b	/* Read data bytes (Dual Output SPI) */
+#define SPINOR_OP_READ_1_2_2	0xbb	/* Read data bytes (Dual I/O SPI) */
+#define SPINOR_OP_READ_1_1_4	0x6b	/* Read data bytes (Quad Output SPI) */
+#define SPINOR_OP_READ_1_4_4	0xeb	/* Read data bytes (Quad I/O SPI) */
 #define SPINOR_OP_PP		0x02	/* Page program (up to 256 bytes) */
+#define SPINOR_OP_PP_1_1_4	0x32	/* Quad page program */
+#define SPINOR_OP_PP_1_4_4	0x38	/* Quad page program */
 #define SPINOR_OP_BE_4K		0x20	/* Erase 4KiB block */
 #define SPINOR_OP_BE_4K_PMC	0xd7	/* Erase 4KiB block on PMC chips */
 #define SPINOR_OP_BE_32K	0x52	/* Erase 32KiB block */
@@ -56,11 +60,17 @@
 #define SPINOR_OP_RDFSR		0x70	/* Read flag status register */
 
 /* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
-#define SPINOR_OP_READ4		0x13	/* Read data bytes (low frequency) */
-#define SPINOR_OP_READ4_FAST	0x0c	/* Read data bytes (high frequency) */
-#define SPINOR_OP_READ4_1_1_2	0x3c	/* Read data bytes (Dual SPI) */
-#define SPINOR_OP_READ4_1_1_4	0x6c	/* Read data bytes (Quad SPI) */
+#define SPINOR_OP_READ_4B	0x13	/* Read data bytes (low frequency) */
+#define SPINOR_OP_READ_FAST_4B	0x0c	/* Read data bytes (high frequency) */
+#define SPINOR_OP_READ_1_1_2_4B	0x3c	/* Read data bytes (Dual Output SPI) */
+#define SPINOR_OP_READ_1_2_2_4B	0xbc	/* Read data bytes (Dual I/O SPI) */
+#define SPINOR_OP_READ_1_1_4_4B	0x6c	/* Read data bytes (Quad Output SPI) */
+#define SPINOR_OP_READ_1_4_4_4B	0xec	/* Read data bytes (Quad I/O SPI) */
 #define SPINOR_OP_PP_4B		0x12	/* Page program (up to 256 bytes) */
+#define SPINOR_OP_PP_1_1_4_4B	0x34	/* Quad page program */
+#define SPINOR_OP_PP_1_4_4_4B	0x3e	/* Quad page program */
+#define SPINOR_OP_BE_4K_4B	0x21	/* Erase 4KiB block */
+#define SPINOR_OP_BE_32K_4B	0x5c	/* Erase 32KiB block */
 #define SPINOR_OP_SE_4B		0xdc	/* Sector erase (usually 64KiB) */
 
 /* Used for SST flashes only. */
-- 
2.7.4



From cyrille.pitchen at atmel.com  Mon Oct 24 09:34:40 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Mon, 24 Oct 2016 18:34:40 +0200
Subject: [PATCH v3 3/9] mtd: spi-nor: add support of SPI protocols like SPI
 1-2-2 and SPI 1-4-4
In-Reply-To: <cover.1477325128.git.cyrille.pitchen@atmel.com>
References: <cover.1477325128.git.cyrille.pitchen@atmel.com>
Message-ID: <1c4cc2b862fa79e8df64baca26fc7f82cffde75d.1477325128.git.cyrille.pitchen@atmel.com>

This patch changes the prototype of spi_nor_scan(): its 3rd parameter
is replaced by a const struct spi_nor_modes pointer, which tells the
spi-nor framework about which SPI protocols are supported by the SPI
controller.

Besides, this patch also introduces a new spi_nor_basic_flash_parameter
structure telling the spi-nor framework about the SPI protocols supported
by the SPI memory and the needed op codes to use these SPI protocols.

Currently the struct spi_nor_basic_flash_parameter is filled with legacy
values but a later patch will allow to fill it dynamically by reading the
JESD216 Serial Flash Discoverable Parameter (SFDP) tables from the SPI
memory.

With both structures, the spi-nor framework can now compute the best
match between SPI protocols supported by both the (Q)SPI memory and
controller hence selecting the relevant op codes for (Fast) Read, Page
Program and Sector Erase operations.

The spi_nor_basic_flash_parameter structure also provides the spi-nor
framework with the number of dummy cycles to be used with each Fast Read
commands and the erase block size associated to the erase block op codes.

Finally the spi_nor_basic_flash_parameter structure, through the optional
.enable_quad_io() hook, tells the spi-nor framework how to set the Quad
Enable (QE) bit of the QSPI memory to enable its Quad SPI features.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
 drivers/mtd/devices/m25p80.c          |  17 ++-
 drivers/mtd/spi-nor/atmel-quadspi.c   |  83 ++++++----
 drivers/mtd/spi-nor/cadence-quadspi.c |  18 ++-
 drivers/mtd/spi-nor/fsl-quadspi.c     |   8 +-
 drivers/mtd/spi-nor/hisi-sfc.c        |  32 +++-
 drivers/mtd/spi-nor/mtk-quadspi.c     |  16 +-
 drivers/mtd/spi-nor/nxp-spifi.c       |  21 +--
 drivers/mtd/spi-nor/spi-nor.c         | 280 +++++++++++++++++++++++++++-------
 include/linux/mtd/spi-nor.h           | 136 +++++++++++++++--
 9 files changed, 482 insertions(+), 129 deletions(-)

diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 9cf7fcd28034..f0a55c01406b 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -111,10 +111,10 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
 
 static inline unsigned int m25p80_rx_nbits(struct spi_nor *nor)
 {
-	switch (nor->flash_read) {
-	case SPI_NOR_DUAL:
+	switch (SNOR_PROTO_DATA_FROM_PROTO(nor->read_proto)) {
+	case 2:
 		return 2;
-	case SPI_NOR_QUAD:
+	case 4:
 		return 4;
 	default:
 		return 0;
@@ -195,7 +195,10 @@ static int m25p_probe(struct spi_device *spi)
 	struct flash_platform_data	*data;
 	struct m25p *flash;
 	struct spi_nor *nor;
-	enum read_mode mode = SPI_NOR_NORMAL;
+	struct spi_nor_modes modes = {
+		.rd_modes = SNOR_MODE_SLOW,
+		.wr_modes = SNOR_MODE_1_1_1,
+	};
 	char *flash_name;
 	int ret;
 
@@ -221,9 +224,9 @@ static int m25p_probe(struct spi_device *spi)
 	flash->spi = spi;
 
 	if (spi->mode & SPI_RX_QUAD)
-		mode = SPI_NOR_QUAD;
+		modes.rd_modes |= SNOR_MODE_1_1_4;
 	else if (spi->mode & SPI_RX_DUAL)
-		mode = SPI_NOR_DUAL;
+		modes.rd_modes |= SNOR_MODE_1_1_2;
 
 	if (data && data->name)
 		nor->mtd.name = data->name;
@@ -240,7 +243,7 @@ static int m25p_probe(struct spi_device *spi)
 	else
 		flash_name = spi->modalias;
 
-	ret = spi_nor_scan(nor, flash_name, mode);
+	ret = spi_nor_scan(nor, flash_name, &modes);
 	if (ret)
 		return ret;
 
diff --git a/drivers/mtd/spi-nor/atmel-quadspi.c b/drivers/mtd/spi-nor/atmel-quadspi.c
index 47937d9beec6..9f7e3124e8b8 100644
--- a/drivers/mtd/spi-nor/atmel-quadspi.c
+++ b/drivers/mtd/spi-nor/atmel-quadspi.c
@@ -275,14 +275,48 @@ static void atmel_qspi_debug_command(struct atmel_qspi *aq,
 
 static int atmel_qspi_run_command(struct atmel_qspi *aq,
 				  const struct atmel_qspi_command *cmd,
-				  u32 ifr_tfrtyp, u32 ifr_width)
+				  u32 ifr_tfrtyp, enum spi_nor_protocol proto)
 {
 	u32 iar, icr, ifr, sr;
 	int err = 0;
 
 	iar = 0;
 	icr = 0;
-	ifr = ifr_tfrtyp | ifr_width;
+	ifr = ifr_tfrtyp;
+
+	/* Set the SPI protocol */
+	switch (proto) {
+	case SNOR_PROTO_1_1_1:
+		ifr |= QSPI_IFR_WIDTH_SINGLE_BIT_SPI;
+		break;
+
+	case SNOR_PROTO_1_1_2:
+		ifr |= QSPI_IFR_WIDTH_DUAL_OUTPUT;
+		break;
+
+	case SNOR_PROTO_1_1_4:
+		ifr |= QSPI_IFR_WIDTH_QUAD_OUTPUT;
+		break;
+
+	case SNOR_PROTO_1_2_2:
+		ifr |= QSPI_IFR_WIDTH_DUAL_IO;
+		break;
+
+	case SNOR_PROTO_1_4_4:
+		ifr |= QSPI_IFR_WIDTH_QUAD_IO;
+		break;
+
+	case SNOR_PROTO_2_2_2:
+		ifr |= QSPI_IFR_WIDTH_DUAL_CMD;
+		break;
+
+	case SNOR_PROTO_4_4_4:
+		ifr |= QSPI_IFR_WIDTH_QUAD_CMD;
+		break;
+
+	default:
+		return -EINVAL;
+	}
 
 	/* Compute instruction parameters */
 	if (cmd->enable.bits.instruction) {
@@ -434,7 +468,7 @@ static int atmel_qspi_read_reg(struct spi_nor *nor, u8 opcode,
 	cmd.rx_buf = buf;
 	cmd.buf_len = len;
 	return atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_READ,
-				      QSPI_IFR_WIDTH_SINGLE_BIT_SPI);
+				      nor->reg_proto);
 }
 
 static int atmel_qspi_write_reg(struct spi_nor *nor, u8 opcode,
@@ -450,7 +484,7 @@ static int atmel_qspi_write_reg(struct spi_nor *nor, u8 opcode,
 	cmd.tx_buf = buf;
 	cmd.buf_len = len;
 	return atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_WRITE,
-				      QSPI_IFR_WIDTH_SINGLE_BIT_SPI);
+				      nor->reg_proto);
 }
 
 static ssize_t atmel_qspi_write(struct spi_nor *nor, loff_t to, size_t len,
@@ -469,7 +503,7 @@ static ssize_t atmel_qspi_write(struct spi_nor *nor, loff_t to, size_t len,
 	cmd.tx_buf = write_buf;
 	cmd.buf_len = len;
 	ret = atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_WRITE_MEM,
-				     QSPI_IFR_WIDTH_SINGLE_BIT_SPI);
+				     nor->write_proto);
 	return (ret < 0) ? ret : len;
 }
 
@@ -484,7 +518,7 @@ static int atmel_qspi_erase(struct spi_nor *nor, loff_t offs)
 	cmd.instruction = nor->erase_opcode;
 	cmd.address = (u32)offs;
 	return atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_WRITE,
-				      QSPI_IFR_WIDTH_SINGLE_BIT_SPI);
+				      nor->reg_proto);
 }
 
 static ssize_t atmel_qspi_read(struct spi_nor *nor, loff_t from, size_t len,
@@ -493,27 +527,8 @@ static ssize_t atmel_qspi_read(struct spi_nor *nor, loff_t from, size_t len,
 	struct atmel_qspi *aq = nor->priv;
 	struct atmel_qspi_command cmd;
 	u8 num_mode_cycles, num_dummy_cycles;
-	u32 ifr_width;
 	ssize_t ret;
 
-	switch (nor->flash_read) {
-	case SPI_NOR_NORMAL:
-	case SPI_NOR_FAST:
-		ifr_width = QSPI_IFR_WIDTH_SINGLE_BIT_SPI;
-		break;
-
-	case SPI_NOR_DUAL:
-		ifr_width = QSPI_IFR_WIDTH_DUAL_OUTPUT;
-		break;
-
-	case SPI_NOR_QUAD:
-		ifr_width = QSPI_IFR_WIDTH_QUAD_OUTPUT;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
 	if (nor->read_dummy >= 2) {
 		num_mode_cycles = 2;
 		num_dummy_cycles = nor->read_dummy - 2;
@@ -536,7 +551,7 @@ static ssize_t atmel_qspi_read(struct spi_nor *nor, loff_t from, size_t len,
 	cmd.rx_buf = read_buf;
 	cmd.buf_len = len;
 	ret = atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_READ_MEM,
-				     ifr_width);
+				     nor->read_proto);
 	return (ret < 0) ? ret : len;
 }
 
@@ -596,6 +611,20 @@ static int atmel_qspi_probe(struct platform_device *pdev)
 	struct spi_nor *nor;
 	struct mtd_info *mtd;
 	int irq, err = 0;
+	struct spi_nor_modes modes = {
+		.rd_modes = (SNOR_MODE_SLOW |
+			     SNOR_MODE_1_1_1 |
+			     SNOR_MODE_1_1_2 |
+			     SNOR_MODE_1_1_4 |
+			     SNOR_MODE_1_2_2 |
+			     SNOR_MODE_1_4_4),
+		.wr_modes = (SNOR_MODE_SLOW |
+			     SNOR_MODE_1_1_1 |
+			     SNOR_MODE_1_1_2 |
+			     SNOR_MODE_1_1_4 |
+			     SNOR_MODE_1_2_2 |
+			     SNOR_MODE_1_4_4),
+	};
 
 	if (of_get_child_count(np) != 1)
 		return -ENODEV;
@@ -679,7 +708,7 @@ static int atmel_qspi_probe(struct platform_device *pdev)
 	if (err)
 		goto disable_clk;
 
-	err = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
+	err = spi_nor_scan(nor, NULL, &modes);
 	if (err)
 		goto disable_clk;
 
diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c
index d403ba7b8f43..87e49231b4ee 100644
--- a/drivers/mtd/spi-nor/cadence-quadspi.c
+++ b/drivers/mtd/spi-nor/cadence-quadspi.c
@@ -853,15 +853,14 @@ static int cqspi_set_protocol(struct spi_nor *nor, const int read)
 	f_pdata->data_width = CQSPI_INST_TYPE_SINGLE;
 
 	if (read) {
-		switch (nor->flash_read) {
-		case SPI_NOR_NORMAL:
-		case SPI_NOR_FAST:
+		switch (nor->read_proto) {
+		case SNOR_PROTO_1_1_1:
 			f_pdata->data_width = CQSPI_INST_TYPE_SINGLE;
 			break;
-		case SPI_NOR_DUAL:
+		case SNOR_PROTO_1_1_2:
 			f_pdata->data_width = CQSPI_INST_TYPE_DUAL;
 			break;
-		case SPI_NOR_QUAD:
+		case SNOR_PROTO_1_1_4:
 			f_pdata->data_width = CQSPI_INST_TYPE_QUAD;
 			break;
 		default:
@@ -1074,6 +1073,13 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
 	struct mtd_info *mtd;
 	unsigned int cs;
 	int i, ret;
+	static const struct spi_nor_modes modes = {
+		.rd_modes = (SNOR_MODE_SLOW |
+			     SNOR_MODE_1_1_1 |
+			     SNOR_MODE_1_1_2 |
+			     SNOR_MODE_1_1_4),
+		.wr_modes = SNOR_MODE_1_1_1,
+	};
 
 	/* Get flash device data */
 	for_each_available_child_of_node(dev->of_node, np) {
@@ -1119,7 +1125,7 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
 			goto err;
 		}
 
-		ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
+		ret = spi_nor_scan(nor, NULL, &modes);
 		if (ret)
 			goto err;
 
diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c
index 5c82e4ef1904..01e7356d6623 100644
--- a/drivers/mtd/spi-nor/fsl-quadspi.c
+++ b/drivers/mtd/spi-nor/fsl-quadspi.c
@@ -980,6 +980,12 @@ static int fsl_qspi_probe(struct platform_device *pdev)
 	struct spi_nor *nor;
 	struct mtd_info *mtd;
 	int ret, i = 0;
+	static const struct spi_nor_modes modes = {
+		.rd_modes = (SNOR_MODE_SLOW |
+			     SNOR_MODE_1_1_1 |
+			     SNOR_MODE_1_1_4),
+		.wr_modes = SNOR_MODE_1_1_1,
+	};
 
 	q = devm_kzalloc(dev, sizeof(*q), GFP_KERNEL);
 	if (!q)
@@ -1081,7 +1087,7 @@ static int fsl_qspi_probe(struct platform_device *pdev)
 		/* set the chip address for READID */
 		fsl_qspi_set_base_addr(q, nor);
 
-		ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
+		ret = spi_nor_scan(nor, NULL, &modes);
 		if (ret)
 			goto mutex_failed;
 
diff --git a/drivers/mtd/spi-nor/hisi-sfc.c b/drivers/mtd/spi-nor/hisi-sfc.c
index 20378b0d55e9..e4d7625b4397 100644
--- a/drivers/mtd/spi-nor/hisi-sfc.c
+++ b/drivers/mtd/spi-nor/hisi-sfc.c
@@ -120,19 +120,24 @@ static inline int wait_op_finish(struct hifmc_host *host)
 		(reg & FMC_INT_OP_DONE), 0, FMC_WAIT_TIMEOUT);
 }
 
-static int get_if_type(enum read_mode flash_read)
+static int get_if_type(enum spi_nor_protocol proto)
 {
 	enum hifmc_iftype if_type;
 
-	switch (flash_read) {
-	case SPI_NOR_DUAL:
+	switch (proto) {
+	case SNOR_PROTO_1_1_2:
 		if_type = IF_TYPE_DUAL;
 		break;
-	case SPI_NOR_QUAD:
+	case SNOR_PROTO_1_2_2:
+		if_type = IF_TYPE_DIO;
+		break;
+	case SNOR_PROTO_1_1_4:
 		if_type = IF_TYPE_QUAD;
 		break;
-	case SPI_NOR_NORMAL:
-	case SPI_NOR_FAST:
+	case SNOR_PROTO_1_4_4:
+		if_type = IF_TYPE_QIO;
+		break;
+	case SNOR_PROTO_1_1_1:
 	default:
 		if_type = IF_TYPE_STD;
 		break;
@@ -238,6 +243,7 @@ static int hisi_spi_nor_dma_transfer(struct spi_nor *nor, loff_t start_off,
 {
 	struct hifmc_priv *priv = nor->priv;
 	struct hifmc_host *host = priv->host;
+	enum spi_nor_protocol proto;
 	u8 if_type = 0;
 	u32 reg;
 
@@ -253,7 +259,10 @@ static int hisi_spi_nor_dma_transfer(struct spi_nor *nor, loff_t start_off,
 	writel(FMC_DMA_LEN_SET(len), host->regbase + FMC_DMA_LEN);
 
 	reg = OP_CFG_FM_CS(priv->chipselect);
-	if_type = get_if_type(nor->flash_read);
+	proto = (op_type == FMC_OP_READ)
+		? nor->read_proto
+		: nor->write_proto;
+	if_type = get_if_type(proto);
 	reg |= OP_CFG_MEM_IF_TYPE(if_type);
 	if (op_type == FMC_OP_READ)
 		reg |= OP_CFG_DUMMY_NUM(nor->read_dummy >> 3);
@@ -326,6 +335,13 @@ static int hisi_spi_nor_register(struct device_node *np,
 	struct hifmc_priv *priv;
 	struct mtd_info *mtd;
 	int ret;
+	static const struct spi_nor_modes modes = {
+		.rd_modes = (SNOR_MODE_SLOW |
+			     SNOR_MODE_1_1_1 |
+			     SNOR_MODE_1_1_2 |
+			     SNOR_MODE_1_1_4),
+		.wr_modes = SNOR_MODE_1_1_1,
+	};
 
 	nor = devm_kzalloc(dev, sizeof(*nor), GFP_KERNEL);
 	if (!nor)
@@ -362,7 +378,7 @@ static int hisi_spi_nor_register(struct device_node *np,
 	nor->read = hisi_spi_nor_read;
 	nor->write = hisi_spi_nor_write;
 	nor->erase = NULL;
-	ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
+	ret = spi_nor_scan(nor, NULL, &modes);
 	if (ret)
 		return ret;
 
diff --git a/drivers/mtd/spi-nor/mtk-quadspi.c b/drivers/mtd/spi-nor/mtk-quadspi.c
index e661877c23de..4dc2bb8eb488 100644
--- a/drivers/mtd/spi-nor/mtk-quadspi.c
+++ b/drivers/mtd/spi-nor/mtk-quadspi.c
@@ -121,20 +121,20 @@ static void mt8173_nor_set_read_mode(struct mt8173_nor *mt8173_nor)
 {
 	struct spi_nor *nor = &mt8173_nor->nor;
 
-	switch (nor->flash_read) {
-	case SPI_NOR_FAST:
+	switch (SNOR_PROTO_DATA_FROM_PROTO(nor->read_proto)) {
+	case 1:
 		writeb(nor->read_opcode, mt8173_nor->base +
 		       MTK_NOR_PRGDATA3_REG);
 		writeb(MTK_NOR_FAST_READ, mt8173_nor->base +
 		       MTK_NOR_CFG1_REG);
 		break;
-	case SPI_NOR_DUAL:
+	case 2:
 		writeb(nor->read_opcode, mt8173_nor->base +
 		       MTK_NOR_PRGDATA3_REG);
 		writeb(MTK_NOR_DUAL_READ_EN, mt8173_nor->base +
 		       MTK_NOR_DUAL_REG);
 		break;
-	case SPI_NOR_QUAD:
+	case 4:
 		writeb(nor->read_opcode, mt8173_nor->base +
 		       MTK_NOR_PRGDATA4_REG);
 		writeb(MTK_NOR_QUAD_READ_EN, mt8173_nor->base +
@@ -383,6 +383,12 @@ static int mtk_nor_init(struct mt8173_nor *mt8173_nor,
 {
 	int ret;
 	struct spi_nor *nor;
+	static const struct spi_nor_modes modes = {
+		.rd_modes = (SNOR_MODE_SLOW |
+			     SNOR_MODE_1_1_1 |
+			     SNOR_MODE_1_1_2),
+		.wr_modes = SNOR_MODE_1_1_1,
+	};
 
 	/* initialize controller to accept commands */
 	writel(MTK_NOR_ENABLE_SF_CMD, mt8173_nor->base + MTK_NOR_WRPROT_REG);
@@ -399,7 +405,7 @@ static int mtk_nor_init(struct mt8173_nor *mt8173_nor,
 	nor->write_reg = mt8173_nor_write_reg;
 	nor->mtd.name = "mtk_nor";
 	/* initialized with NULL */
-	ret = spi_nor_scan(nor, NULL, SPI_NOR_DUAL);
+	ret = spi_nor_scan(nor, NULL, &modes);
 	if (ret)
 		return ret;
 
diff --git a/drivers/mtd/spi-nor/nxp-spifi.c b/drivers/mtd/spi-nor/nxp-spifi.c
index 73a14f40928b..327c5b5fe9da 100644
--- a/drivers/mtd/spi-nor/nxp-spifi.c
+++ b/drivers/mtd/spi-nor/nxp-spifi.c
@@ -240,13 +240,12 @@ static int nxp_spifi_erase(struct spi_nor *nor, loff_t offs)
 
 static int nxp_spifi_setup_memory_cmd(struct nxp_spifi *spifi)
 {
-	switch (spifi->nor.flash_read) {
-	case SPI_NOR_NORMAL:
-	case SPI_NOR_FAST:
+	switch (SNOR_PROTO_DATA_FROM_PROTO(spifi->nor.read_proto)) {
+	case 1:
 		spifi->mcmd = SPIFI_CMD_FIELDFORM_ALL_SERIAL;
 		break;
-	case SPI_NOR_DUAL:
-	case SPI_NOR_QUAD:
+	case 2:
+	case 4:
 		spifi->mcmd = SPIFI_CMD_FIELDFORM_QUAD_DUAL_DATA;
 		break;
 	default:
@@ -274,7 +273,10 @@ static void nxp_spifi_dummy_id_read(struct spi_nor *nor)
 static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
 				 struct device_node *np)
 {
-	enum read_mode flash_read;
+	struct spi_nor_modes modes = {
+		.rd_modes = (SNOR_MODE_SLOW | SNOR_MODE_1_1_1),
+		.wr_modes = SNOR_MODE_1_1_1,
+	};
 	u32 ctrl, property;
 	u16 mode = 0;
 	int ret;
@@ -308,13 +310,12 @@ static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
 
 	if (mode & SPI_RX_DUAL) {
 		ctrl |= SPIFI_CTRL_DUAL;
-		flash_read = SPI_NOR_DUAL;
+		modes.rd_modes |= SNOR_MODE_1_1_2;
 	} else if (mode & SPI_RX_QUAD) {
 		ctrl &= ~SPIFI_CTRL_DUAL;
-		flash_read = SPI_NOR_QUAD;
+		modes.rd_modes |= SNOR_MODE_1_1_4;
 	} else {
 		ctrl |= SPIFI_CTRL_DUAL;
-		flash_read = SPI_NOR_NORMAL;
 	}
 
 	switch (mode & (SPI_CPHA | SPI_CPOL)) {
@@ -351,7 +352,7 @@ static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
 	 */
 	nxp_spifi_dummy_id_read(&spifi->nor);
 
-	ret = spi_nor_scan(&spifi->nor, NULL, flash_read);
+	ret = spi_nor_scan(&spifi->nor, NULL, &modes);
 	if (ret) {
 		dev_err(spifi->dev, "device scan failed\n");
 		return ret;
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 423448c1c7a8..05000b010e7f 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -143,24 +143,6 @@ static int read_cr(struct spi_nor *nor)
 }
 
 /*
- * Dummy Cycle calculation for different type of read.
- * It can be used to support more commands with
- * different dummy cycle requirements.
- */
-static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor)
-{
-	switch (nor->flash_read) {
-	case SPI_NOR_FAST:
-	case SPI_NOR_DUAL:
-	case SPI_NOR_QUAD:
-		return 8;
-	case SPI_NOR_NORMAL:
-		return 0;
-	}
-	return 0;
-}
-
-/*
  * Write status register 1 byte
  * Returns negative if error occurred.
  */
@@ -1384,8 +1366,206 @@ static int spi_nor_check(struct spi_nor *nor)
 	return 0;
 }
 
-int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+static inline void spi_nor_set_read_settings(struct spi_nor_read *read,
+					     u8 num_mode_clocks,
+					     u8 num_wait_states,
+					     u8 opcode)
+{
+	read->num_mode_clocks = num_mode_clocks;
+	read->num_wait_states = num_wait_states;
+	read->opcode = opcode;
+}
+
+static inline void spi_nor_set_erase_settings(struct spi_nor_erase_type *erase,
+					      u8 size, u8 opcode)
+{
+	erase->size = size;
+	erase->opcode = opcode;
+}
+
+static int spi_nor_init_params(struct spi_nor *nor,
+			       const struct flash_info *info,
+			       struct spi_nor_basic_flash_parameter *params)
+{
+	// TODO: parse SFDP table
+
+	/* If SFDP tables are not available, use legacy settings. */
+	memset(params, 0, sizeof(*params));
+
+	/* (Fast) Read settings. */
+	params->rd_modes = SNOR_MODE_SLOW;
+	spi_nor_set_read_settings(&params->reads[SNOR_PINDEX_SLOW],
+				  0, 0, SPINOR_OP_READ);
+	if (!(info->flags & SPI_NOR_NO_FR)) {
+		params->rd_modes |= SNOR_MODE_1_1_1;
+		spi_nor_set_read_settings(&params->reads[SNOR_PINDEX_1_1_1],
+					  0, 8, SPINOR_OP_READ_FAST);
+	}
+	if (info->flags & SPI_NOR_DUAL_READ) {
+		params->rd_modes |= SNOR_MODE_1_1_2;
+		spi_nor_set_read_settings(&params->reads[SNOR_PINDEX_1_1_2],
+					  0, 8, SPINOR_OP_READ_1_1_2);
+	}
+	if (info->flags & SPI_NOR_QUAD_READ) {
+		params->rd_modes |= SNOR_MODE_1_1_4;
+		spi_nor_set_read_settings(&params->reads[SNOR_PINDEX_1_1_4],
+					  0, 8, SPINOR_OP_READ_1_1_4);
+	}
+
+	/* Page Program settings. */
+	params->wr_modes = SNOR_MODE_1_1_1;
+	params->page_programs[SNOR_PINDEX_1_1_1] = SPINOR_OP_PP;
+
+	/* Sector Erase settings. */
+	spi_nor_set_erase_settings(&params->erase_types[0],
+				   SNOR_ERASE_64K, SPINOR_OP_SE);
+	if (info->flags & SECT_4K)
+		spi_nor_set_erase_settings(&params->erase_types[1],
+					   SNOR_ERASE_4K, SPINOR_OP_BE_4K);
+	else if (info->flags & SECT_4K_PMC)
+		spi_nor_set_erase_settings(&params->erase_types[1],
+					   SNOR_ERASE_4K, SPINOR_OP_BE_4K_PMC);
+
+	/* Select the procedure to set the Quad Enable bit. */
+	if (params->rd_modes & (SNOR_MODE_1_1_4 |
+				SNOR_MODE_1_4_4 |
+				SNOR_MODE_4_4_4)) {
+		switch (JEDEC_MFR(info)) {
+		case SNOR_MFR_MACRONIX:
+			params->enable_quad_io = macronix_quad_enable;
+			break;
+
+		case SNOR_MFR_MICRON:
+			break;
+
+		default:
+			params->enable_quad_io = spansion_quad_enable;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int spi_nor_pindex2proto(int pindex, enum spi_nor_protocol *proto)
+{
+	enum spi_nor_protocol_width pwidth;
+	enum spi_nor_protocol_class pclass;
+	uint8_t width;
+
+	if (pindex < 0)
+		return -EINVAL;
+
+	pwidth = (enum spi_nor_protocol_width)(pindex / SNOR_PCLASS_MAX);
+	pclass = (enum spi_nor_protocol_class)(pindex % SNOR_PCLASS_MAX);
+
+	width = (1 << pwidth) & 0xf;
+	if (!width)
+		return -EINVAL;
+
+	switch (pclass) {
+	case SNOR_PCLASS_1_1_N:
+		*proto = SNOR_PROTO(1, 1, width);
+		break;
+
+	case SNOR_PCLASS_1_N_N:
+		*proto = SNOR_PROTO(1, width, width);
+		break;
+
+	case SNOR_PCLASS_N_N_N:
+		*proto = SNOR_PROTO(width, width, width);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
+			 const struct spi_nor_basic_flash_parameter *params,
+			 const struct spi_nor_modes *modes)
 {
+	bool enable_quad_io;
+	u32 rd_modes, wr_modes, mask;
+	const struct spi_nor_erase_type *erase_type = NULL;
+	const struct spi_nor_read *read;
+	int rd_pindex, wr_pindex, i, err = 0;
+	u8 erase_size = SNOR_ERASE_64K;
+
+	/* 2-2-2 or 4-4-4 modes are not supported yet. */
+	mask = (SNOR_MODE_2_2_2 | SNOR_MODE_4_4_4);
+	rd_modes = modes->rd_modes & ~mask;
+	wr_modes = modes->wr_modes & ~mask;
+
+	/* Setup read operation. */
+	rd_pindex = fls(params->rd_modes & rd_modes) - 1;
+	if (spi_nor_pindex2proto(rd_pindex, &nor->read_proto)) {
+		dev_err(nor->dev, "invalid (fast) read\n");
+		return -EINVAL;
+	}
+	read = &params->reads[rd_pindex];
+	nor->read_opcode = read->opcode;
+	nor->read_dummy = read->num_mode_clocks + read->num_wait_states;
+
+	/* Set page program op code and protocol. */
+	wr_pindex = fls(params->wr_modes & wr_modes) - 1;
+	if (spi_nor_pindex2proto(wr_pindex, &nor->write_proto)) {
+		dev_err(nor->dev, "invalid page program\n");
+		return -EINVAL;
+	}
+	nor->program_opcode = params->page_programs[wr_pindex];
+
+	/* Set sector erase op code and size. */
+	erase_type = &params->erase_types[0];
+#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
+	erase_size = SNOR_ERASE_4K;
+#endif
+	for (i = 0; i < SNOR_MAX_ERASE_TYPES; ++i) {
+		if (params->erase_types[i].size == erase_size) {
+			erase_type = &params->erase_types[i];
+			break;
+		} else if (!erase_type->size && params->erase_types[i].size) {
+			erase_type = &params->erase_types[i];
+		}
+	}
+	nor->erase_opcode = erase_type->opcode;
+	nor->mtd.erasesize = (1 << erase_type->size);
+
+
+	enable_quad_io = (SNOR_PROTO_DATA_FROM_PROTO(nor->read_proto) == 4 ||
+			  SNOR_PROTO_DATA_FROM_PROTO(nor->write_proto) == 4);
+
+	/* Enable Quad I/O if needed. */
+	if (enable_quad_io && params->enable_quad_io) {
+		err = params->enable_quad_io(nor);
+		if (err) {
+			dev_err(nor->dev,
+				"failed to enable the Quad I/O mode\n");
+			return err;
+		}
+	}
+
+	dev_dbg(nor->dev,
+		"(Fast) Read:  opcode=%02Xh, protocol=%03x, mode=%u, wait=%u\n",
+		nor->read_opcode, nor->read_proto,
+		read->num_mode_clocks, read->num_wait_states);
+	dev_dbg(nor->dev,
+		"Page Program: opcode=%02Xh, protocol=%03x\n",
+		nor->program_opcode, nor->write_proto);
+	dev_dbg(nor->dev,
+		"Sector Erase: opcode=%02Xh, protocol=%03x, sector size=%u\n",
+		nor->erase_opcode, nor->reg_proto, (u32)nor->mtd.erasesize);
+
+	return 0;
+}
+
+int spi_nor_scan(struct spi_nor *nor, const char *name,
+		 const struct spi_nor_modes *modes)
+{
+	struct spi_nor_basic_flash_parameter params;
+	struct spi_nor_modes fixed_modes = *modes;
 	const struct flash_info *info = NULL;
 	struct device *dev = nor->dev;
 	struct mtd_info *mtd = &nor->mtd;
@@ -1397,6 +1577,11 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 	if (ret)
 		return ret;
 
+	/* Reset SPI protocol for all commands */
+	nor->reg_proto = SNOR_PROTO_1_1_1;
+	nor->read_proto = SNOR_PROTO_1_1_1;
+	nor->write_proto = SNOR_PROTO_1_1_1;
+
 	if (name)
 		info = spi_nor_match_id(name);
 	/* Try to auto-detect if chip name wasn't specified or not found */
@@ -1429,6 +1614,11 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 		}
 	}
 
+	/* Parse the Serial Flash Discoverable Parameters table */
+	ret = spi_nor_init_params(nor, info, &params);
+	if (ret)
+		return ret;
+
 	mutex_init(&nor->lock);
 
 	/*
@@ -1505,51 +1695,31 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 	if (np) {
 		/* If we were instantiated by DT, use it */
 		if (of_property_read_bool(np, "m25p,fast-read"))
-			nor->flash_read = SPI_NOR_FAST;
+			fixed_modes.rd_modes |= SNOR_MODE_1_1_1;
 		else
-			nor->flash_read = SPI_NOR_NORMAL;
+			fixed_modes.rd_modes &= ~SNOR_MODE_1_1_1;
 	} else {
 		/* If we weren't instantiated by DT, default to fast-read */
-		nor->flash_read = SPI_NOR_FAST;
+		fixed_modes.rd_modes |= SNOR_MODE_1_1_1;
 	}
 
 	/* Some devices cannot do fast-read, no matter what DT tells us */
 	if (info->flags & SPI_NOR_NO_FR)
-		nor->flash_read = SPI_NOR_NORMAL;
-
-	/* Quad/Dual-read mode takes precedence over fast/normal */
-	if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) {
-		ret = set_quad_mode(nor, info);
-		if (ret) {
-			dev_err(dev, "quad mode not supported\n");
-			return ret;
-		}
-		nor->flash_read = SPI_NOR_QUAD;
-	} else if (mode == SPI_NOR_DUAL && info->flags & SPI_NOR_DUAL_READ) {
-		nor->flash_read = SPI_NOR_DUAL;
-	}
-
-	/* Default commands */
-	switch (nor->flash_read) {
-	case SPI_NOR_QUAD:
-		nor->read_opcode = SPINOR_OP_READ_1_1_4;
-		break;
-	case SPI_NOR_DUAL:
-		nor->read_opcode = SPINOR_OP_READ_1_1_2;
-		break;
-	case SPI_NOR_FAST:
-		nor->read_opcode = SPINOR_OP_READ_FAST;
-		break;
-	case SPI_NOR_NORMAL:
-		nor->read_opcode = SPINOR_OP_READ;
-		break;
-	default:
-		dev_err(dev, "No Read opcode defined\n");
-		return -EINVAL;
-	}
+		fixed_modes.rd_modes &= ~SNOR_MODE_1_1_1;
 
 	nor->program_opcode = SPINOR_OP_PP;
 
+	/*
+	 * Configure the SPI memory:
+	 * - select op codes for (Fast) Read, Page Program and Sector Erase.
+	 * - set the number of dummy cycles (mode cycles + wait states).
+	 * - set the SPI protocols for register and memory accesses.
+	 * - set the Quad Enable bit if needed (required by SPI x-y-4 protos).
+	 */
+	ret = spi_nor_setup(nor, info, &params, &fixed_modes);
+	if (ret)
+		return ret;
+
 	if (info->addr_width)
 		nor->addr_width = info->addr_width;
 	else if (mtd->size > 0x1000000) {
@@ -1570,8 +1740,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 		return -EINVAL;
 	}
 
-	nor->read_dummy = spi_nor_read_dummy_cycles(nor);
-
 	dev_info(dev, "%s (%lld Kbytes)\n", info->name,
 			(long long)mtd->size >> 10);
 
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 8b02fd7864d0..88ac446b1230 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -110,11 +110,124 @@
 /* Configuration Register bits. */
 #define CR_QUAD_EN_SPAN		BIT(1)	/* Spansion Quad I/O */
 
-enum read_mode {
-	SPI_NOR_NORMAL = 0,
-	SPI_NOR_FAST,
-	SPI_NOR_DUAL,
-	SPI_NOR_QUAD,
+
+/* Supported SPI protocols */
+enum spi_nor_protocol_class {
+	SNOR_PCLASS_1_1_N,
+	SNOR_PCLASS_1_N_N,
+	SNOR_PCLASS_N_N_N,
+
+	SNOR_PCLASS_MAX
+};
+
+enum spi_nor_protocol_width {
+	SNOR_PWIDTH_1,
+	SNOR_PWIDTH_2,
+	SNOR_PWIDTH_4,
+	SNOR_PWIDTH_8,
+};
+
+/* The encoding is chosen so the higher index the higher priority */
+#define SNOR_PINDEX(pwidth, pclass) \
+	((pwidth) * SNOR_PCLASS_MAX + (pclass))
+enum spi_nor_protocol_index {
+	SNOR_PINDEX_SLOW  = SNOR_PINDEX(SNOR_PWIDTH_1, SNOR_PCLASS_1_1_N),
+	/* Little trick to make the difference between Read and Fast Read. */
+	SNOR_PINDEX_1_1_1 = SNOR_PINDEX(SNOR_PWIDTH_1, SNOR_PCLASS_1_N_N),
+	SNOR_PINDEX_1_1_2 = SNOR_PINDEX(SNOR_PWIDTH_2, SNOR_PCLASS_1_1_N),
+	SNOR_PINDEX_1_2_2 = SNOR_PINDEX(SNOR_PWIDTH_2, SNOR_PCLASS_1_N_N),
+	SNOR_PINDEX_2_2_2 = SNOR_PINDEX(SNOR_PWIDTH_2, SNOR_PCLASS_N_N_N),
+	SNOR_PINDEX_1_1_4 = SNOR_PINDEX(SNOR_PWIDTH_4, SNOR_PCLASS_1_1_N),
+	SNOR_PINDEX_1_4_4 = SNOR_PINDEX(SNOR_PWIDTH_4, SNOR_PCLASS_1_N_N),
+	SNOR_PINDEX_4_4_4 = SNOR_PINDEX(SNOR_PWIDTH_4, SNOR_PCLASS_N_N_N),
+
+	SNOR_PINDEX_MAX
+};
+
+#define SNOR_MODE_SLOW		BIT(SNOR_PINDEX_SLOW)
+#define SNOR_MODE_1_1_1		BIT(SNOR_PINDEX_1_1_1)
+#define SNOR_MODE_1_1_2		BIT(SNOR_PINDEX_1_1_2)
+#define SNOR_MODE_1_2_2		BIT(SNOR_PINDEX_1_2_2)
+#define SNOR_MODE_2_2_2		BIT(SNOR_PINDEX_2_2_2)
+#define SNOR_MODE_1_1_4		BIT(SNOR_PINDEX_1_1_4)
+#define SNOR_MODE_1_4_4		BIT(SNOR_PINDEX_1_4_4)
+#define SNOR_MODE_4_4_4		BIT(SNOR_PINDEX_4_4_4)
+
+struct spi_nor_modes {
+	u32	rd_modes;	/* supported SPI modes for (Fast) Read */
+	u32	wr_modes;	/* supported SPI modes for Page Program */
+};
+
+
+struct spi_nor_read {
+	u8	num_wait_states:5;
+	u8	num_mode_clocks:3;
+	u8	opcode;
+};
+
+struct spi_nor_erase_type {
+	u8	size;	/* specifies 'N' so erase size = 2^N */
+	u8	opcode;
+};
+
+#define SNOR_ERASE_64K		0x10
+#define SNOR_ERASE_32K		0x0f
+#define SNOR_ERASE_4K		0x0c
+
+struct spi_nor;
+
+#define SNOR_MAX_ERASE_TYPES	4
+
+struct spi_nor_basic_flash_parameter {
+	/* Fast Read settings */
+	u32				rd_modes;
+	struct spi_nor_read		reads[SNOR_PINDEX_MAX];
+
+	/* Page Program settings */
+	u32				wr_modes;
+	u8				page_programs[SNOR_PINDEX_MAX];
+
+	/* Sector Erase settings */
+	struct spi_nor_erase_type	erase_types[SNOR_MAX_ERASE_TYPES];
+
+	int (*enable_quad_io)(struct spi_nor *nor);
+};
+
+
+#define SNOR_PROTO_CODE_OFF	8
+#define SNOR_PROTO_CODE_MASK	GENMASK(11, 8)
+#define SNOR_PROTO_CODE_TO_PROTO(code) \
+	(((code) << SNOR_PROTO_CODE_OFF) & SNOR_PROTO_CODE_MASK)
+#define SNOR_PROTO_CODE_FROM_PROTO(proto) \
+	((((u32)(proto)) & SNOR_PROTO_CODE_MASK) >> SNOR_PROTO_CODE_OFF)
+
+#define SNOR_PROTO_ADDR_OFF	4
+#define SNOR_PROTO_ADDR_MASK	GENMASK(7, 4)
+#define SNOR_PROTO_ADDR_TO_PROTO(addr) \
+	(((addr) << SNOR_PROTO_ADDR_OFF) & SNOR_PROTO_ADDR_MASK)
+#define SNOR_PROTO_ADDR_FROM_PROTO(proto) \
+	((((u32)(proto)) & SNOR_PROTO_ADDR_MASK) >> SNOR_PROTO_ADDR_OFF)
+
+#define SNOR_PROTO_DATA_OFF	0
+#define SNOR_PROTO_DATA_MASK	GENMASK(3, 0)
+#define SNOR_PROTO_DATA_TO_PROTO(data) \
+	(((data) << SNOR_PROTO_DATA_OFF) & SNOR_PROTO_DATA_MASK)
+#define SNOR_PROTO_DATA_FROM_PROTO(proto) \
+	((((u32)(proto)) & SNOR_PROTO_DATA_MASK) >> SNOR_PROTO_DATA_OFF)
+
+#define SNOR_PROTO(code, addr, data)	  \
+	(SNOR_PROTO_CODE_TO_PROTO(code) |   \
+	 SNOR_PROTO_ADDR_TO_PROTO(addr) | \
+	 SNOR_PROTO_DATA_TO_PROTO(data))
+
+enum spi_nor_protocol {
+	SNOR_PROTO_1_1_1 = SNOR_PROTO(1, 1, 1),	/* SPI */
+	SNOR_PROTO_1_1_2 = SNOR_PROTO(1, 1, 2),	/* Dual Output */
+	SNOR_PROTO_1_1_4 = SNOR_PROTO(1, 1, 4),	/* Quad Output */
+	SNOR_PROTO_1_2_2 = SNOR_PROTO(1, 2, 2),	/* Dual IO */
+	SNOR_PROTO_1_4_4 = SNOR_PROTO(1, 4, 4),	/* Quad IO */
+	SNOR_PROTO_2_2_2 = SNOR_PROTO(2, 2, 2),	/* Dual Command */
+	SNOR_PROTO_4_4_4 = SNOR_PROTO(4, 4, 4),	/* Quad Command */
 };
 
 #define SPI_NOR_MAX_CMD_SIZE	8
@@ -142,9 +255,11 @@ enum spi_nor_option_flags {
  * @read_opcode:	the read opcode
  * @read_dummy:		the dummy needed by the read operation
  * @program_opcode:	the program opcode
- * @flash_read:		the mode of the read
  * @sst_write_second:	used by the SST write operation
  * @flags:		flag options for the current SPI-NOR (SNOR_F_*)
+ * @read_proto:		the SPI protocol used by read operations
+ * @write_proto:	the SPI protocol used by write operations
+ * @reg_proto		the SPI protocol used by read_reg/write_reg operations
  * @cmd_buf:		used by the write_reg
  * @prepare:		[OPTIONAL] do some preparations for the
  *			read/write/erase/lock/unlock operations
@@ -173,7 +288,9 @@ struct spi_nor {
 	u8			read_opcode;
 	u8			read_dummy;
 	u8			program_opcode;
-	enum read_mode		flash_read;
+	enum spi_nor_protocol	read_proto;
+	enum spi_nor_protocol	write_proto;
+	enum spi_nor_protocol	reg_proto;
 	bool			sst_write_second;
 	u32			flags;
 	u8			cmd_buf[SPI_NOR_MAX_CMD_SIZE];
@@ -211,7 +328,7 @@ static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor)
  * spi_nor_scan() - scan the SPI NOR
  * @nor:	the spi_nor structure
  * @name:	the chip type name
- * @mode:	the read mode supported by the driver
+ * @modes:	the SPI modes supported by the controller driver
  *
  * The drivers can use this fuction to scan the SPI NOR.
  * In the scanning, it will try to get all the necessary information to
@@ -221,6 +338,7 @@ static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor)
  *
  * Return: 0 for success, others for failure.
  */
-int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode);
+int spi_nor_scan(struct spi_nor *nor, const char *name,
+		 const struct spi_nor_modes *modes);
 
 #endif
-- 
2.7.4



From cyrille.pitchen at atmel.com  Mon Oct 24 09:34:41 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Mon, 24 Oct 2016 18:34:41 +0200
Subject: [PATCH v3 4/9] mtd: spi-nor: remove unused set_quad_mode() function
In-Reply-To: <cover.1477325128.git.cyrille.pitchen@atmel.com>
References: <cover.1477325128.git.cyrille.pitchen@atmel.com>
Message-ID: <48d795fb0507dc356ac284520170c5be0882c431.1477325128.git.cyrille.pitchen@atmel.com>

The set_quad_mode() function is no longer used, so we remove it.

This patch is not squashed into the previous patch on purpose for
readiness issue and to ease the review process of the whole series.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 24 ------------------------
 1 file changed, 24 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 05000b010e7f..a06fcf400b39 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1331,30 +1331,6 @@ static int spansion_quad_enable(struct spi_nor *nor)
 	return 0;
 }
 
-static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
-{
-	int status;
-
-	switch (JEDEC_MFR(info)) {
-	case SNOR_MFR_MACRONIX:
-		status = macronix_quad_enable(nor);
-		if (status) {
-			dev_err(nor->dev, "Macronix quad-read not enabled\n");
-			return -EINVAL;
-		}
-		return status;
-	case SNOR_MFR_MICRON:
-		return 0;
-	default:
-		status = spansion_quad_enable(nor);
-		if (status) {
-			dev_err(nor->dev, "Spansion quad-read not enabled\n");
-			return -EINVAL;
-		}
-		return status;
-	}
-}
-
 static int spi_nor_check(struct spi_nor *nor)
 {
 	if (!nor->dev || !nor->read || !nor->write ||
-- 
2.7.4



From cyrille.pitchen at atmel.com  Mon Oct 24 09:34:42 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Mon, 24 Oct 2016 18:34:42 +0200
Subject: [PATCH v3 5/9] mtd: m25p80: add support of dual and quad spi
 protocols to all commands
In-Reply-To: <cover.1477325128.git.cyrille.pitchen@atmel.com>
References: <cover.1477325128.git.cyrille.pitchen@atmel.com>
Message-ID: <20bbf1848567ce25c5ab58b1bf1a710c44fec2ac.1477325128.git.cyrille.pitchen@atmel.com>

Before this patch, m25p80_read() supported few SPI protocols:
- regular SPI 1-1-1
- SPI Dual Output 1-1-2
- SPI Quad Output 1-1-4
On the other hand, all other m25p80_*() hooks only supported SPI 1-1-1.

This patch adds support to all currently existing SPI protocols to
cover as many protocols as possible.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
 drivers/mtd/devices/m25p80.c | 193 +++++++++++++++++++++++++++++++++----------
 1 file changed, 149 insertions(+), 44 deletions(-)

diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index f0a55c01406b..38778eac6c21 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -27,22 +27,64 @@
 #include <linux/spi/flash.h>
 #include <linux/mtd/spi-nor.h>
 
-#define	MAX_CMD_SIZE		6
+#define	MAX_CMD_SIZE		16
 struct m25p {
 	struct spi_device	*spi;
 	struct spi_nor		spi_nor;
 	u8			command[MAX_CMD_SIZE];
 };
 
+static inline int m25p80_proto2nbits(enum spi_nor_protocol proto,
+				     unsigned *code_nbits,
+				     unsigned *addr_nbits,
+				     unsigned *data_nbits)
+{
+	if (code_nbits)
+		*code_nbits = SNOR_PROTO_CODE_FROM_PROTO(proto);
+	if (addr_nbits)
+		*addr_nbits = SNOR_PROTO_ADDR_FROM_PROTO(proto);
+	if (data_nbits)
+		*data_nbits = SNOR_PROTO_DATA_FROM_PROTO(proto);
+
+	return 0;
+}
+
 static int m25p80_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len)
 {
 	struct m25p *flash = nor->priv;
 	struct spi_device *spi = flash->spi;
+	unsigned code_nbits, data_nbits;
+	struct spi_transfer xfers[2];
 	int ret;
 
-	ret = spi_write_then_read(spi, &code, 1, val, len);
+	/* Check the total length of command op code and data. */
+	if (len + 1 > MAX_CMD_SIZE)
+		return -EINVAL;
+
+	/* Get transfer protocols (addr_nbits is not relevant here). */
+	ret = m25p80_proto2nbits(nor->reg_proto,
+				 &code_nbits, NULL, &data_nbits);
+	if (ret < 0)
+		return ret;
+
+	/* Set up transfers. */
+	memset(xfers, 0, sizeof(xfers));
+
+	flash->command[0] = code;
+	xfers[0].len = 1;
+	xfers[0].tx_buf = flash->command;
+	xfers[0].tx_nbits = code_nbits;
+
+	xfers[1].len = len;
+	xfers[1].rx_buf = &flash->command[1];
+	xfers[1].rx_nbits = data_nbits;
+
+	/* Process command. */
+	ret = spi_sync_transfer(spi, xfers, 2);
 	if (ret < 0)
 		dev_err(&spi->dev, "error %d reading %x\n", ret, code);
+	else
+		memcpy(val, &flash->command[1], len);
 
 	return ret;
 }
@@ -65,12 +107,42 @@ static int m25p80_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
 {
 	struct m25p *flash = nor->priv;
 	struct spi_device *spi = flash->spi;
+	unsigned code_nbits, data_nbits, num_xfers = 1;
+	struct spi_transfer xfers[2];
+	int ret;
+
+	/* Check the total length of command op code and data. */
+	if (buf && (len + 1 > MAX_CMD_SIZE))
+		return -EINVAL;
+
+	/* Get transfer protocols (addr_nbits is not relevant here). */
+	ret = m25p80_proto2nbits(nor->reg_proto,
+				 &code_nbits, NULL, &data_nbits);
+	if (ret < 0)
+		return ret;
+
+	/* Set up transfer(s). */
+	memset(xfers, 0, sizeof(xfers));
 
 	flash->command[0] = opcode;
-	if (buf)
+	xfers[0].len = 1;
+	xfers[0].tx_buf = flash->command;
+	xfers[0].tx_nbits = code_nbits;
+
+	if (buf) {
 		memcpy(&flash->command[1], buf, len);
+		if (data_nbits == code_nbits) {
+			xfers[0].len += len;
+		} else {
+			xfers[1].len = len;
+			xfers[1].tx_buf = &flash->command[1];
+			xfers[1].tx_nbits = data_nbits;
+			num_xfers++;
+		}
+	}
 
-	return spi_write(spi, flash->command, len + 1);
+	/* Process command. */
+	return spi_sync_transfer(spi, xfers, num_xfers);
 }
 
 static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
@@ -78,27 +150,48 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
 {
 	struct m25p *flash = nor->priv;
 	struct spi_device *spi = flash->spi;
-	struct spi_transfer t[2] = {};
+	unsigned code_nbits, addr_nbits, data_nbits, num_xfers = 1;
+	struct spi_transfer xfers[3];
 	struct spi_message m;
 	int cmd_sz = m25p_cmdsz(nor);
 	ssize_t ret;
 
-	spi_message_init(&m);
-
 	if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
 		cmd_sz = 1;
 
-	flash->command[0] = nor->program_opcode;
-	m25p_addr2cmd(nor, to, flash->command);
+	/* Get transfer protocols. */
+	ret = m25p80_proto2nbits(nor->write_proto,
+				 &code_nbits, &addr_nbits, &data_nbits);
+	if (ret < 0)
+		return ret;
 
-	t[0].tx_buf = flash->command;
-	t[0].len = cmd_sz;
-	spi_message_add_tail(&t[0], &m);
+	/* Set up transfers. */
+	memset(xfers, 0, sizeof(xfers));
+
+	flash->command[0] = nor->program_opcode;
+	xfers[0].len = 1;
+	xfers[0].tx_buf = flash->command;
+	xfers[0].tx_nbits = code_nbits;
+
+	if (cmd_sz > 1) {
+		m25p_addr2cmd(nor, to, flash->command);
+		if (addr_nbits == code_nbits) {
+			xfers[0].len += nor->addr_width;
+		} else {
+			xfers[1].len = nor->addr_width;
+			xfers[1].tx_buf = &flash->command[1];
+			xfers[1].tx_nbits = addr_nbits;
+			num_xfers++;
+		}
+	}
 
-	t[1].tx_buf = buf;
-	t[1].len = len;
-	spi_message_add_tail(&t[1], &m);
+	xfers[num_xfers].len = len;
+	xfers[num_xfers].tx_buf = buf;
+	xfers[num_xfers].tx_nbits = data_nbits;
+	num_xfers++;
 
+	/* Process command. */
+	spi_message_init_with_transfers(&m, xfers, num_xfers);
 	ret = spi_sync(spi, &m);
 	if (ret)
 		return ret;
@@ -109,18 +202,6 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
 	return ret;
 }
 
-static inline unsigned int m25p80_rx_nbits(struct spi_nor *nor)
-{
-	switch (SNOR_PROTO_DATA_FROM_PROTO(nor->read_proto)) {
-	case 2:
-		return 2;
-	case 4:
-		return 4;
-	default:
-		return 0;
-	}
-}
-
 /*
  * Read an address range from the nor chip.  The address range
  * may be any size provided it is within the physical boundaries.
@@ -130,14 +211,22 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
 {
 	struct m25p *flash = nor->priv;
 	struct spi_device *spi = flash->spi;
-	struct spi_transfer t[2];
-	struct spi_message m;
+	unsigned code_nbits, addr_nbits, data_nbits, num_xfers = 1;
 	unsigned int dummy = nor->read_dummy;
 	ssize_t ret;
+	struct spi_transfer xfers[3];
+	struct spi_message m;
+
+	/* Get transfer protocols. */
+	ret = m25p80_proto2nbits(nor->read_proto,
+				 &code_nbits, &addr_nbits, &data_nbits);
+	if (ret < 0)
+		return ret;
 
 	/* convert the dummy cycles to the number of bytes */
-	dummy /= 8;
+	dummy = (dummy * addr_nbits) / 8;
 
+	/* Use the SPI flash API if supported. */
 	if (spi_flash_read_supported(spi)) {
 		struct spi_flash_read_message msg;
 
@@ -149,10 +238,9 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
 		msg.read_opcode = nor->read_opcode;
 		msg.addr_width = nor->addr_width;
 		msg.dummy_bytes = dummy;
-		/* TODO: Support other combinations */
-		msg.opcode_nbits = SPI_NBITS_SINGLE;
-		msg.addr_nbits = SPI_NBITS_SINGLE;
-		msg.data_nbits = m25p80_rx_nbits(nor);
+		msg.opcode_nbits = code_nbits;
+		msg.addr_nbits = addr_nbits;
+		msg.data_nbits = data_nbits;
 
 		ret = spi_flash_read(spi, &msg);
 		if (ret < 0)
@@ -160,21 +248,38 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
 		return msg.retlen;
 	}
 
-	spi_message_init(&m);
-	memset(t, 0, (sizeof t));
+	/* Set up transfers. */
+	memset(xfers, 0, sizeof(xfers));
 
 	flash->command[0] = nor->read_opcode;
-	m25p_addr2cmd(nor, from, flash->command);
+	xfers[0].len = 1;
+	xfers[0].tx_buf = flash->command;
+	xfers[0].tx_nbits = code_nbits;
 
-	t[0].tx_buf = flash->command;
-	t[0].len = m25p_cmdsz(nor) + dummy;
-	spi_message_add_tail(&t[0], &m);
+	m25p_addr2cmd(nor, from, flash->command);
+	/*
+	 * Clear all dummy/mode cycle bits to avoid sending some manufacturer
+	 * specific pattern, which might make the memory enter its Continuous
+	 * Read mode by mistake.
+	 */
+	memset(flash->command + 1 + nor->addr_width, 0, dummy);
+
+	if (addr_nbits == code_nbits) {
+		xfers[0].len += nor->addr_width + dummy;
+	} else {
+		xfers[1].len = nor->addr_width + dummy;
+		xfers[1].tx_buf = &flash->command[1];
+		xfers[1].tx_nbits = addr_nbits;
+		num_xfers++;
+	}
 
-	t[1].rx_buf = buf;
-	t[1].rx_nbits = m25p80_rx_nbits(nor);
-	t[1].len = min(len, spi_max_transfer_size(spi));
-	spi_message_add_tail(&t[1], &m);
+	xfers[num_xfers].len = len;
+	xfers[num_xfers].rx_buf = buf;
+	xfers[num_xfers].rx_nbits = data_nbits;
+	num_xfers++;
 
+	/* Process command. */
+	spi_message_init_with_transfers(&m, xfers, num_xfers);
 	ret = spi_sync(spi, &m);
 	if (ret)
 		return ret;
-- 
2.7.4



From cyrille.pitchen at atmel.com  Mon Oct 24 09:34:43 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Mon, 24 Oct 2016 18:34:43 +0200
Subject: [PATCH v3 6/9] mtd: spi-nor: parse Serial Flash Discoverable
 Parameters (SFDP) tables
In-Reply-To: <cover.1477325128.git.cyrille.pitchen@atmel.com>
References: <cover.1477325128.git.cyrille.pitchen@atmel.com>
Message-ID: <ffa2e235b8308ba5f19d9538f948afbcb0d2b6ee.1477325128.git.cyrille.pitchen@atmel.com>

This patch adds support the the JESD216B standard and parse the SFDP
tables to dynamically initialize the spi_nor_basic_flash_parameter
structure.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 468 +++++++++++++++++++++++++++++++++++++++++-
 include/linux/mtd/spi-nor.h   |   6 +
 2 files changed, 473 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index a06fcf400b39..7fc0138c1d68 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -17,6 +17,7 @@
 #include <linux/mutex.h>
 #include <linux/math64.h>
 #include <linux/sizes.h>
+#include <linux/slab.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/of_platform.h>
@@ -79,6 +80,7 @@ struct flash_info {
 					 * Use dedicated 4byte address op codes
 					 * to support memory size above 128Mib.
 					 */
+#define SPI_NOR_SKIP_SFDP	BIT(11) /* Skip read of SFDP tables */
 };
 
 #define JEDEC_MFR(info)	((info)->id[0])
@@ -1331,6 +1333,99 @@ static int spansion_quad_enable(struct spi_nor *nor)
 	return 0;
 }
 
+static int spansion_new_quad_enable(struct spi_nor *nor)
+{
+	u8 sr_cr[2];
+	int ret;
+
+	/* Check current Quad Enable bit value. */
+	ret = read_cr(nor);
+	if (ret < 0) {
+		dev_err(nor->dev,
+			"error while reading configuration register\n");
+		return -EINVAL;
+	}
+	sr_cr[1] = ret;
+	if (sr_cr[1] & CR_QUAD_EN_SPAN)
+		return 0;
+
+	dev_info(nor->dev, "setting Spansion Quad Enable (non-volatile) bit\n");
+
+	/* Keep the current value of the Status Register. */
+	ret = read_sr(nor);
+	if (ret < 0) {
+		dev_err(nor->dev,
+			"error while reading status register\n");
+		return -EINVAL;
+	}
+	sr_cr[0] = ret;
+	sr_cr[1] |= CR_QUAD_EN_SPAN;
+
+	write_enable(nor);
+
+	ret = nor->write_reg(nor, SPINOR_OP_WRSR, sr_cr, 2);
+	if (ret < 0) {
+		dev_err(nor->dev,
+			"error while writing configuration register\n");
+		return -EINVAL;
+	}
+
+	ret = spi_nor_wait_till_ready(nor);
+	if (ret < 0) {
+		dev_err(nor->dev, "error while waiting for WRSR completion\n");
+		return ret;
+	}
+
+	/* read back and check it */
+	ret = read_cr(nor);
+	if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
+		dev_err(nor->dev, "Spansion Quad bit not set\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int sr2_bit7_quad_enable(struct spi_nor *nor)
+{
+	u8 sr2;
+	int ret;
+
+	/* Check current Quad Enable bit value. */
+	ret = nor->read_reg(nor, SPINOR_OP_RDSR2, &sr2, 1);
+	if (ret)
+		return ret;
+	if (sr2 & SR2_QUAD_EN_BIT7)
+		return 0;
+
+	/* Update the Quad Enable bit. */
+	sr2 |= SR2_QUAD_EN_BIT7;
+
+	write_enable(nor);
+
+	ret = nor->write_reg(nor, SPINOR_OP_WRSR2, &sr2, 1);
+	if (ret < 0) {
+		dev_err(nor->dev,
+			"error while writing status register 2\n");
+		return -EINVAL;
+	}
+
+	ret = spi_nor_wait_till_ready(nor);
+	if (ret < 0) {
+		dev_err(nor->dev, "error while waiting for WRSR2 completion\n");
+		return ret;
+	}
+
+	/* Read back and check it. */
+	ret = nor->read_reg(nor, SPINOR_OP_RDSR2, &sr2, 1);
+	if (ret || !(sr2 & SR2_QUAD_EN_BIT7)) {
+		dev_err(nor->dev, "SR2 Quad bit not set\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int spi_nor_check(struct spi_nor *nor)
 {
 	if (!nor->dev || !nor->read || !nor->write ||
@@ -1359,11 +1454,381 @@ static inline void spi_nor_set_erase_settings(struct spi_nor_erase_type *erase,
 	erase->opcode = opcode;
 }
 
+static int spi_nor_read_sfdp(struct spi_nor *nor, u32 addr,
+			     size_t len, void *buf)
+{
+	u8 addr_width, read_opcode, read_dummy;
+	int ret;
+
+	read_opcode = nor->read_opcode;
+	addr_width = nor->addr_width;
+	read_dummy = nor->read_dummy;
+
+	nor->read_opcode = SPINOR_OP_RDSFDP;
+	nor->addr_width = 3;
+	nor->read_dummy = 8;
+
+	ret = nor->read(nor, addr, len, (u8 *)buf);
+
+	nor->read_opcode = read_opcode;
+	nor->addr_width = addr_width;
+	nor->read_dummy = read_dummy;
+
+	return (ret < 0) ? ret : 0;
+}
+
+struct sfdp_parameter_header {
+	u8		id_lsb;
+	u8		minor;
+	u8		major;
+	u8		length; /* in double words */
+	u8		parameter_table_pointer[3]; /* byte address */
+	u8		id_msb;
+};
+
+#define SFDP_PARAM_HEADER_ID(p)	((u16)(((p)->id_msb << 8) | (p)->id_lsb))
+#define SFDP_PARAM_HEADER_PTP(p) \
+	((u32)(((p)->parameter_table_pointer[2] << 16) | \
+	       ((p)->parameter_table_pointer[1] <<  8) | \
+	       ((p)->parameter_table_pointer[0] <<  0)))
+
+
+#define SFDP_BFPT_ID		0xff00u	/* Basic Flash Parameter Table */
+
+#define SFDP_SIGNATURE		0x50444653u
+#define SFDP_JESD216_MAJOR	1
+#define SFDP_JESD216_MINOR	0
+#define SFDP_JESD216A_MINOR	5
+#define SFDP_JESD216B_MINOR	6
+
+struct sfdp_header {
+	u32		signature; /* Ox50444653 <=> "SFDP" */
+	u8		minor;
+	u8		major;
+	u8		nph; /* 0-base number of parameter headers */
+	u8		unused;
+
+	/* Basic Flash Parameter Table. */
+	struct sfdp_parameter_header	bfpt_header;
+};
+
+/* Basic Flash Parameter Table */
+
+/* 1st DWORD. */
+#define BFPT_WORD0_FAST_READ_1_1_2	BIT(16)
+#define BFPT_WORD0_ADDRESS_BYTES_MASK	GENMASK(18, 17)
+#define BFPT_WORD0_ADDRESS_BYTES_3_ONLY	(0u << 17)
+#define BFPT_WORD0_ADDRESS_BYTES_3_OR_4	(1u << 17)
+#define BFPT_WORD0_ADDRESS_BYTES_4_ONLY	(2u << 17)
+#define BFPT_WORD0_DTR			BIT(19)
+#define BFPT_WORD0_FAST_READ_1_2_2	BIT(20)
+#define BFPT_WORD0_FAST_READ_1_4_4	BIT(21)
+#define BFPT_WORD0_FAST_READ_1_1_4	BIT(22)
+
+/* 15th DWORD. */
+
+/*
+ * (from JESD216B)
+ * Quad Enable Requirements (QER):
+ * - 000b: Device does not have a QE bit. Device detects 1-1-4 and 1-4-4
+ *         reads based on instruction. DQ3/HOLD# functions are hold during
+ *         instruction pahse.
+ * - 001b: QE is bit 1 of status register 2. It is set via Write Status with
+ *         two data bytes where bit 1 of the second byte is one.
+ *         [...]
+ *         Writing only one byte to the status register has the side-effect of
+ *         clearing status register 2, including the QE bit. The 100b code is
+ *         used if writing one byte to the status register does not modify
+ *         status register 2.
+ * - 010b: QE is bit 6 of status register 1. It is set via Write Status with
+ *         one data byte where bit 6 is one.
+ *         [...]
+ * - 011b: QE is bit 7 of status register 2. It is set via Write status
+ *         register 2 instruction 3Eh with one data byte where bit 7 is one.
+ *         [...]
+ *         The status register 2 is read using instruction 3Fh.
+ * - 100b: QE is bit 1 of status register 2. It is set via Write Status with
+ *         two data bytes where bit 1 of the second byte is one.
+ *         [...]
+ *         In contrast to the 001b code, writing one byte to the status
+ *         register does not modify status register 2.
+ * - 101b: QE is bit 1 of status register 2. Status register 1 is read using
+ *         Read Status instruction 05h. Status register2 is read using
+ *         instruction 35h. QE is set via Writ Status instruction 01h with
+ *         two data bytes where bit 1 of the second byte is one.
+ *         [...]
+ */
+#define BFPT_WORD14_QER_MASK		GENMASK(22, 20)
+#define BFPT_WORD14_QER_NONE		(0 << 20) /* Micron */
+#define BFPT_WORD14_QER_SR2_BIT1_BUGGY	(1 << 20)
+#define BFPT_WORD14_QER_SR1_BIT6	(2 << 20) /* Macronix */
+#define BFPT_WORD14_QER_SR2_BIT7	(3 << 20)
+#define BFPT_WORD14_QER_SR2_BIT1_NO_RD	(4 << 20)
+#define BFPT_WORD14_QER_SR2_BIT1	(5 << 20) /* Spansion */
+
+/* JESD216B defines a Basic Flash Parameter Table of 16 words. */
+#define SFDP_BFPT_MAX_WORDS	16
+
+struct sfdp_bfpt {
+	u32	word[SFDP_BFPT_MAX_WORDS];
+};
+
+/* Fast Read settings. */
+#define BFPT_FAST_READ_WAIT_STATES(half)	((((u16)(half)) >> 0) & 0x1f)
+#define BFPT_FAST_READ_MODE_CLOCKS(half)	((((u16)(half)) >> 5) & 0x07)
+#define BFPT_FAST_READ_OP_CODE(half)		((((u16)(half)) >> 8) & 0xff)
+
+struct sfdp_read {
+	/* The protocol index of SPI x-y-z. */
+	enum spi_nor_protocol_index	pindex;
+
+	/*
+	 * The bit <wbit> in DWORD<windex> tells us whether the
+	 * Fast Read x-y-z command is supported.
+	 */
+	int				windex;
+	int				wbit;
+
+	/*
+	 * The half-word at offset <hshift> in DWORD<hindex> encodes the
+	 * op code, the number of mode clocks and the number of wait states
+	 * to be used by Fast Read x-y-z commands.
+	 */
+	int				hindex;
+	int				hshift;
+};
+
+static const struct sfdp_read sfdp_reads[] = {
+	/* Supported: DWORD0 bit 16,  Settings: DWORD3 bit[15:0] */
+	{SNOR_PINDEX_1_1_2, 0, 16, 3,  0},
+
+	/* Supported: DWORD0 bit 20,  Settings: DWORD3 bit[31:16] */
+	{SNOR_PINDEX_1_2_2, 0, 20, 3, 16},
+
+	/* Supported: DWORD4 bit  0,  Settings: DWORD5 bit[31:16] */
+	{SNOR_PINDEX_2_2_2, 4,  0, 5, 16},
+
+	/* Supported: DWORD0 bit 22,  Settings: DWORD2 bit[31:16] */
+	{SNOR_PINDEX_1_1_4, 0, 22, 2, 16},
+
+	/* Supported: DWORD0 bit 21,  Settings: DWORD2 bit[15:0] */
+	{SNOR_PINDEX_1_4_4, 0, 21, 2, 0},
+
+	/* Supported: DWORD4 bit  4,  Settings: DWORD6 bit[31:16] */
+	{SNOR_PINDEX_4_4_4, 4, 4, 6, 16},
+};
+
+
+/* Sector Erase settings. */
+#define BFPT_ERASE_SIZE(half)		((((u16)(half)) >> 0) & 0xff)
+#define BFPT_ERASE_OP_CODE(half)	((((u16)(half)) >> 8) & 0xff)
+
+struct sfdp_erase {
+	/*
+	 * The half-word at offset <hshift> in DWORD<hindex> encodes the
+	 * op code and erase sector size to be used by Sector Erase commands.
+	 */
+	int		hindex;
+	int		hshift;
+};
+
+static const struct sfdp_erase sfdp_erases[SNOR_MAX_ERASE_TYPES] = {
+	/* Erase Type 1 in DWORD7 bits[15:0] */
+	{7, 0},
+
+	/* Erase Type 2 in DWORD7 bits[31:16] */
+	{7, 16},
+
+	/* Erase Type 3 in DWORD8 bits[15:0] */
+	{8, 0},
+
+	/* Erase Type 4: in DWORD8 bits[31:16] */
+	{8, 16},
+};
+
+
+static int spi_nor_parse_bfpt(struct spi_nor *nor,
+			      const struct sfdp_parameter_header *bfpt_header,
+			      struct spi_nor_basic_flash_parameter *params)
+{
+	struct sfdp_bfpt bfpt;
+	size_t len;
+	int i, err;
+	u32 addr;
+	u16 half;
+
+	/* JESD216 Basic Flash Parameter Table length is at least 9 words. */
+	if (bfpt_header->length < 9)
+		return -EINVAL;
+
+	/* Read the Basic Flash Parameter Table. */
+	len = min_t(size_t, sizeof(bfpt),
+		    bfpt_header->length * sizeof(uint32_t));
+	addr = SFDP_PARAM_HEADER_PTP(bfpt_header);
+	memset(&bfpt, 0, sizeof(bfpt));
+	err = spi_nor_read_sfdp(nor,  addr, len, &bfpt);
+	if (err)
+		return err;
+
+	for (i = 0; i < SFDP_BFPT_MAX_WORDS; ++i)
+		bfpt.word[i] = le32_to_cpu(bfpt.word[i]);
+
+	memset(params, 0, sizeof(*params));
+
+	/* Fast Read settings. */
+	params->rd_modes = (SNOR_MODE_SLOW | SNOR_MODE_1_1_1);
+	spi_nor_set_read_settings(&params->reads[SNOR_PINDEX_SLOW],
+				  0, 0, SPINOR_OP_READ);
+	spi_nor_set_read_settings(&params->reads[SNOR_PINDEX_1_1_1],
+				  0, 8, SPINOR_OP_READ_FAST);
+
+	for (i = 0; i < ARRAY_SIZE(sfdp_reads); ++i) {
+		const struct sfdp_read *rd_info = &sfdp_reads[i];
+		struct spi_nor_read *read = &params->reads[rd_info->pindex];
+
+		if (!(bfpt.word[rd_info->windex] & BIT(rd_info->wbit)))
+			continue;
+
+		params->rd_modes |= BIT(rd_info->pindex);
+		half = bfpt.word[rd_info->hindex] >> rd_info->hshift;
+		read->num_mode_clocks = BFPT_FAST_READ_MODE_CLOCKS(half);
+		read->num_wait_states = BFPT_FAST_READ_WAIT_STATES(half);
+		read->opcode = BFPT_FAST_READ_OP_CODE(half);
+	}
+
+	/* Page Program settings. */
+	params->wr_modes = SNOR_MODE_1_1_1;
+	params->page_programs[SNOR_PINDEX_1_1_1] = SPINOR_OP_PP;
+
+	/* Sector Erase settings. */
+	for (i = 0; i < SNOR_MAX_ERASE_TYPES; ++i) {
+		const struct sfdp_erase *er_info = &sfdp_erases[i];
+		struct spi_nor_erase_type *erase = &params->erase_types[i];
+
+		half = bfpt.word[er_info->hindex] >> er_info->hshift;
+		erase->size = BFPT_ERASE_SIZE(half);
+		erase->opcode = BFPT_ERASE_OP_CODE(half);
+	}
+
+	/* Stop here if not JESD216 rev A or later. */
+	if (bfpt_header->length < 15)
+		return 0;
+
+	/* Enable Quad I/O. */
+	switch (bfpt.word[14] & BFPT_WORD14_QER_MASK) {
+	default:
+	case BFPT_WORD14_QER_NONE:
+		break;
+
+	case BFPT_WORD14_QER_SR2_BIT1_BUGGY:
+	case BFPT_WORD14_QER_SR2_BIT1_NO_RD:
+		params->enable_quad_io = spansion_quad_enable;
+		break;
+
+	case BFPT_WORD14_QER_SR1_BIT6:
+		params->enable_quad_io = macronix_quad_enable;
+		break;
+
+	case BFPT_WORD14_QER_SR2_BIT7:
+		params->enable_quad_io = sr2_bit7_quad_enable;
+		break;
+
+	case BFPT_WORD14_QER_SR2_BIT1:
+		params->enable_quad_io = spansion_new_quad_enable;
+		break;
+	}
+
+	return 0;
+}
+
+static int spi_nor_parse_sfdp(struct spi_nor *nor,
+			      struct spi_nor_basic_flash_parameter *params)
+{
+	const struct sfdp_parameter_header *param_header, *bfpt_header;
+	struct sfdp_parameter_header *param_headers = NULL;
+	struct sfdp_header header;
+	size_t psize;
+	int i, err;
+
+	/* Get the SFDP header. */
+	err = spi_nor_read_sfdp(nor, 0, sizeof(header), &header);
+	if (err)
+		return err;
+
+	/* Check the SFDP header version. */
+	if (le32_to_cpu(header.signature) != SFDP_SIGNATURE ||
+	    header.major != SFDP_JESD216_MAJOR ||
+	    header.minor < SFDP_JESD216_MINOR)
+		return -EINVAL;
+
+	/*
+	 * Verify that the first and only mandatory parameter header is a
+	 * Basic Flash Parameter Table header as specified in JESD216.
+	 */
+	bfpt_header = &header.bfpt_header;
+	if (SFDP_PARAM_HEADER_ID(bfpt_header) != SFDP_BFPT_ID ||
+	    bfpt_header->major != SFDP_JESD216_MAJOR)
+		return -EINVAL;
+
+	/* Allocate memory for parameter headers. */
+	if (header.nph) {
+		psize = header.nph * sizeof(*param_headers);
+
+		param_headers = kmalloc(psize, GFP_KERNEL);
+		if (!param_headers) {
+			dev_err(nor->dev,
+				"failed to allocate memory for SFDP parameter headers\n");
+			return -ENOMEM;
+		}
+
+		err = spi_nor_read_sfdp(nor, sizeof(header),
+					psize, param_headers);
+		if (err) {
+			dev_err(nor->dev,
+				"failed to read SFDP parameter headers\n");
+			goto exit;
+		}
+	}
+
+	/*
+	 * Check other parameter headers to get the latest revision of
+	 * the basic flash parameter table.
+	 */
+	for (i = 0; i < header.nph; ++i) {
+		param_header = &param_headers[i];
+
+		if (SFDP_PARAM_HEADER_ID(param_header) == SFDP_BFPT_ID &&
+		    param_header->major == SFDP_JESD216_MAJOR &&
+		    (param_header->minor > bfpt_header->minor ||
+		     (param_header->minor == bfpt_header->minor &&
+		      param_header->length > bfpt_header->length)))
+			bfpt_header = param_header;
+	}
+	err = spi_nor_parse_bfpt(nor, bfpt_header, params);
+	if (err)
+		goto exit;
+
+exit:
+	kfree(param_headers);
+	return (err) ? err : bfpt_header->minor;
+}
+
 static int spi_nor_init_params(struct spi_nor *nor,
 			       const struct flash_info *info,
 			       struct spi_nor_basic_flash_parameter *params)
 {
-	// TODO: parse SFDP table
+	int jesd216_minor = -EINVAL;
+
+	/* First trying to parse SFDP tables. */
+	if (!(info->flags & SPI_NOR_SKIP_SFDP)) {
+		jesd216_minor = spi_nor_parse_sfdp(nor, params);
+
+		if (jesd216_minor >= SFDP_JESD216A_MINOR)
+			return 0;
+
+		if (jesd216_minor >= SFDP_JESD216_MINOR)
+			goto set_enable_quad_io;
+	}
 
 	/* If SFDP tables are not available, use legacy settings. */
 	memset(params, 0, sizeof(*params));
@@ -1402,6 +1867,7 @@ static int spi_nor_init_params(struct spi_nor *nor,
 		spi_nor_set_erase_settings(&params->erase_types[1],
 					   SNOR_ERASE_4K, SPINOR_OP_BE_4K_PMC);
 
+set_enable_quad_io:
 	/* Select the procedure to set the Quad Enable bit. */
 	if (params->rd_modes & (SNOR_MODE_1_1_4 |
 				SNOR_MODE_1_4_4 |
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 88ac446b1230..8fd9619dabff 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -41,6 +41,8 @@
 #define SPINOR_OP_WREN		0x06	/* Write enable */
 #define SPINOR_OP_RDSR		0x05	/* Read status register */
 #define SPINOR_OP_WRSR		0x01	/* Write status register 1 byte */
+#define SPINOR_OP_RDSR2		0x3f	/* Read status register 2 */
+#define SPINOR_OP_WRSR2		0x3e	/* Write status register 2 */
 #define SPINOR_OP_READ		0x03	/* Read data bytes (low frequency) */
 #define SPINOR_OP_READ_FAST	0x0b	/* Read data bytes (high frequency) */
 #define SPINOR_OP_READ_1_1_2	0x3b	/* Read data bytes (Dual Output SPI) */
@@ -56,6 +58,7 @@
 #define SPINOR_OP_CHIP_ERASE	0xc7	/* Erase whole flash chip */
 #define SPINOR_OP_SE		0xd8	/* Sector erase (usually 64KiB) */
 #define SPINOR_OP_RDID		0x9f	/* Read JEDEC ID */
+#define SPINOR_OP_RDSFDP	0x5a	/* Read SFDP */
 #define SPINOR_OP_RDCR		0x35	/* Read configuration register */
 #define SPINOR_OP_RDFSR		0x70	/* Read flag status register */
 
@@ -110,6 +113,9 @@
 /* Configuration Register bits. */
 #define CR_QUAD_EN_SPAN		BIT(1)	/* Spansion Quad I/O */
 
+/* Status Register 2 bits. */
+#define SR2_QUAD_EN_BIT7	BIT(7)
+
 
 /* Supported SPI protocols */
 enum spi_nor_protocol_class {
-- 
2.7.4



From cyrille.pitchen at atmel.com  Mon Oct 24 09:34:44 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Mon, 24 Oct 2016 18:34:44 +0200
Subject: [PATCH v3 7/9] mtd: spi-nor: parse SFDP 4-byte Address Instruction
 Table
In-Reply-To: <cover.1477325128.git.cyrille.pitchen@atmel.com>
References: <cover.1477325128.git.cyrille.pitchen@atmel.com>
Message-ID: <532cec0bb68094065beb637c776163498a22f9f2.1477325128.git.cyrille.pitchen@atmel.com>

This patch adds supports for SFDP (JESD216B) 4-byte Address Instruction
Table. This table is optional but when available, we parse it to get the
4-byte address op codes supported by the memory.
Using these op codes is stateless as opposed to entering the 4-byte
address mode or setting the Base Address Register (BAR).

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 140 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 139 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 7fc0138c1d68..db4874d4af79 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1494,6 +1494,7 @@ struct sfdp_parameter_header {
 
 
 #define SFDP_BFPT_ID		0xff00u	/* Basic Flash Parameter Table */
+#define SFDP_4BAIT_ID		0xff84u	/* 4-byte Address Instruction Table */
 
 #define SFDP_SIGNATURE		0x50444653u
 #define SFDP_JESD216_MAJOR	1
@@ -1741,6 +1742,124 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
 	return 0;
 }
 
+struct sfdp_4bait {
+	enum spi_nor_protocol_index	pindex;
+	int				wbit;
+};
+
+static int spi_nor_parse_4bait(struct spi_nor *nor,
+			       const struct sfdp_parameter_header *param_header,
+			       struct spi_nor_basic_flash_parameter *params)
+{
+	static const struct sfdp_4bait reads[] = {
+		{SNOR_PINDEX_SLOW,  0},	/* 0x13 */
+		{SNOR_PINDEX_1_1_1, 1}, /* 0x0c */
+		{SNOR_PINDEX_1_1_2, 2}, /* 0x3c */
+		{SNOR_PINDEX_1_2_2, 3},	/* 0xbc */
+		{SNOR_PINDEX_1_1_4, 4},	/* 0x6c */
+		{SNOR_PINDEX_1_4_4, 5},	/* 0xec */
+	};
+	static const struct sfdp_4bait programs[] = {
+		{SNOR_PINDEX_1_1_1, 6}, /* 0x12 */
+		{SNOR_PINDEX_1_1_4, 7}, /* 0x34 */
+		{SNOR_PINDEX_1_4_4, 8}, /* 0x3e */
+	};
+	static const struct sfdp_4bait erases[SNOR_MAX_ERASE_TYPES] = {
+		{SNOR_PINDEX_1_1_1,  9},
+		{SNOR_PINDEX_1_1_1, 10},
+		{SNOR_PINDEX_1_1_1, 11},
+		{SNOR_PINDEX_1_1_1, 12},
+	};
+	u32 word[2], addr, rd_modes, wr_modes, erase_modes;
+	int i, err;
+
+	if (param_header->major != SFDP_JESD216_MAJOR ||
+	    param_header->length < 2)
+		return -EINVAL;
+
+	/* Read the 4-byte Address Instruction Table. */
+	addr = SFDP_PARAM_HEADER_PTP(param_header);
+	err = spi_nor_read_sfdp(nor, addr, sizeof(word), word);
+	if (err)
+		return err;
+
+	for (i = 0; i < 2; ++i)
+		word[i] = le32_to_cpu(word[i]);
+
+	/*
+	 * Compute the subset of (Fast) Read commands for which the 4-byte
+	 * version is supported.
+	 */
+	rd_modes = 0;
+	for (i = 0; i < ARRAY_SIZE(reads); ++i) {
+		const struct sfdp_4bait *read = &reads[i];
+
+		if ((params->rd_modes & BIT(read->pindex)) &&
+		    (word[0] & BIT(read->wbit)))
+			rd_modes |= BIT(read->pindex);
+	}
+
+	/*
+	 * Compute the subset of Page Program commands for which the 4-byte
+	 * version is supported.
+	 */
+	wr_modes = 0;
+	for (i = 0; i < ARRAY_SIZE(programs); ++i) {
+		const struct sfdp_4bait *program = &programs[i];
+
+		if ((params->wr_modes & BIT(program->pindex)) &&
+		    (word[0] & BIT(program->wbit)))
+			wr_modes |= BIT(program->pindex);
+	}
+
+	/*
+	 * Compute the subet of Sector Erase commands for which the 4-byte
+	 * version is supported.
+	 */
+	erase_modes = 0;
+	for (i = 0; i < SNOR_MAX_ERASE_TYPES; ++i) {
+		const struct sfdp_4bait *erase = &erases[i];
+
+		if ((params->erase_types[i].size > 0) &&
+		    (word[0] & BIT(erase->wbit)))
+			erase_modes |= BIT(i);
+	}
+
+	/*
+	 * We need at least one 4-byte op code per read, program and erase
+	 * operation; the .read(), .write() and .erase() hooks share the
+	 * nor->addr_width value.
+	 */
+	if (!rd_modes || !wr_modes || !erase_modes)
+		return 0;
+
+	/*
+	 * Discard all operations from the 4-byte instruction set which are
+	 * not supported by this memory.
+	 */
+	params->rd_modes = rd_modes;
+	params->wr_modes = wr_modes;
+	for (i = 0; i < SNOR_MAX_ERASE_TYPES; ++i)
+		if (!(erase_modes & BIT(i)))
+			params->erase_types[i].size = 0;
+
+	/* Use the 4-byte address instruction set. */
+	params->reads[SNOR_PINDEX_SLOW].opcode  = SPINOR_OP_READ_4B;
+	params->reads[SNOR_PINDEX_1_1_1].opcode = SPINOR_OP_READ_FAST_4B;
+	params->reads[SNOR_PINDEX_1_1_2].opcode = SPINOR_OP_READ_1_1_2_4B;
+	params->reads[SNOR_PINDEX_1_2_2].opcode = SPINOR_OP_READ_1_2_2_4B;
+	params->reads[SNOR_PINDEX_1_1_4].opcode = SPINOR_OP_READ_1_1_4_4B;
+	params->reads[SNOR_PINDEX_1_4_4].opcode = SPINOR_OP_READ_1_4_4_4B;
+	params->page_programs[SNOR_PINDEX_1_1_1] = SPINOR_OP_PP_4B;
+	params->page_programs[SNOR_PINDEX_1_1_4] = SPINOR_OP_PP_1_1_4_4B;
+	params->page_programs[SNOR_PINDEX_1_4_4] = SPINOR_OP_PP_1_4_4_4B;
+	for (i = 0; i < SNOR_MAX_ERASE_TYPES; ++i)
+		params->erase_types[i].opcode = (word[1] >> (i * 8)) & 0xff;
+
+	nor->addr_width = 4;
+	return 0;
+}
+
 static int spi_nor_parse_sfdp(struct spi_nor *nor,
 			      struct spi_nor_basic_flash_parameter *params)
 {
@@ -1808,6 +1927,23 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor,
 	if (err)
 		goto exit;
 
+	/* Parse other parameter headers. */
+	for (i = 0; i < header.nph; ++i) {
+		param_header = &param_headers[i];
+
+		switch (SFDP_PARAM_HEADER_ID(param_header)) {
+		case SFDP_4BAIT_ID:
+			err = spi_nor_parse_4bait(nor, param_header, params);
+			break;
+
+		default:
+			break;
+		}
+
+		if (err)
+			goto exit;
+	}
+
 exit:
 	kfree(param_headers);
 	return (err) ? err : bfpt_header->minor;
@@ -2162,7 +2298,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
 	if (ret)
 		return ret;
 
-	if (info->addr_width)
+	if (nor->addr_width)
+		; /* already configured by spi_nor_setup(). */
+	else if (info->addr_width)
 		nor->addr_width = info->addr_width;
 	else if (mtd->size > 0x1000000) {
 		/* enable 4-byte addressing if the device exceeds 16MiB */
-- 
2.7.4



From cyrille.pitchen at atmel.com  Mon Oct 24 09:34:45 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Mon, 24 Oct 2016 18:34:45 +0200
Subject: [PATCH v3 8/9] mtd: spi-nor: add support to Macronix mx66l1g45g
In-Reply-To: <cover.1477325128.git.cyrille.pitchen@atmel.com>
References: <cover.1477325128.git.cyrille.pitchen@atmel.com>
Message-ID: <4db277dccf52acd48e592d9f285724aab70704d1.1477325128.git.cyrille.pitchen@atmel.com>

This patch adds an entry in the spi_nor_ids[] table to add support
to the Macronix mx66l1g45g.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index db4874d4af79..eb21d3d4e4e6 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -937,6 +937,7 @@ static const struct flash_info spi_nor_ids[] = {
 	{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
 	{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
 	{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) },
+	{ "mx66l1g45g",  INFO(0xc2201b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
 	{ "mx66l1g55g",  INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
 
 	/* Micron */
-- 
2.7.4



From cyrille.pitchen at atmel.com  Mon Oct 24 09:34:46 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Mon, 24 Oct 2016 18:34:46 +0200
Subject: [PATCH v3 9/9] mtd: spi-nor: add support to SST sst26* QSPI memories
In-Reply-To: <cover.1477325128.git.cyrille.pitchen@atmel.com>
References: <cover.1477325128.git.cyrille.pitchen@atmel.com>
Message-ID: <74fedab98fba683d3563ac8c93d1fac6108ba278.1477325128.git.cyrille.pitchen@atmel.com>

This patch adds support to the SST sst26* QSPI memories.
It also adds a new SST_BLOCK_PROTECT flag so spi_nor_scan() sends
a SST Global Block Protection Unlock (98h) command once for all
otherwise later Sector Erase and Page Program commands would fail.

It was tested with sst26vf016b, sst26vf032b, sst26vf032ba and sst26vf064b
on a sama5d2 xplained board at 55.3MHz and 3.3V.

sst26wf040b and sst26wf080b were not tested since they are 1.8V memories
hence don't fit the sama5d2 xplained board requirements.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 20 ++++++++++++++++++++
 include/linux/mtd/spi-nor.h   |  1 +
 2 files changed, 21 insertions(+)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index eb21d3d4e4e6..300ee38f4e9a 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -81,6 +81,7 @@ struct flash_info {
 					 * to support memory size above 128Mib.
 					 */
 #define SPI_NOR_SKIP_SFDP	BIT(11) /* Skip read of SFDP tables */
+#define SST_BLOCK_PROTECT	BIT(12)	/* use SST Unlock Block-Protection */
 };
 
 #define JEDEC_MFR(info)	((info)->id[0])
@@ -999,6 +1000,11 @@ static const struct flash_info 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 | SST_BLOCK_PROTECT) },
+	{ "sst26vf032b", INFO(0xbf2642, 0, 64 * 1024, 64, SECT_4K | SST_BLOCK_PROTECT) },
+	{ "sst26vf064b", INFO(0xbf2643, 0, 64 * 1024, 128, SECT_4K | SST_BLOCK_PROTECT) },
+	{ "sst26wf040b", INFO(0xbf2654, 0, 64 * 1024,  8, SECT_4K | SST_BLOCK_PROTECT) },
+	{ "sst26wf080b", INFO(0xbf2658, 0, 64 * 1024, 16, SECT_4K | SST_BLOCK_PROTECT) },
 
 	/* ST Microelectronics -- newer production may have feature updates */
 	{ "m25p05",  INFO(0x202010,  0,  32 * 1024,   2, 0) },
@@ -1135,6 +1141,14 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
 	return ret;
 }
 
+static int sst_unlock_block_protection(struct spi_nor *nor)
+{
+	int ret;
+
+	ret = write_enable(nor);
+	return ret ? ret : nor->write_reg(nor, SPINOR_OP_ULBPR, NULL, 0);
+}
+
 static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
 		size_t *retlen, const u_char *buf)
 {
@@ -2321,6 +2335,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
 		return -EINVAL;
 	}
 
+	if (info->flags & SST_BLOCK_PROTECT) {
+		ret = sst_unlock_block_protection(nor);
+		if (ret)
+			return ret;
+	}
+
 	dev_info(dev, "%s (%lld Kbytes)\n", info->name,
 			(long long)mtd->size >> 10);
 
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 8fd9619dabff..c8f7e231a25c 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -80,6 +80,7 @@
 #define SPINOR_OP_BP		0x02	/* Byte program */
 #define SPINOR_OP_WRDI		0x04	/* Write disable */
 #define SPINOR_OP_AAI_WP	0xad	/* Auto address increment word program */
+#define SPINOR_OP_ULBPR		0x98	/* Global Block Protection Unlock */
 
 /* Used for Macronix and Winbond flashes. */
 #define SPINOR_OP_EN4B		0xb7	/* Enter 4-byte mode */
-- 
2.7.4



From sergio.prado at e-labworks.com  Mon Oct 24 11:47:38 2016
From: sergio.prado at e-labworks.com (Sergio Prado)
Date: Mon, 24 Oct 2016 16:47:38 -0200
Subject: [PATCH v3 3/3] mtd: s3c2410: parse the device configuration from
 OF node
In-Reply-To: <20161024150201.01952f67@bbrezillon>
References: <1476999766-32526-1-git-send-email-sergio.prado@e-labworks.com>
 <1476999766-32526-4-git-send-email-sergio.prado@e-labworks.com>
 <20161024150201.01952f67@bbrezillon>
Message-ID: <20161024184738.GA26671@sprado-desktop>

On Mon, Oct 24, 2016 at 03:02:01PM +0200, Boris Brezillon wrote:
> > +static int s3c2410_nand_setup_data_interface(struct mtd_info *mtd,
> > +					     const struct nand_data_interface *conf,
> > +					     bool check_only)
> > +{
> > +	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
> > +	struct s3c2410_platform_nand *pdata = info->platform;
> > +	const struct nand_sdr_timings *timings;
> > +	int tacls;
> > +
> > +	timings = nand_get_sdr_timings(conf);
> > +	if (IS_ERR(timings))
> > +		return -ENOTSUPP;
> > +
> > +	tacls = timings->tCLS_min - timings->tWP_min;
> > +	if (tacls < 0)
> > +		tacls = 0;
> > +
> > +	pdata->tacls  = DIV_ROUND_UP(tacls, 1000);
> > +	pdata->twrph0 = DIV_ROUND_UP(timings->tWP_min, 1000);
> > +	pdata->twrph1 = DIV_ROUND_UP(timings->tCLH_min, 1000);
> 
> You seem to only apply the timings in s3c2410_nand_setrate(), which is
> only called at probe time or on a cpufreq even, but the core can change
> timings at runtime (this is what happens each time you reset the chip).
> 
> To support that you have 2 options:
>  - apply the timings in ->select_chip()
>  - apply the timings here

Right. As far as I understood, ->setup_data_interface() will be called
when MTD core change timings at runtime, so it is enough to apply the
timings in the end of ->setup_data_interface()?

Thanks,

Sergio Prado


From boris.brezillon at free-electrons.com  Mon Oct 24 11:50:56 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Mon, 24 Oct 2016 20:50:56 +0200
Subject: [PATCH v3 3/3] mtd: s3c2410: parse the device configuration
 from OF node
In-Reply-To: <20161024184738.GA26671@sprado-desktop>
References: <1476999766-32526-1-git-send-email-sergio.prado@e-labworks.com>
 <1476999766-32526-4-git-send-email-sergio.prado@e-labworks.com>
 <20161024150201.01952f67@bbrezillon>
 <20161024184738.GA26671@sprado-desktop>
Message-ID: <20161024205056.1782f76e@bbrezillon>

On Mon, 24 Oct 2016 16:47:38 -0200
Sergio Prado <sergio.prado at e-labworks.com> wrote:

> On Mon, Oct 24, 2016 at 03:02:01PM +0200, Boris Brezillon wrote:
> > > +static int s3c2410_nand_setup_data_interface(struct mtd_info *mtd,
> > > +					     const struct nand_data_interface *conf,
> > > +					     bool check_only)
> > > +{
> > > +	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
> > > +	struct s3c2410_platform_nand *pdata = info->platform;
> > > +	const struct nand_sdr_timings *timings;
> > > +	int tacls;
> > > +
> > > +	timings = nand_get_sdr_timings(conf);
> > > +	if (IS_ERR(timings))
> > > +		return -ENOTSUPP;
> > > +
> > > +	tacls = timings->tCLS_min - timings->tWP_min;
> > > +	if (tacls < 0)
> > > +		tacls = 0;
> > > +
> > > +	pdata->tacls  = DIV_ROUND_UP(tacls, 1000);
> > > +	pdata->twrph0 = DIV_ROUND_UP(timings->tWP_min, 1000);
> > > +	pdata->twrph1 = DIV_ROUND_UP(timings->tCLH_min, 1000);  
> > 
> > You seem to only apply the timings in s3c2410_nand_setrate(), which is
> > only called at probe time or on a cpufreq even, but the core can change
> > timings at runtime (this is what happens each time you reset the chip).
> > 
> > To support that you have 2 options:
> >  - apply the timings in ->select_chip()
> >  - apply the timings here  
> 
> Right. As far as I understood, ->setup_data_interface() will be called
> when MTD core change timings at runtime, so it is enough to apply the
> timings in the end of ->setup_data_interface()?

If your controller does not support interfacing with multiple chips,
then yes, it should work.


From marek.vasut at gmail.com  Mon Oct 24 13:47:59 2016
From: marek.vasut at gmail.com (Marek Vasut)
Date: Mon, 24 Oct 2016 22:47:59 +0200
Subject: [PATCH] mtd: ichxrom: maybe-uninitialized with gcc-4.9
In-Reply-To: <20161024152853.2673518-1-arnd@arndb.de>
References: <20161024152853.2673518-1-arnd@arndb.de>
Message-ID: <470c5483-949c-6e2a-cd52-73d99748b312@gmail.com>

On 10/24/2016 05:28 PM, Arnd Bergmann wrote:
> pci_read_config_word() might fail and not initialize its output,
> as pointed out by older versions of gcc when using the -Wmaybe-unintialized
> flag:
> 
> drivers/mtd/maps/ichxrom.c: In function ?ichxrom_cleanup?:
> drivers/mtd/maps/ichxrom.c:63:2: error: ?word? is used uninitialized in this function [-Werror=uninitialized]
> 
> This is apparently a correct warning, though it does not show up
> with newer compilers. Changing the code to not attempt to write
> back uninitialized data into PCI config space is a correct
> fix for the problem and avoids the warning.
> 
> Signed-off-by: Arnd Bergmann <arnd at arndb.de>

Reviewed-by: Marek Vasut <marex at denx.de>

> ---
>  drivers/mtd/maps/ichxrom.c | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c
> index e17d02ae03f0..976d42f63aef 100644
> --- a/drivers/mtd/maps/ichxrom.c
> +++ b/drivers/mtd/maps/ichxrom.c
> @@ -57,10 +57,12 @@ static void ichxrom_cleanup(struct ichxrom_window *window)
>  {
>  	struct ichxrom_map_info *map, *scratch;
>  	u16 word;
> +	int ret;
>  
>  	/* Disable writes through the rom window */
> -	pci_read_config_word(window->pdev, BIOS_CNTL, &word);
> -	pci_write_config_word(window->pdev, BIOS_CNTL, word & ~1);
> +	ret = pci_read_config_word(window->pdev, BIOS_CNTL, &word);
> +	if (!ret)
> +		pci_write_config_word(window->pdev, BIOS_CNTL, word & ~1);
>  	pci_dev_put(window->pdev);
>  
>  	/* Free all of the mtd devices */
> 


-- 
Best regards,
Marek Vasut


From marex at denx.de  Mon Oct 24 15:00:33 2016
From: marex at denx.de (Marek Vasut)
Date: Tue, 25 Oct 2016 00:00:33 +0200
Subject: [PATCH v3 1/9] mtd: spi-nor: improve macronix_quad_enable()
In-Reply-To: <c63d3715903e640c7ea5328614bd4468688b761d.1477325128.git.cyrille.pitchen@atmel.com>
References: <cover.1477325128.git.cyrille.pitchen@atmel.com>
 <c63d3715903e640c7ea5328614bd4468688b761d.1477325128.git.cyrille.pitchen@atmel.com>
Message-ID: <74f0fa1b-3212-8a21-f966-14f153d2bf43@denx.de>

On 10/24/2016 06:34 PM, Cyrille Pitchen wrote:
> The patch checks whether the Quad Enable bit is already set in the Status
> Register. If so, the function exits immediately with a successful return
> code. Otherwise, a message is now printed telling we're setting the
> non-volatile bit.
> 
> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
> Reviewed-by: Jagan Teki <jagan at openedev.com>
> ---
>  drivers/mtd/spi-nor/spi-nor.c | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
> index d0fc165d7d66..5c87b2d99507 100644
> --- a/drivers/mtd/spi-nor/spi-nor.c
> +++ b/drivers/mtd/spi-nor/spi-nor.c
> @@ -1211,6 +1211,11 @@ static int macronix_quad_enable(struct spi_nor *nor)
>  	val = read_sr(nor);
>  	if (val < 0)
>  		return val;
> +	if (val & SR_QUAD_EN_MX)
> +		return 0;
> +
> +	/* Update the Quad Enable bit. */
> +	dev_info(nor->dev, "setting Macronix Quad Enable (non-volatile) bit\n");

Should probably be dev_dbg(), since this is just churn in the kernel
log. The user doesn't care and the developer can just up the debug level
or add his own printk .

>  	write_enable(nor);
>  
>  	write_sr(nor, val | SR_QUAD_EN_MX);
> 


-- 
Best regards,
Marek Vasut


From marex at denx.de  Mon Oct 24 15:15:02 2016
From: marex at denx.de (Marek Vasut)
Date: Tue, 25 Oct 2016 00:15:02 +0200
Subject: [PATCH v3 5/9] mtd: m25p80: add support of dual and quad spi
 protocols to all commands
In-Reply-To: <20bbf1848567ce25c5ab58b1bf1a710c44fec2ac.1477325128.git.cyrille.pitchen@atmel.com>
References: <cover.1477325128.git.cyrille.pitchen@atmel.com>
 <20bbf1848567ce25c5ab58b1bf1a710c44fec2ac.1477325128.git.cyrille.pitchen@atmel.com>
Message-ID: <73101e7a-379f-f6a6-58b0-94966c821be4@denx.de>

On 10/24/2016 06:34 PM, Cyrille Pitchen wrote:
> Before this patch, m25p80_read() supported few SPI protocols:
> - regular SPI 1-1-1
> - SPI Dual Output 1-1-2
> - SPI Quad Output 1-1-4
> On the other hand, all other m25p80_*() hooks only supported SPI 1-1-1.
> 
> This patch adds support to all currently existing SPI protocols to
> cover as many protocols as possible.
> 
> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
> ---
>  drivers/mtd/devices/m25p80.c | 193 +++++++++++++++++++++++++++++++++----------
>  1 file changed, 149 insertions(+), 44 deletions(-)
> 
> diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
> index f0a55c01406b..38778eac6c21 100644
> --- a/drivers/mtd/devices/m25p80.c
> +++ b/drivers/mtd/devices/m25p80.c
> @@ -27,22 +27,64 @@
>  #include <linux/spi/flash.h>
>  #include <linux/mtd/spi-nor.h>
>  
> -#define	MAX_CMD_SIZE		6
> +#define	MAX_CMD_SIZE		16
>  struct m25p {
>  	struct spi_device	*spi;
>  	struct spi_nor		spi_nor;
>  	u8			command[MAX_CMD_SIZE];
>  };
>  
> +static inline int m25p80_proto2nbits(enum spi_nor_protocol proto,

This can be void , since it's always returning zero.

> +				     unsigned *code_nbits,
> +				     unsigned *addr_nbits,
> +				     unsigned *data_nbits)
> +{
> +	if (code_nbits)
> +		*code_nbits = SNOR_PROTO_CODE_FROM_PROTO(proto);
> +	if (addr_nbits)
> +		*addr_nbits = SNOR_PROTO_ADDR_FROM_PROTO(proto);
> +	if (data_nbits)
> +		*data_nbits = SNOR_PROTO_DATA_FROM_PROTO(proto);
> +
> +	return 0;
> +}
> +
[...]


-- 
Best regards,
Marek Vasut


From marex at denx.de  Mon Oct 24 15:10:57 2016
From: marex at denx.de (Marek Vasut)
Date: Tue, 25 Oct 2016 00:10:57 +0200
Subject: [PATCH v3 2/9] mtd: spi-nor: add an alternative method to support
 memory >16MiB
In-Reply-To: <87ace1a307f4d9899a84108de999a2eeb151da1a.1477325128.git.cyrille.pitchen@atmel.com>
References: <cover.1477325128.git.cyrille.pitchen@atmel.com>
 <87ace1a307f4d9899a84108de999a2eeb151da1a.1477325128.git.cyrille.pitchen@atmel.com>
Message-ID: <6eb07d71-cd1c-fa96-f576-c3ab6a62d246@denx.de>

On 10/24/2016 06:34 PM, Cyrille Pitchen wrote:
> This patch provides an alternative mean to support memory above 16MiB
> (128Mib) by replacing 3byte address op codes by their associated 4byte
> address versions.
> 
> Using the dedicated 4byte address op codes doesn't change the internal
> state of the SPI NOR memory as opposed to using other means such as
> updating a Base Address Register (BAR) and sending command to enter/leave
> the 4byte mode.
> 
> Hence when a CPU reset occurs, early bootloaders don't need to be aware
> of BAR value or 4byte mode being enabled: they can still access the first
> 16MiB of the SPI NOR memory using the regular 3byte address op codes.
> 
> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
> Tested-by: Vignesh R <vigneshr at ti.com>
> ---
>  drivers/mtd/devices/serial_flash_cmds.h |   7 ---
>  drivers/mtd/devices/st_spi_fsm.c        |  28 ++++-----
>  drivers/mtd/spi-nor/spi-nor.c           | 104 +++++++++++++++++++++++++-------
>  include/linux/mtd/spi-nor.h             |  22 +++++--
>  4 files changed, 113 insertions(+), 48 deletions(-)
> 
> diff --git a/drivers/mtd/devices/serial_flash_cmds.h b/drivers/mtd/devices/serial_flash_cmds.h
> index f59a125295d0..8b81e15105dd 100644
> --- a/drivers/mtd/devices/serial_flash_cmds.h
> +++ b/drivers/mtd/devices/serial_flash_cmds.h
> @@ -18,19 +18,12 @@
>  #define SPINOR_OP_RDVCR		0x85
>  
>  /* JEDEC Standard - Serial Flash Discoverable Parmeters (SFDP) Commands */
> -#define SPINOR_OP_READ_1_2_2	0xbb	/* DUAL I/O READ */
> -#define SPINOR_OP_READ_1_4_4	0xeb	/* QUAD I/O READ */
> -
>  #define SPINOR_OP_WRITE		0x02	/* PAGE PROGRAM */
>  #define SPINOR_OP_WRITE_1_1_2	0xa2	/* DUAL INPUT PROGRAM */
>  #define SPINOR_OP_WRITE_1_2_2	0xd2	/* DUAL INPUT EXT PROGRAM */
>  #define SPINOR_OP_WRITE_1_1_4	0x32	/* QUAD INPUT PROGRAM */
>  #define SPINOR_OP_WRITE_1_4_4	0x12	/* QUAD INPUT EXT PROGRAM */
>  
> -/* READ commands with 32-bit addressing */
> -#define SPINOR_OP_READ4_1_2_2	0xbc
> -#define SPINOR_OP_READ4_1_4_4	0xec
> -

It'd be nice to have this move/rename bit factored out into a separate
patch.

>  /* Configuration flags */
>  #define FLASH_FLAG_SINGLE	0x000000ff
>  #define FLASH_FLAG_READ_WRITE	0x00000001
> diff --git a/drivers/mtd/devices/st_spi_fsm.c b/drivers/mtd/devices/st_spi_fsm.c
> index 5454b4113589..804313a33f2b 100644

[...]

> +static u8 spi_nor_convert_opcode(u8 opcode,
> +				 const struct spi_nor_address_entry *entries,
> +				 size_t num_entries)
> +{
> +	int min, max;
> +
> +	min = 0;
> +	max = num_entries - 1;
> +	while (min <= max) {

It's really not clear at all what this function does, so please add a
comment.

> +		int mid = (min + max) >> 1;
> +		const struct spi_nor_address_entry *entry = &entries[mid];
> +
> +		if (opcode == entry->src_opcode)
> +			return entry->dst_opcode;
> +
> +		if (opcode < entry->src_opcode)
> +			max = mid - 1;
> +		else
> +			min = mid + 1;
> +	}
> +
> +	/* No conversion found */
> +	return opcode;
> +}
> +
> +static u8 spi_nor_3to4_opcode(u8 opcode)
> +{
> +	/* MUST be sorted by 3byte opcode */

Because ... why ?

> +#define ENTRY_3TO4(_opcode)	{ _opcode, _opcode##_4B }

Will this break/be unflexible for flashes with some different 4B opcodes ?

> +	static const struct spi_nor_address_entry spi_nor_3to4_table[] = {
> +		ENTRY_3TO4(SPINOR_OP_PP),		/* 0x02 */
> +		ENTRY_3TO4(SPINOR_OP_READ),		/* 0x03 */
> +		ENTRY_3TO4(SPINOR_OP_READ_FAST),	/* 0x0b */
> +		ENTRY_3TO4(SPINOR_OP_BE_4K),		/* 0x20 */
> +		ENTRY_3TO4(SPINOR_OP_PP_1_1_4),		/* 0x32 */
> +		ENTRY_3TO4(SPINOR_OP_PP_1_4_4),		/* 0x38 */
> +		ENTRY_3TO4(SPINOR_OP_READ_1_1_2),	/* 0x3b */
> +		ENTRY_3TO4(SPINOR_OP_BE_32K),		/* 0x52 */
> +		ENTRY_3TO4(SPINOR_OP_READ_1_1_4),	/* 0x6b */
> +		ENTRY_3TO4(SPINOR_OP_READ_1_2_2),	/* 0xbb */
> +		ENTRY_3TO4(SPINOR_OP_SE),		/* 0xd8 */
> +		ENTRY_3TO4(SPINOR_OP_READ_1_4_4),	/* 0xeb */
> +	};
> +#undef ENTRY_3TO4
> +
> +	return spi_nor_convert_opcode(opcode, spi_nor_3to4_table,
> +				      ARRAY_SIZE(spi_nor_3to4_table));
> +}
> +

[...]

-- 
Best regards,
Marek Vasut


From marex at denx.de  Mon Oct 24 15:17:57 2016
From: marex at denx.de (Marek Vasut)
Date: Tue, 25 Oct 2016 00:17:57 +0200
Subject: [PATCH v3 9/9] mtd: spi-nor: add support to SST sst26* QSPI
 memories
In-Reply-To: <74fedab98fba683d3563ac8c93d1fac6108ba278.1477325128.git.cyrille.pitchen@atmel.com>
References: <cover.1477325128.git.cyrille.pitchen@atmel.com>
 <74fedab98fba683d3563ac8c93d1fac6108ba278.1477325128.git.cyrille.pitchen@atmel.com>
Message-ID: <ca306f33-2eb7-a268-49f3-9b515a04f318@denx.de>

On 10/24/2016 06:34 PM, Cyrille Pitchen wrote:
> This patch adds support to the SST sst26* QSPI memories.
> It also adds a new SST_BLOCK_PROTECT flag so spi_nor_scan() sends
> a SST Global Block Protection Unlock (98h) command once for all
> otherwise later Sector Erase and Page Program commands would fail.
> 
> It was tested with sst26vf016b, sst26vf032b, sst26vf032ba and sst26vf064b
> on a sama5d2 xplained board at 55.3MHz and 3.3V.
> 
> sst26wf040b and sst26wf080b were not tested since they are 1.8V memories
> hence don't fit the sama5d2 xplained board requirements.
> 
> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
> ---
>  drivers/mtd/spi-nor/spi-nor.c | 20 ++++++++++++++++++++
>  include/linux/mtd/spi-nor.h   |  1 +
>  2 files changed, 21 insertions(+)
> 
> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
> index eb21d3d4e4e6..300ee38f4e9a 100644
> --- a/drivers/mtd/spi-nor/spi-nor.c
> +++ b/drivers/mtd/spi-nor/spi-nor.c
> @@ -81,6 +81,7 @@ struct flash_info {
>  					 * to support memory size above 128Mib.
>  					 */
>  #define SPI_NOR_SKIP_SFDP	BIT(11) /* Skip read of SFDP tables */
> +#define SST_BLOCK_PROTECT	BIT(12)	/* use SST Unlock Block-Protection */
>  };
>  
>  #define JEDEC_MFR(info)	((info)->id[0])
> @@ -999,6 +1000,11 @@ static const struct flash_info 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 | SST_BLOCK_PROTECT) },
> +	{ "sst26vf032b", INFO(0xbf2642, 0, 64 * 1024, 64, SECT_4K | SST_BLOCK_PROTECT) },
> +	{ "sst26vf064b", INFO(0xbf2643, 0, 64 * 1024, 128, SECT_4K | SST_BLOCK_PROTECT) },
> +	{ "sst26wf040b", INFO(0xbf2654, 0, 64 * 1024,  8, SECT_4K | SST_BLOCK_PROTECT) },
> +	{ "sst26wf080b", INFO(0xbf2658, 0, 64 * 1024, 16, SECT_4K | SST_BLOCK_PROTECT) },

You should split adding the chip and adding the sst block protection
into two separate patches.

>  	/* ST Microelectronics -- newer production may have feature updates */
>  	{ "m25p05",  INFO(0x202010,  0,  32 * 1024,   2, 0) },
> @@ -1135,6 +1141,14 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
>  	return ret;
>  }
>  
> +static int sst_unlock_block_protection(struct spi_nor *nor)
> +{
> +	int ret;
> +
> +	ret = write_enable(nor);
> +	return ret ? ret : nor->write_reg(nor, SPINOR_OP_ULBPR, NULL, 0);

I'm not a big fan of the ternary here, what about:

ret = write_enable()
if (!ret)
  ret = nor->write_reg();
return ret;

> +}
> +
>  static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
>  		size_t *retlen, const u_char *buf)
>  {
> @@ -2321,6 +2335,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
>  		return -EINVAL;
>  	}
>  
> +	if (info->flags & SST_BLOCK_PROTECT) {
> +		ret = sst_unlock_block_protection(nor);
> +		if (ret)
> +			return ret;
> +	}
> +
>  	dev_info(dev, "%s (%lld Kbytes)\n", info->name,
>  			(long long)mtd->size >> 10);
>  
> diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
> index 8fd9619dabff..c8f7e231a25c 100644
> --- a/include/linux/mtd/spi-nor.h
> +++ b/include/linux/mtd/spi-nor.h
> @@ -80,6 +80,7 @@
>  #define SPINOR_OP_BP		0x02	/* Byte program */
>  #define SPINOR_OP_WRDI		0x04	/* Write disable */
>  #define SPINOR_OP_AAI_WP	0xad	/* Auto address increment word program */
> +#define SPINOR_OP_ULBPR		0x98	/* Global Block Protection Unlock */
>  
>  /* Used for Macronix and Winbond flashes. */
>  #define SPINOR_OP_EN4B		0xb7	/* Enter 4-byte mode */
> 


-- 
Best regards,
Marek Vasut


From marex at denx.de  Mon Oct 24 15:16:59 2016
From: marex at denx.de (Marek Vasut)
Date: Tue, 25 Oct 2016 00:16:59 +0200
Subject: [PATCH v3 8/9] mtd: spi-nor: add support to Macronix mx66l1g45g
In-Reply-To: <4db277dccf52acd48e592d9f285724aab70704d1.1477325128.git.cyrille.pitchen@atmel.com>
References: <cover.1477325128.git.cyrille.pitchen@atmel.com>
 <4db277dccf52acd48e592d9f285724aab70704d1.1477325128.git.cyrille.pitchen@atmel.com>
Message-ID: <b043147d-cc39-9238-c6e7-432af67f684e@denx.de>

On 10/24/2016 06:34 PM, Cyrille Pitchen wrote:
> This patch adds an entry in the spi_nor_ids[] table to add support
> to the Macronix mx66l1g45g.
> 
> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
> ---
>  drivers/mtd/spi-nor/spi-nor.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
> index db4874d4af79..eb21d3d4e4e6 100644
> --- a/drivers/mtd/spi-nor/spi-nor.c
> +++ b/drivers/mtd/spi-nor/spi-nor.c
> @@ -937,6 +937,7 @@ static const struct flash_info spi_nor_ids[] = {
>  	{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
>  	{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
>  	{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) },
> +	{ "mx66l1g45g",  INFO(0xc2201b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
>  	{ "mx66l1g55g",  INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
>  
>  	/* Micron */
> 
This should be submitted separately as it could be applied right away.

-- 
Best regards,
Marek Vasut


From jgunthorpe at obsidianresearch.com  Mon Oct 24 15:59:54 2016
From: jgunthorpe at obsidianresearch.com (Jason Gunthorpe)
Date: Mon, 24 Oct 2016 16:59:54 -0600
Subject: [v7, 1/3] nand: pl353: Add basic driver for arm pl353 smc nand
 interface
In-Reply-To: <CAGnW=Bb-pnJ9-xjcw-1dR-y+oKjNs53bgD+dh1LwsMTCmzdRmQ@mail.gmail.com>
References: <1433786918-21500-2-git-send-email-punnaia@xilinx.com>
 <20161021203322.GA28655@obsidianresearch.com>
 <20161021234611.1f737144@bbrezillon>
 <CAGnW=Bb-pnJ9-xjcw-1dR-y+oKjNs53bgD+dh1LwsMTCmzdRmQ@mail.gmail.com>
Message-ID: <20161024225954.GA12438@obsidianresearch.com>

[cc list trimmed]

On Sun, Oct 23, 2016 at 05:37:42PM +0530, punnaiah choudary kalluri wrote:
> Hi Boris and Jason,
> 
>  I am doing rework on these patches to accommodate recent changes with
>  respect to ooblayout. Also some of the comments that i have received
> from Boris as part of the arasan nand controller upstream patches will
> apply to this driver. So, i will be releasing the next set of patches for this
> driver soon and request your time for reviewing those patches.

I have hacked the v7 patchset enough to work on 4.8 and hacked it some
more to work on my hardware. The driver appears to be in no better
shape than the 3.12 out-of-tree Xilinx release I was using previously..

I've attached the ugly, ugly patch I made, it may save you some time
when preparing v8.

Commentary:
 1) nand_chip already includes mtd_info, no reason for a second one in
    the pl353_nand_info struct. The standard accessors mtd_to_nand/etc
    should be used instead of priv
 2) I hacked out all the ECC stuff from the driver since I don't use
    it and it was broken.. Obviously some has to come back, but fixing
    other things on this list first will make that much easier and better..
 3) pl353_nand_write_page_swecc/pl353_nand_read_page_swecc are pure
    outdated copies of the core routines and should not exist in a
    driver. This needs to be fixed so nand_scan_tail sets them.
    This seems to be a side effect of #9 ?
 4) The hacky stuff to detect 2 vs 3 address cycle NAND doesn't work,
    and doesn't work without ONFI (see patch for possible fix). The
    driver should probably use the same scheme the core code uses..
    But this is all a problem because of #10
 5) The driver assumes alignment of the iomap, needs to use + not |
    when constructing the address. (yes, this blows up on my system)
 6) Driver unconditionally sets timing to ONFI mode 0 (slow!)
    Maybe timing should be common code driven by DT..
 7) Driver unconditionally selects a BBT format, and an ECC layout
    (neither match what my system uses, but I guess that is a core mtd
    issue these days :/)
 8) Driver unconditionally forces a chip-delay (wrong for my
    system) maybe this should be common code driven by DT..
 9) This buisness with pl353_nand_ecc_init and the
    special functions to do PL353_NAND_LAST_TRANSFER_LENGTH stuff
    is just horrid. I'd expect that is a big NAK.

    The driver needs to implement read_buf *properly* so the core
    routines can be used instead of trying to 'fix' the call sites
    to do the PL353_NAND_LAST_TRANSFER_LENGTH stuff.
 10) pl353_nand_cmd_function is a wonky copy of nand_command_lp, maybe
     this driver should use cmd_ctrl, or the core code should be
     refactored some more..

Jason

diff --git a/drivers/mtd/nand/pl353_nand.c b/drivers/mtd/nand/pl353_nand.c
index 7e3993931f75..63a8d8c008e3 100644
--- a/drivers/mtd/nand/pl353_nand.c
+++ b/drivers/mtd/nand/pl353_nand.c
@@ -26,7 +26,6 @@
 #include <linux/mtd/partitions.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
-#include <linux/of_mtd.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
@@ -56,7 +55,6 @@
 #define PL353_NAND_ECC_LAST	BIT(ECC_LAST_SHIFT)	/* Set ECC_Last */
 #define PL353_NAND_CLEAR_CS	BIT(CLEAR_CS_SHIFT)	/* Clear chip select */
 
-#define ONDIE_ECC_FEATURE_ADDR	0x90
 #define PL353_NAND_ECC_BUSY_TIMEOUT	(1 * HZ)
 #define PL353_NAND_DEV_BUSY_TIMEOUT	(1 * HZ)
 #define PL353_NAND_LAST_TRANSFER_LENGTH	4
@@ -88,11 +86,9 @@ struct pl353_nand_command_format {
  */
 struct pl353_nand_info {
 	struct nand_chip chip;
-	struct mtd_info mtd;
 	void __iomem *nand_base;
 	unsigned long end_cmd_pending;
 	unsigned long end_cmd;
-	int ecc_mode;
 	u8 raddr_cycles;
 	u8 caddr_cycles;
 };
@@ -101,13 +97,13 @@ struct pl353_nand_info {
  * The NAND flash operations command format
  */
 static const struct pl353_nand_command_format pl353_nand_commands[] = {
-	{NAND_CMD_READ0, NAND_CMD_READSTART, 5, PL353_NAND_CMD_PHASE},
+	{NAND_CMD_READ0, NAND_CMD_READSTART, -1, PL353_NAND_CMD_PHASE},
 	{NAND_CMD_RNDOUT, NAND_CMD_RNDOUTSTART, 2, PL353_NAND_CMD_PHASE},
 	{NAND_CMD_READID, NAND_CMD_NONE, 1, NAND_CMD_NONE},
 	{NAND_CMD_STATUS, NAND_CMD_NONE, 0, NAND_CMD_NONE},
-	{NAND_CMD_SEQIN, NAND_CMD_PAGEPROG, 5, PL353_NAND_DATA_PHASE},
+	{NAND_CMD_SEQIN, NAND_CMD_PAGEPROG, -1, PL353_NAND_DATA_PHASE},
 	{NAND_CMD_RNDIN, NAND_CMD_NONE, 2, NAND_CMD_NONE},
-	{NAND_CMD_ERASE1, NAND_CMD_ERASE2, 3, PL353_NAND_CMD_PHASE},
+	{NAND_CMD_ERASE1, NAND_CMD_ERASE2, -1, PL353_NAND_CMD_PHASE},
 	{NAND_CMD_RESET, NAND_CMD_NONE, 0, NAND_CMD_NONE},
 	{NAND_CMD_PARAM, NAND_CMD_NONE, 1, NAND_CMD_NONE},
 	{NAND_CMD_GET_FEATURES, NAND_CMD_NONE, 1, NAND_CMD_NONE},
@@ -126,22 +122,58 @@ static const struct pl353_nand_command_format pl353_nand_commands[] = {
 };
 
 /* Define default oob placement schemes for large and small page devices */
-static struct nand_ecclayout nand_oob_16 = {
-	.eccbytes = 3,
-	.eccpos = {0, 1, 2},
-	.oobfree = {
-		{.offset = 8,
-		 . length = 8} }
+static int pl353_ooblayout_16_ecc(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *oobregion)
+{
+	if (section != 0)
+		return -ERANGE;
+
+	oobregion->offset = 0;
+	oobregion->length = 3;
+	return 0;
+}
+
+static int pl353_ooblayout_16_free(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *oobregion)
+{
+	if (section != 0)
+		return -ERANGE;
+
+	oobregion->offset = 8;
+	oobregion->length = 8;
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops pl353_16_ooblayout_ops = {
+	.ecc = pl353_ooblayout_16_ecc,
+	.free = pl353_ooblayout_16_free,
 };
 
-static struct nand_ecclayout nand_oob_64 = {
-	.eccbytes = 12,
-	.eccpos = {
-		   52, 53, 54, 55, 56, 57,
-		   58, 59, 60, 61, 62, 63},
-	.oobfree = {
-		{.offset = 2,
-		 .length = 50} }
+static int pl353_ooblayout_64_ecc(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *oobregion)
+{
+	if (section != 0)
+		return -ERANGE;
+
+	oobregion->offset = 52;
+	oobregion->length = 12;
+	return 0;
+}
+
+static int pl353_ooblayout_64_free(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *oobregion)
+{
+	if (section != 0)
+		return -ERANGE;
+
+	oobregion->offset = 2;
+	oobregion->length = 50;
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops pl353_64_ooblayout_ops = {
+	.ecc = pl353_ooblayout_64_ecc,
+	.free = pl353_ooblayout_64_free,
 };
 
 static unsigned int get_cyc_from_ns(u32 clkrate, u32 ns)
@@ -163,6 +195,7 @@ static unsigned int get_cyc_from_ns(u32 clkrate, u32 ns)
  *
  * Return:	0 on success or error value on failure
  */
+#if 0
 static int pl353_nand_calculate_hwecc(struct mtd_info *mtd,
 				const u8 *data, u8 *ecc_code)
 {
@@ -202,6 +235,7 @@ static int pl353_nand_calculate_hwecc(struct mtd_info *mtd,
 	}
 	return 0;
 }
+#endif
 
 /**
  * onehot - onehot function
@@ -212,10 +246,12 @@ static int pl353_nand_calculate_hwecc(struct mtd_info *mtd,
  *
  * Return:	1 if it is onehot else 0
  */
+#if 0
 static int onehot(unsigned short value)
 {
 	return (value & (value - 1)) == 0;
 }
+#endif
 
 /**
  * pl353_nand_correct_data - ECC correction function
@@ -230,6 +266,7 @@ static int onehot(unsigned short value)
  *		1 if single bit error found and corrected.
  *		-1 if multiple ECC errors found.
  */
+#if 0
 static int pl353_nand_correct_data(struct mtd_info *mtd, unsigned char *buf,
 				unsigned char *read_ecc,
 				unsigned char *calc_ecc)
@@ -266,6 +303,7 @@ static int pl353_nand_correct_data(struct mtd_info *mtd, unsigned char *buf,
 
 	return -EBADMSG; /* Uncorrectable error */
 }
+#endif
 
 /**
  * pl353_nand_read_oob - [REPLACEABLE] the most common OOB data read function
@@ -372,8 +410,8 @@ static int pl353_nand_read_page_raw(struct mtd_info *mtd,
  * Return:	Always return zero
  */
 static int pl353_nand_write_page_raw(struct mtd_info *mtd,
-				    struct nand_chip *chip,
-				    const uint8_t *buf, int oob_required)
+				     struct nand_chip *chip, const uint8_t *buf,
+				     int oob_required, int page)
 {
 	unsigned long data_phase_addr;
 	uint8_t *p;
@@ -406,6 +444,7 @@ static int pl353_nand_write_page_raw(struct mtd_info *mtd,
  *
  * Return:	Zero on success and error on failure.
  */
+#if 0
 static int pl353_nand_write_page_hwecc(struct mtd_info *mtd,
 				    struct nand_chip *chip, const uint8_t *buf,
 				    int oob_required)
@@ -459,39 +498,7 @@ static int pl353_nand_write_page_hwecc(struct mtd_info *mtd,
 
 	return 0;
 }
-
-/**
- * pl353_nand_write_page_swecc - [REPLACEABLE] software ecc based page write
- * function
- * @mtd:		Pointer to the mtd info structure
- * @chip:		Pointer to the NAND chip info structure
- * @buf:		Pointer to the data buffer
- * @oob_required:	Caller requires OOB data read to chip->oob_poi
- *
- * Return:	Always return zero
- */
-static int pl353_nand_write_page_swecc(struct mtd_info *mtd,
-				    struct nand_chip *chip, const uint8_t *buf,
-				    int oob_required)
-{
-	int i, eccsize = chip->ecc.size;
-	int eccbytes = chip->ecc.bytes;
-	int eccsteps = chip->ecc.steps;
-	uint8_t *ecc_calc = chip->buffers->ecccalc;
-	const uint8_t *p = buf;
-	uint32_t *eccpos = chip->ecc.layout->eccpos;
-
-	/* Software ecc calculation */
-	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
-		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
-
-	for (i = 0; i < chip->ecc.total; i++)
-		chip->oob_poi[eccpos[i]] = ecc_calc[i];
-
-	chip->ecc.write_page_raw(mtd, chip, buf, 1);
-
-	return 0;
-}
+#endif
 
 /**
  * pl353_nand_read_page_hwecc - Hardware ECC based page read function
@@ -506,6 +513,7 @@ static int pl353_nand_write_page_swecc(struct mtd_info *mtd,
  *
  * Return:	0 always and updates ECC operation status in to MTD structure
  */
+#if 0
 static int pl353_nand_read_page_hwecc(struct mtd_info *mtd,
 				     struct nand_chip *chip,
 				     uint8_t *buf, int oob_required, int page)
@@ -573,52 +581,7 @@ static int pl353_nand_read_page_hwecc(struct mtd_info *mtd,
 	}
 	return 0;
 }
-
-/**
- * pl353_nand_read_page_swecc - [REPLACEABLE] software ecc based page read
- * function
- * @mtd:		Pointer to the mtd info structure
- * @chip:		Pointer to the NAND chip info structure
- * @buf:		Pointer to the buffer to store read data
- * @oob_required:	Caller requires OOB data read to chip->oob_poi
- * @page:		Page number to read
- *
- * Return:	Always return zero
- */
-static int pl353_nand_read_page_swecc(struct mtd_info *mtd,
-				     struct nand_chip *chip,
-				     uint8_t *buf,  int oob_required, int page)
-{
-	int i, eccsize = chip->ecc.size;
-	int eccbytes = chip->ecc.bytes;
-	int eccsteps = chip->ecc.steps;
-	uint8_t *p = buf;
-	uint8_t *ecc_calc = chip->buffers->ecccalc;
-	uint8_t *ecc_code = chip->buffers->ecccode;
-	uint32_t *eccpos = chip->ecc.layout->eccpos;
-
-	chip->ecc.read_page_raw(mtd, chip, buf, page, 1);
-
-	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
-		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
-
-	for (i = 0; i < chip->ecc.total; i++)
-		ecc_code[i] = chip->oob_poi[eccpos[i]];
-
-	eccsteps = chip->ecc.steps;
-	p = buf;
-
-	for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
-		int stat;
-
-		stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
-		if (stat < 0)
-			mtd->ecc_stats.failed++;
-		else
-			mtd->ecc_stats.corrected += stat;
-	}
-	return 0;
-}
+#endif
 
 /**
  * pl353_nand_select_chip - Select the flash device
@@ -643,10 +606,10 @@ static void pl353_nand_select_chip(struct mtd_info *mtd, int chip)
 static void pl353_nand_cmd_function(struct mtd_info *mtd, unsigned int command,
 				 int column, int page_addr)
 {
-	struct nand_chip *chip = mtd->priv;
-	const struct pl353_nand_command_format *curr_cmd = NULL;
+	struct nand_chip *chip = mtd_to_nand(mtd);
 	struct pl353_nand_info *xnand =
-		container_of(mtd, struct pl353_nand_info, mtd);
+	    container_of(chip, struct pl353_nand_info, chip);
+	const struct pl353_nand_command_format *curr_cmd = NULL;
 	void __iomem *cmd_addr;
 	unsigned long cmd_data = 0, end_cmd_valid = 0;
 	unsigned long cmd_phase_addr, data_phase_addr, end_cmd, i;
@@ -693,33 +656,27 @@ static void pl353_nand_cmd_function(struct mtd_info *mtd, unsigned int command,
 	else
 		end_cmd = curr_cmd->end_cmd;
 
-	if ((command == NAND_CMD_READ0) && (command == NAND_CMD_SEQIN))
+	if ((command == NAND_CMD_READ0) || (command == NAND_CMD_SEQIN))
 		addrcycles = xnand->raddr_cycles + xnand->caddr_cycles;
 	else if (command == NAND_CMD_ERASE1)
 		addrcycles = xnand->raddr_cycles;
 	else
 		addrcycles = curr_cmd->addr_cycles;
 
-	cmd_phase_addr = (unsigned long __force)xnand->nand_base        |
-			 (addrcycles << ADDR_CYCLES_SHIFT)    |
-			 (end_cmd_valid << END_CMD_VALID_SHIFT)          |
-			 (COMMAND_PHASE)                                 |
-			 (end_cmd << END_CMD_SHIFT)                      |
-			 (curr_cmd->start_cmd << START_CMD_SHIFT);
-
-	cmd_addr = (void __iomem * __force)cmd_phase_addr;
+	cmd_addr =
+	    xnand->nand_base + ((addrcycles << ADDR_CYCLES_SHIFT) |
+				(end_cmd_valid << END_CMD_VALID_SHIFT) |
+				(COMMAND_PHASE) | (end_cmd << END_CMD_SHIFT) |
+				(curr_cmd->start_cmd << START_CMD_SHIFT));
 
 	/* Get the data phase address */
 	end_cmd_valid = 0;
 
-	data_phase_addr = (unsigned long __force)xnand->nand_base       |
-			  (0x0 << CLEAR_CS_SHIFT)                         |
-			  (end_cmd_valid << END_CMD_VALID_SHIFT)          |
-			  (DATA_PHASE)                                    |
-			  (end_cmd << END_CMD_SHIFT)                      |
-			  (0x0 << ECC_LAST_SHIFT);
-
-	chip->IO_ADDR_R = (void __iomem * __force)data_phase_addr;
+	chip->IO_ADDR_R =
+	    xnand->nand_base + ((0x0 << CLEAR_CS_SHIFT) |
+				(end_cmd_valid << END_CMD_VALID_SHIFT) |
+				(DATA_PHASE) | (end_cmd << END_CMD_SHIFT) |
+				(0x0 << ECC_LAST_SHIFT));
 	chip->IO_ADDR_W = chip->IO_ADDR_R;
 
 	/* Command phase AXI write */
@@ -779,6 +736,7 @@ static void pl353_nand_cmd_function(struct mtd_info *mtd, unsigned int command,
 
 		if (time_after_eq(jiffies, timeout))
 			pr_err("%s timed out\n", __func__);
+
 		return;
 	}
 }
@@ -791,8 +749,8 @@ static void pl353_nand_cmd_function(struct mtd_info *mtd, unsigned int command,
  */
 static void pl353_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 {
+	struct nand_chip *chip = mtd_to_nand(mtd);
 	int i;
-	struct nand_chip *chip = mtd->priv;
 	unsigned long *ptr = (unsigned long *)buf;
 
 	len >>= 2;
@@ -809,8 +767,8 @@ static void pl353_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 static void pl353_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf,
 				int len)
 {
+	struct nand_chip *chip = mtd_to_nand(mtd);
 	int i;
-	struct nand_chip *chip = mtd->priv;
 	unsigned long *ptr = (unsigned long *)buf;
 
 	len >>= 2;
@@ -843,11 +801,12 @@ static int pl353_nand_device_ready(struct mtd_info *mtd)
  *
  * Return:	Zero on success and error on failure.
  */
+#if 0
 static int pl353_nand_ecc_init(struct mtd_info *mtd)
 {
-	struct nand_chip *nand_chip = mtd->priv;
+	struct nand_chip *chip = mtd_to_nand(mtd);
 	struct pl353_nand_info *xnand =
-		container_of(mtd, struct pl353_nand_info, mtd);
+	    container_of(chip, struct pl353_nand_info, chip);
 
 	nand_chip->ecc.read_oob = pl353_nand_read_oob;
 	nand_chip->ecc.write_oob = pl353_nand_write_oob;
@@ -868,7 +827,7 @@ static int pl353_nand_ecc_init(struct mtd_info *mtd)
 		nand_chip->ecc.hwctl = NULL;
 		nand_chip->ecc.read_page = pl353_nand_read_page_hwecc;
 		nand_chip->ecc.size = PL353_NAND_ECC_SIZE;
-		nand_chip->ecc.write_page = pl353_nand_write_page_hwecc;
+//		nand_chip->ecc.write_page = pl353_nand_write_page_hwecc;
 		pl353_smc_set_ecc_pg_size(mtd->dev.parent, mtd->writesize);
 		pl353_smc_set_ecc_mode(mtd->dev.parent, PL353_SMC_ECCMODE_APB);
 		/* Hardware ECC generates 3 bytes ECC code for each 512 bytes */
@@ -904,6 +863,7 @@ static int pl353_nand_ecc_init(struct mtd_info *mtd)
 
 	return 0;
 }
+#endif
 
 static int pl353_nand_init_timing(struct device *dev, int mode)
 {
@@ -924,7 +884,7 @@ static int pl353_nand_init_timing(struct device *dev, int mode)
 	t_ar  = get_cyc_from_ns(clkrate, time->tAR_min / 1000);
 	t_rr  = get_cyc_from_ns(clkrate, time->tRR_min / 1000);
 
-	pl353_smc_set_cycles(dev, t_rc, t_wc, t_rea, t_wp, t_clr, t_ar, t_rr);
+//	pl353_smc_set_cycles(dev, t_rc, t_wc, t_rea, t_wp, t_clr, t_ar, t_rr);
 
 	return 0;
 }
@@ -943,28 +903,24 @@ static int pl353_nand_probe(struct platform_device *pdev)
 	struct mtd_info *mtd;
 	struct nand_chip *nand_chip;
 	struct resource *res;
-	struct mtd_part_parser_data ppdata;
 
 	xnand = devm_kzalloc(&pdev->dev, sizeof(*xnand), GFP_KERNEL);
 	if (!xnand)
 		return -ENOMEM;
 
+	/* Setup the basic MTD stuff */
+	mtd = nand_to_mtd(&xnand->chip);
+	nand_chip = &xnand->chip;
+	mtd->dev.parent = pdev->dev.parent;
+	mtd->name = PL353_NAND_DRIVER_NAME;
+	nand_set_flash_node(nand_chip, pdev->dev.of_node);
+
 	/* Map physical address of NAND flash */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	xnand->nand_base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(xnand->nand_base))
 		return PTR_ERR(xnand->nand_base);
 
-	/* Link the private data with the MTD structure */
-	mtd = &xnand->mtd;
-	nand_chip = &xnand->chip;
-
-	nand_chip->priv = xnand;
-	mtd->priv = nand_chip;
-	mtd->dev.parent = pdev->dev.parent;
-	mtd->owner = THIS_MODULE;
-	mtd->name = PL353_NAND_DRIVER_NAME;
-
 	/* Set address of NAND IO lines */
 	nand_chip->IO_ADDR_R = xnand->nand_base;
 	nand_chip->IO_ADDR_W = xnand->nand_base;
@@ -973,42 +929,46 @@ static int pl353_nand_probe(struct platform_device *pdev)
 	nand_chip->cmdfunc = pl353_nand_cmd_function;
 	nand_chip->dev_ready = pl353_nand_device_ready;
 	nand_chip->select_chip = pl353_nand_select_chip;
-
-	/* If we don't set this delay driver sets 20us by default */
-	nand_chip->chip_delay = 30;
-
-	/* Buffer read/write routines */
 	nand_chip->read_buf = pl353_nand_read_buf;
 	nand_chip->write_buf = pl353_nand_write_buf;
-
-	/* Set the device option and flash width */
 	nand_chip->options = NAND_BUSWIDTH_AUTO;
-	nand_chip->bbt_options = NAND_BBT_USE_FLASH;
+//	nand_chip->bbt_options = NAND_BBT_USE_FLASH;
+
+	/* If we don't set this delay driver sets 20us by default */
+	nand_chip->chip_delay = 30;
+	// FIXME: from dt
+	nand_chip->chip_delay = 50;
 
 	platform_set_drvdata(pdev, xnand);
 	if (pl353_nand_init_timing(pdev->dev.parent, 0))
 		return -ENOTSUPP;
+
 	/* First scan to find the device and get the page size */
 	if (nand_scan_ident(mtd, 1, NULL)) {
 		dev_err(&pdev->dev, "nand_scan_ident for NAND failed\n");
 		return -ENXIO;
 	}
 
-	xnand->ecc_mode = of_get_nand_ecc_mode(pdev->dev.of_node);
-	if (xnand->ecc_mode < 0)
-		xnand->ecc_mode = NAND_ECC_HW;
-
 	if (nand_chip->onfi_version) {
 		xnand->raddr_cycles = nand_chip->onfi_params.addr_cycles & 0xF;
 		xnand->caddr_cycles =
 				(nand_chip->onfi_params.addr_cycles >> 4) & 0xF;
 	} else {
-		/*For non-ONFI devices, configuring the address cyles as 5 */
-		xnand->raddr_cycles = xnand->caddr_cycles = 5;
+		/* For non-ONFI devices, configure the address cyles based on
+		 * the device size */
+		xnand->caddr_cycles = 2;
+		if (nand_chip->chipsize > (128 << 20))
+			xnand->raddr_cycles = 3;
+		else
+			xnand->raddr_cycles = 2;
 	}
 
-	if (pl353_nand_ecc_init(mtd))
-		return -ENOTSUPP;
+	nand_chip->ecc.read_oob = pl353_nand_read_oob;
+	nand_chip->ecc.write_oob = pl353_nand_write_oob;
+	nand_chip->ecc.read_page_raw = pl353_nand_read_page_raw;
+	nand_chip->ecc.write_page_raw = pl353_nand_write_page_raw;
+/*	if (pl353_nand_ecc_init(mtd))
+	return -ENOTSUPP;*/
 
 	if (nand_chip->options & NAND_BUSWIDTH_16)
 		pl353_smc_set_buswidth(pdev->dev.parent,
@@ -1021,9 +981,7 @@ static int pl353_nand_probe(struct platform_device *pdev)
 		return -ENXIO;
 	}
 
-	ppdata.of_node = pdev->dev.of_node;
-
-	mtd_device_parse_register(&xnand->mtd, NULL, &ppdata, NULL, 0);
+	mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
 
 	return 0;
 }
@@ -1042,7 +1000,7 @@ static int pl353_nand_remove(struct platform_device *pdev)
 	struct pl353_nand_info *xnand = platform_get_drvdata(pdev);
 
 	/* Release resources, unregister device */
-	nand_release(&xnand->mtd);
+	nand_release(nand_to_mtd(&xnand->chip));
 
 	return 0;
 }


From punnaiah.choudary.kalluri at xilinx.com  Mon Oct 24 20:58:49 2016
From: punnaiah.choudary.kalluri at xilinx.com (Punnaiah Choudary Kalluri)
Date: Tue, 25 Oct 2016 03:58:49 +0000
Subject: [v7, 1/3] nand: pl353: Add basic driver for arm pl353 smc nand
 interface
In-Reply-To: <20161024225954.GA12438@obsidianresearch.com>
References: <1433786918-21500-2-git-send-email-punnaia@xilinx.com>
 <20161021203322.GA28655@obsidianresearch.com>
 <20161021234611.1f737144@bbrezillon>
 <CAGnW=Bb-pnJ9-xjcw-1dR-y+oKjNs53bgD+dh1LwsMTCmzdRmQ@mail.gmail.com>
 <20161024225954.GA12438@obsidianresearch.com>
Message-ID: <03CA77BA8AF6F1469AEDFBDA1322A7B764216D8A@XAP-PVEXMBX02.xlnx.xilinx.com>



> -----Original Message-----
> From: Jason Gunthorpe [mailto:jgunthorpe at obsidianresearch.com]
> Sent: Tuesday, October 25, 2016 4:30 AM
> To: Punnaiah Choudary Kalluri <punnaia at xilinx.com>
> Cc: Boris Brezillon <boris.brezillon at free-electrons.com>; Punnaiah Choudary
> Kalluri <punnaia at xilinx.com>; mark.rutland at arm.com; linux-
> mtd at lists.infradead.org; michal.simek at xilinx.com; ezequiel.garcia at free-
> electrons.com; linux-kernel at vger.kernel.org; rob at landley.net;
> galak at codeaurora.org; Khoronzhuk, Ivan <ivan.khoronzhuk at ti.com>;
> computersforpeace at gmail.com; dwmw2 at infradead.org
> Subject: Re: [v7, 1/3] nand: pl353: Add basic driver for arm pl353 smc nand
> interface
> 
> [cc list trimmed]
> 
> On Sun, Oct 23, 2016 at 05:37:42PM +0530, punnaiah choudary kalluri wrote:
> > Hi Boris and Jason,
> >
> >  I am doing rework on these patches to accommodate recent changes with
> >  respect to ooblayout. Also some of the comments that i have received
> > from Boris as part of the arasan nand controller upstream patches will
> > apply to this driver. So, i will be releasing the next set of patches for this
> > driver soon and request your time for reviewing those patches.
> 
> I have hacked the v7 patchset enough to work on 4.8 and hacked it some
> more to work on my hardware. The driver appears to be in no better
> shape than the 3.12 out-of-tree Xilinx release I was using previously..


The driver in Xilinx tree works with 4.6 kernel and adopted the required
 Changes (may release in 1-2 weeks). Still it need some rework, now a days
I am seeing many requests from different people for this driver and some of
Them are using different version of IP as you know this IP has four variants and
Xilinx is using the pl353 variant.  Let's wait for the next series of patches and 
Get the patches tested with others as well along with the review comments.
 
Regards,
Punnaiah
> I've attached the ugly, ugly patch I made, it may save you some time
> when preparing v8.
> 
> Commentary:
>  1) nand_chip already includes mtd_info, no reason for a second one in
>     the pl353_nand_info struct. The standard accessors mtd_to_nand/etc
>     should be used instead of priv
>  2) I hacked out all the ECC stuff from the driver since I don't use
>     it and it was broken.. Obviously some has to come back, but fixing
>     other things on this list first will make that much easier and better..
>  3) pl353_nand_write_page_swecc/pl353_nand_read_page_swecc are pure
>     outdated copies of the core routines and should not exist in a
>     driver. This needs to be fixed so nand_scan_tail sets them.
>     This seems to be a side effect of #9 ?
>  4) The hacky stuff to detect 2 vs 3 address cycle NAND doesn't work,
>     and doesn't work without ONFI (see patch for possible fix). The
>     driver should probably use the same scheme the core code uses..
>     But this is all a problem because of #10
>  5) The driver assumes alignment of the iomap, needs to use + not |
>     when constructing the address. (yes, this blows up on my system)
>  6) Driver unconditionally sets timing to ONFI mode 0 (slow!)
>     Maybe timing should be common code driven by DT..
>  7) Driver unconditionally selects a BBT format, and an ECC layout
>     (neither match what my system uses, but I guess that is a core mtd
>     issue these days :/)
>  8) Driver unconditionally forces a chip-delay (wrong for my
>     system) maybe this should be common code driven by DT..
>  9) This buisness with pl353_nand_ecc_init and the
>     special functions to do PL353_NAND_LAST_TRANSFER_LENGTH stuff
>     is just horrid. I'd expect that is a big NAK.
> 
>     The driver needs to implement read_buf *properly* so the core
>     routines can be used instead of trying to 'fix' the call sites
>     to do the PL353_NAND_LAST_TRANSFER_LENGTH stuff.
>  10) pl353_nand_cmd_function is a wonky copy of nand_command_lp,
> maybe
>      this driver should use cmd_ctrl, or the core code should be
>      refactored some more..
> 
> Jason
> 
> diff --git a/drivers/mtd/nand/pl353_nand.c
> b/drivers/mtd/nand/pl353_nand.c
> index 7e3993931f75..63a8d8c008e3 100644
> --- a/drivers/mtd/nand/pl353_nand.c
> +++ b/drivers/mtd/nand/pl353_nand.c
> @@ -26,7 +26,6 @@
>  #include <linux/mtd/partitions.h>
>  #include <linux/of_address.h>
>  #include <linux/of_device.h>
> -#include <linux/of_mtd.h>
>  #include <linux/of_platform.h>
>  #include <linux/platform_device.h>
>  #include <linux/slab.h>
> @@ -56,7 +55,6 @@
>  #define PL353_NAND_ECC_LAST	BIT(ECC_LAST_SHIFT)	/* Set
> ECC_Last */
>  #define PL353_NAND_CLEAR_CS	BIT(CLEAR_CS_SHIFT)	/* Clear chip
> select */
> 
> -#define ONDIE_ECC_FEATURE_ADDR	0x90
>  #define PL353_NAND_ECC_BUSY_TIMEOUT	(1 * HZ)
>  #define PL353_NAND_DEV_BUSY_TIMEOUT	(1 * HZ)
>  #define PL353_NAND_LAST_TRANSFER_LENGTH	4
> @@ -88,11 +86,9 @@ struct pl353_nand_command_format {
>   */
>  struct pl353_nand_info {
>  	struct nand_chip chip;
> -	struct mtd_info mtd;
>  	void __iomem *nand_base;
>  	unsigned long end_cmd_pending;
>  	unsigned long end_cmd;
> -	int ecc_mode;
>  	u8 raddr_cycles;
>  	u8 caddr_cycles;
>  };
> @@ -101,13 +97,13 @@ struct pl353_nand_info {
>   * The NAND flash operations command format
>   */
>  static const struct pl353_nand_command_format pl353_nand_commands[]
> = {
> -	{NAND_CMD_READ0, NAND_CMD_READSTART, 5,
> PL353_NAND_CMD_PHASE},
> +	{NAND_CMD_READ0, NAND_CMD_READSTART, -1,
> PL353_NAND_CMD_PHASE},
>  	{NAND_CMD_RNDOUT, NAND_CMD_RNDOUTSTART, 2,
> PL353_NAND_CMD_PHASE},
>  	{NAND_CMD_READID, NAND_CMD_NONE, 1, NAND_CMD_NONE},
>  	{NAND_CMD_STATUS, NAND_CMD_NONE, 0, NAND_CMD_NONE},
> -	{NAND_CMD_SEQIN, NAND_CMD_PAGEPROG, 5,
> PL353_NAND_DATA_PHASE},
> +	{NAND_CMD_SEQIN, NAND_CMD_PAGEPROG, -1,
> PL353_NAND_DATA_PHASE},
>  	{NAND_CMD_RNDIN, NAND_CMD_NONE, 2, NAND_CMD_NONE},
> -	{NAND_CMD_ERASE1, NAND_CMD_ERASE2, 3,
> PL353_NAND_CMD_PHASE},
> +	{NAND_CMD_ERASE1, NAND_CMD_ERASE2, -1,
> PL353_NAND_CMD_PHASE},
>  	{NAND_CMD_RESET, NAND_CMD_NONE, 0, NAND_CMD_NONE},
>  	{NAND_CMD_PARAM, NAND_CMD_NONE, 1, NAND_CMD_NONE},
>  	{NAND_CMD_GET_FEATURES, NAND_CMD_NONE, 1,
> NAND_CMD_NONE},
> @@ -126,22 +122,58 @@ static const struct pl353_nand_command_format
> pl353_nand_commands[] = {
>  };
> 
>  /* Define default oob placement schemes for large and small page devices
> */
> -static struct nand_ecclayout nand_oob_16 = {
> -	.eccbytes = 3,
> -	.eccpos = {0, 1, 2},
> -	.oobfree = {
> -		{.offset = 8,
> -		 . length = 8} }
> +static int pl353_ooblayout_16_ecc(struct mtd_info *mtd, int section,
> +				  struct mtd_oob_region *oobregion)
> +{
> +	if (section != 0)
> +		return -ERANGE;
> +
> +	oobregion->offset = 0;
> +	oobregion->length = 3;
> +	return 0;
> +}
> +
> +static int pl353_ooblayout_16_free(struct mtd_info *mtd, int section,
> +				  struct mtd_oob_region *oobregion)
> +{
> +	if (section != 0)
> +		return -ERANGE;
> +
> +	oobregion->offset = 8;
> +	oobregion->length = 8;
> +	return 0;
> +}
> +
> +static const struct mtd_ooblayout_ops pl353_16_ooblayout_ops = {
> +	.ecc = pl353_ooblayout_16_ecc,
> +	.free = pl353_ooblayout_16_free,
>  };
> 
> -static struct nand_ecclayout nand_oob_64 = {
> -	.eccbytes = 12,
> -	.eccpos = {
> -		   52, 53, 54, 55, 56, 57,
> -		   58, 59, 60, 61, 62, 63},
> -	.oobfree = {
> -		{.offset = 2,
> -		 .length = 50} }
> +static int pl353_ooblayout_64_ecc(struct mtd_info *mtd, int section,
> +				  struct mtd_oob_region *oobregion)
> +{
> +	if (section != 0)
> +		return -ERANGE;
> +
> +	oobregion->offset = 52;
> +	oobregion->length = 12;
> +	return 0;
> +}
> +
> +static int pl353_ooblayout_64_free(struct mtd_info *mtd, int section,
> +				  struct mtd_oob_region *oobregion)
> +{
> +	if (section != 0)
> +		return -ERANGE;
> +
> +	oobregion->offset = 2;
> +	oobregion->length = 50;
> +	return 0;
> +}
> +
> +static const struct mtd_ooblayout_ops pl353_64_ooblayout_ops = {
> +	.ecc = pl353_ooblayout_64_ecc,
> +	.free = pl353_ooblayout_64_free,
>  };
> 
>  static unsigned int get_cyc_from_ns(u32 clkrate, u32 ns)
> @@ -163,6 +195,7 @@ static unsigned int get_cyc_from_ns(u32 clkrate, u32
> ns)
>   *
>   * Return:	0 on success or error value on failure
>   */
> +#if 0
>  static int pl353_nand_calculate_hwecc(struct mtd_info *mtd,
>  				const u8 *data, u8 *ecc_code)
>  {
> @@ -202,6 +235,7 @@ static int pl353_nand_calculate_hwecc(struct
> mtd_info *mtd,
>  	}
>  	return 0;
>  }
> +#endif
> 
>  /**
>   * onehot - onehot function
> @@ -212,10 +246,12 @@ static int pl353_nand_calculate_hwecc(struct
> mtd_info *mtd,
>   *
>   * Return:	1 if it is onehot else 0
>   */
> +#if 0
>  static int onehot(unsigned short value)
>  {
>  	return (value & (value - 1)) == 0;
>  }
> +#endif
> 
>  /**
>   * pl353_nand_correct_data - ECC correction function
> @@ -230,6 +266,7 @@ static int onehot(unsigned short value)
>   *		1 if single bit error found and corrected.
>   *		-1 if multiple ECC errors found.
>   */
> +#if 0
>  static int pl353_nand_correct_data(struct mtd_info *mtd, unsigned char
> *buf,
>  				unsigned char *read_ecc,
>  				unsigned char *calc_ecc)
> @@ -266,6 +303,7 @@ static int pl353_nand_correct_data(struct mtd_info
> *mtd, unsigned char *buf,
> 
>  	return -EBADMSG; /* Uncorrectable error */
>  }
> +#endif
> 
>  /**
>   * pl353_nand_read_oob - [REPLACEABLE] the most common OOB data read
> function
> @@ -372,8 +410,8 @@ static int pl353_nand_read_page_raw(struct
> mtd_info *mtd,
>   * Return:	Always return zero
>   */
>  static int pl353_nand_write_page_raw(struct mtd_info *mtd,
> -				    struct nand_chip *chip,
> -				    const uint8_t *buf, int oob_required)
> +				     struct nand_chip *chip, const uint8_t *buf,
> +				     int oob_required, int page)
>  {
>  	unsigned long data_phase_addr;
>  	uint8_t *p;
> @@ -406,6 +444,7 @@ static int pl353_nand_write_page_raw(struct
> mtd_info *mtd,
>   *
>   * Return:	Zero on success and error on failure.
>   */
> +#if 0
>  static int pl353_nand_write_page_hwecc(struct mtd_info *mtd,
>  				    struct nand_chip *chip, const uint8_t *buf,
>  				    int oob_required)
> @@ -459,39 +498,7 @@ static int pl353_nand_write_page_hwecc(struct
> mtd_info *mtd,
> 
>  	return 0;
>  }
> -
> -/**
> - * pl353_nand_write_page_swecc - [REPLACEABLE] software ecc based
> page write
> - * function
> - * @mtd:		Pointer to the mtd info structure
> - * @chip:		Pointer to the NAND chip info structure
> - * @buf:		Pointer to the data buffer
> - * @oob_required:	Caller requires OOB data read to chip->oob_poi
> - *
> - * Return:	Always return zero
> - */
> -static int pl353_nand_write_page_swecc(struct mtd_info *mtd,
> -				    struct nand_chip *chip, const uint8_t *buf,
> -				    int oob_required)
> -{
> -	int i, eccsize = chip->ecc.size;
> -	int eccbytes = chip->ecc.bytes;
> -	int eccsteps = chip->ecc.steps;
> -	uint8_t *ecc_calc = chip->buffers->ecccalc;
> -	const uint8_t *p = buf;
> -	uint32_t *eccpos = chip->ecc.layout->eccpos;
> -
> -	/* Software ecc calculation */
> -	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
> -		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
> -
> -	for (i = 0; i < chip->ecc.total; i++)
> -		chip->oob_poi[eccpos[i]] = ecc_calc[i];
> -
> -	chip->ecc.write_page_raw(mtd, chip, buf, 1);
> -
> -	return 0;
> -}
> +#endif
> 
>  /**
>   * pl353_nand_read_page_hwecc - Hardware ECC based page read function
> @@ -506,6 +513,7 @@ static int pl353_nand_write_page_swecc(struct
> mtd_info *mtd,
>   *
>   * Return:	0 always and updates ECC operation status in to MTD
> structure
>   */
> +#if 0
>  static int pl353_nand_read_page_hwecc(struct mtd_info *mtd,
>  				     struct nand_chip *chip,
>  				     uint8_t *buf, int oob_required, int page)
> @@ -573,52 +581,7 @@ static int pl353_nand_read_page_hwecc(struct
> mtd_info *mtd,
>  	}
>  	return 0;
>  }
> -
> -/**
> - * pl353_nand_read_page_swecc - [REPLACEABLE] software ecc based page
> read
> - * function
> - * @mtd:		Pointer to the mtd info structure
> - * @chip:		Pointer to the NAND chip info structure
> - * @buf:		Pointer to the buffer to store read data
> - * @oob_required:	Caller requires OOB data read to chip->oob_poi
> - * @page:		Page number to read
> - *
> - * Return:	Always return zero
> - */
> -static int pl353_nand_read_page_swecc(struct mtd_info *mtd,
> -				     struct nand_chip *chip,
> -				     uint8_t *buf,  int oob_required, int page)
> -{
> -	int i, eccsize = chip->ecc.size;
> -	int eccbytes = chip->ecc.bytes;
> -	int eccsteps = chip->ecc.steps;
> -	uint8_t *p = buf;
> -	uint8_t *ecc_calc = chip->buffers->ecccalc;
> -	uint8_t *ecc_code = chip->buffers->ecccode;
> -	uint32_t *eccpos = chip->ecc.layout->eccpos;
> -
> -	chip->ecc.read_page_raw(mtd, chip, buf, page, 1);
> -
> -	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
> -		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
> -
> -	for (i = 0; i < chip->ecc.total; i++)
> -		ecc_code[i] = chip->oob_poi[eccpos[i]];
> -
> -	eccsteps = chip->ecc.steps;
> -	p = buf;
> -
> -	for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
> -		int stat;
> -
> -		stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
> -		if (stat < 0)
> -			mtd->ecc_stats.failed++;
> -		else
> -			mtd->ecc_stats.corrected += stat;
> -	}
> -	return 0;
> -}
> +#endif
> 
>  /**
>   * pl353_nand_select_chip - Select the flash device
> @@ -643,10 +606,10 @@ static void pl353_nand_select_chip(struct mtd_info
> *mtd, int chip)
>  static void pl353_nand_cmd_function(struct mtd_info *mtd, unsigned int
> command,
>  				 int column, int page_addr)
>  {
> -	struct nand_chip *chip = mtd->priv;
> -	const struct pl353_nand_command_format *curr_cmd = NULL;
> +	struct nand_chip *chip = mtd_to_nand(mtd);
>  	struct pl353_nand_info *xnand =
> -		container_of(mtd, struct pl353_nand_info, mtd);
> +	    container_of(chip, struct pl353_nand_info, chip);
> +	const struct pl353_nand_command_format *curr_cmd = NULL;
>  	void __iomem *cmd_addr;
>  	unsigned long cmd_data = 0, end_cmd_valid = 0;
>  	unsigned long cmd_phase_addr, data_phase_addr, end_cmd, i;
> @@ -693,33 +656,27 @@ static void pl353_nand_cmd_function(struct
> mtd_info *mtd, unsigned int command,
>  	else
>  		end_cmd = curr_cmd->end_cmd;
> 
> -	if ((command == NAND_CMD_READ0) && (command ==
> NAND_CMD_SEQIN))
> +	if ((command == NAND_CMD_READ0) || (command ==
> NAND_CMD_SEQIN))
>  		addrcycles = xnand->raddr_cycles + xnand->caddr_cycles;
>  	else if (command == NAND_CMD_ERASE1)
>  		addrcycles = xnand->raddr_cycles;
>  	else
>  		addrcycles = curr_cmd->addr_cycles;
> 
> -	cmd_phase_addr = (unsigned long __force)xnand->nand_base        |
> -			 (addrcycles << ADDR_CYCLES_SHIFT)    |
> -			 (end_cmd_valid << END_CMD_VALID_SHIFT)          |
> -			 (COMMAND_PHASE)                                 |
> -			 (end_cmd << END_CMD_SHIFT)                      |
> -			 (curr_cmd->start_cmd << START_CMD_SHIFT);
> -
> -	cmd_addr = (void __iomem * __force)cmd_phase_addr;
> +	cmd_addr =
> +	    xnand->nand_base + ((addrcycles << ADDR_CYCLES_SHIFT) |
> +				(end_cmd_valid << END_CMD_VALID_SHIFT)
> |
> +				(COMMAND_PHASE) | (end_cmd <<
> END_CMD_SHIFT) |
> +				(curr_cmd->start_cmd <<
> START_CMD_SHIFT));
> 
>  	/* Get the data phase address */
>  	end_cmd_valid = 0;
> 
> -	data_phase_addr = (unsigned long __force)xnand->nand_base       |
> -			  (0x0 << CLEAR_CS_SHIFT)                         |
> -			  (end_cmd_valid << END_CMD_VALID_SHIFT)          |
> -			  (DATA_PHASE)                                    |
> -			  (end_cmd << END_CMD_SHIFT)                      |
> -			  (0x0 << ECC_LAST_SHIFT);
> -
> -	chip->IO_ADDR_R = (void __iomem * __force)data_phase_addr;
> +	chip->IO_ADDR_R =
> +	    xnand->nand_base + ((0x0 << CLEAR_CS_SHIFT) |
> +				(end_cmd_valid << END_CMD_VALID_SHIFT)
> |
> +				(DATA_PHASE) | (end_cmd <<
> END_CMD_SHIFT) |
> +				(0x0 << ECC_LAST_SHIFT));
>  	chip->IO_ADDR_W = chip->IO_ADDR_R;
> 
>  	/* Command phase AXI write */
> @@ -779,6 +736,7 @@ static void pl353_nand_cmd_function(struct mtd_info
> *mtd, unsigned int command,
> 
>  		if (time_after_eq(jiffies, timeout))
>  			pr_err("%s timed out\n", __func__);
> +
>  		return;
>  	}
>  }
> @@ -791,8 +749,8 @@ static void pl353_nand_cmd_function(struct mtd_info
> *mtd, unsigned int command,
>   */
>  static void pl353_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int
> len)
>  {
> +	struct nand_chip *chip = mtd_to_nand(mtd);
>  	int i;
> -	struct nand_chip *chip = mtd->priv;
>  	unsigned long *ptr = (unsigned long *)buf;
> 
>  	len >>= 2;
> @@ -809,8 +767,8 @@ static void pl353_nand_read_buf(struct mtd_info
> *mtd, uint8_t *buf, int len)
>  static void pl353_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf,
>  				int len)
>  {
> +	struct nand_chip *chip = mtd_to_nand(mtd);
>  	int i;
> -	struct nand_chip *chip = mtd->priv;
>  	unsigned long *ptr = (unsigned long *)buf;
> 
>  	len >>= 2;
> @@ -843,11 +801,12 @@ static int pl353_nand_device_ready(struct
> mtd_info *mtd)
>   *
>   * Return:	Zero on success and error on failure.
>   */
> +#if 0
>  static int pl353_nand_ecc_init(struct mtd_info *mtd)
>  {
> -	struct nand_chip *nand_chip = mtd->priv;
> +	struct nand_chip *chip = mtd_to_nand(mtd);
>  	struct pl353_nand_info *xnand =
> -		container_of(mtd, struct pl353_nand_info, mtd);
> +	    container_of(chip, struct pl353_nand_info, chip);
> 
>  	nand_chip->ecc.read_oob = pl353_nand_read_oob;
>  	nand_chip->ecc.write_oob = pl353_nand_write_oob;
> @@ -868,7 +827,7 @@ static int pl353_nand_ecc_init(struct mtd_info *mtd)
>  		nand_chip->ecc.hwctl = NULL;
>  		nand_chip->ecc.read_page =
> pl353_nand_read_page_hwecc;
>  		nand_chip->ecc.size = PL353_NAND_ECC_SIZE;
> -		nand_chip->ecc.write_page =
> pl353_nand_write_page_hwecc;
> +//		nand_chip->ecc.write_page =
> pl353_nand_write_page_hwecc;
>  		pl353_smc_set_ecc_pg_size(mtd->dev.parent, mtd-
> >writesize);
>  		pl353_smc_set_ecc_mode(mtd->dev.parent,
> PL353_SMC_ECCMODE_APB);
>  		/* Hardware ECC generates 3 bytes ECC code for each 512
> bytes */
> @@ -904,6 +863,7 @@ static int pl353_nand_ecc_init(struct mtd_info *mtd)
> 
>  	return 0;
>  }
> +#endif
> 
>  static int pl353_nand_init_timing(struct device *dev, int mode)
>  {
> @@ -924,7 +884,7 @@ static int pl353_nand_init_timing(struct device *dev,
> int mode)
>  	t_ar  = get_cyc_from_ns(clkrate, time->tAR_min / 1000);
>  	t_rr  = get_cyc_from_ns(clkrate, time->tRR_min / 1000);
> 
> -	pl353_smc_set_cycles(dev, t_rc, t_wc, t_rea, t_wp, t_clr, t_ar, t_rr);
> +//	pl353_smc_set_cycles(dev, t_rc, t_wc, t_rea, t_wp, t_clr, t_ar, t_rr);
> 
>  	return 0;
>  }
> @@ -943,28 +903,24 @@ static int pl353_nand_probe(struct platform_device
> *pdev)
>  	struct mtd_info *mtd;
>  	struct nand_chip *nand_chip;
>  	struct resource *res;
> -	struct mtd_part_parser_data ppdata;
> 
>  	xnand = devm_kzalloc(&pdev->dev, sizeof(*xnand), GFP_KERNEL);
>  	if (!xnand)
>  		return -ENOMEM;
> 
> +	/* Setup the basic MTD stuff */
> +	mtd = nand_to_mtd(&xnand->chip);
> +	nand_chip = &xnand->chip;
> +	mtd->dev.parent = pdev->dev.parent;
> +	mtd->name = PL353_NAND_DRIVER_NAME;
> +	nand_set_flash_node(nand_chip, pdev->dev.of_node);
> +
>  	/* Map physical address of NAND flash */
>  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>  	xnand->nand_base = devm_ioremap_resource(&pdev->dev, res);
>  	if (IS_ERR(xnand->nand_base))
>  		return PTR_ERR(xnand->nand_base);
> 
> -	/* Link the private data with the MTD structure */
> -	mtd = &xnand->mtd;
> -	nand_chip = &xnand->chip;
> -
> -	nand_chip->priv = xnand;
> -	mtd->priv = nand_chip;
> -	mtd->dev.parent = pdev->dev.parent;
> -	mtd->owner = THIS_MODULE;
> -	mtd->name = PL353_NAND_DRIVER_NAME;
> -
>  	/* Set address of NAND IO lines */
>  	nand_chip->IO_ADDR_R = xnand->nand_base;
>  	nand_chip->IO_ADDR_W = xnand->nand_base;
> @@ -973,42 +929,46 @@ static int pl353_nand_probe(struct platform_device
> *pdev)
>  	nand_chip->cmdfunc = pl353_nand_cmd_function;
>  	nand_chip->dev_ready = pl353_nand_device_ready;
>  	nand_chip->select_chip = pl353_nand_select_chip;
> -
> -	/* If we don't set this delay driver sets 20us by default */
> -	nand_chip->chip_delay = 30;
> -
> -	/* Buffer read/write routines */
>  	nand_chip->read_buf = pl353_nand_read_buf;
>  	nand_chip->write_buf = pl353_nand_write_buf;
> -
> -	/* Set the device option and flash width */
>  	nand_chip->options = NAND_BUSWIDTH_AUTO;
> -	nand_chip->bbt_options = NAND_BBT_USE_FLASH;
> +//	nand_chip->bbt_options = NAND_BBT_USE_FLASH;
> +
> +	/* If we don't set this delay driver sets 20us by default */
> +	nand_chip->chip_delay = 30;
> +	// FIXME: from dt
> +	nand_chip->chip_delay = 50;
> 
>  	platform_set_drvdata(pdev, xnand);
>  	if (pl353_nand_init_timing(pdev->dev.parent, 0))
>  		return -ENOTSUPP;
> +
>  	/* First scan to find the device and get the page size */
>  	if (nand_scan_ident(mtd, 1, NULL)) {
>  		dev_err(&pdev->dev, "nand_scan_ident for NAND
> failed\n");
>  		return -ENXIO;
>  	}
> 
> -	xnand->ecc_mode = of_get_nand_ecc_mode(pdev->dev.of_node);
> -	if (xnand->ecc_mode < 0)
> -		xnand->ecc_mode = NAND_ECC_HW;
> -
>  	if (nand_chip->onfi_version) {
>  		xnand->raddr_cycles = nand_chip->onfi_params.addr_cycles
> & 0xF;
>  		xnand->caddr_cycles =
>  				(nand_chip->onfi_params.addr_cycles >> 4)
> & 0xF;
>  	} else {
> -		/*For non-ONFI devices, configuring the address cyles as 5 */
> -		xnand->raddr_cycles = xnand->caddr_cycles = 5;
> +		/* For non-ONFI devices, configure the address cyles based
> on
> +		 * the device size */
> +		xnand->caddr_cycles = 2;
> +		if (nand_chip->chipsize > (128 << 20))
> +			xnand->raddr_cycles = 3;
> +		else
> +			xnand->raddr_cycles = 2;
>  	}
> 
> -	if (pl353_nand_ecc_init(mtd))
> -		return -ENOTSUPP;
> +	nand_chip->ecc.read_oob = pl353_nand_read_oob;
> +	nand_chip->ecc.write_oob = pl353_nand_write_oob;
> +	nand_chip->ecc.read_page_raw = pl353_nand_read_page_raw;
> +	nand_chip->ecc.write_page_raw = pl353_nand_write_page_raw;
> +/*	if (pl353_nand_ecc_init(mtd))
> +	return -ENOTSUPP;*/
> 
>  	if (nand_chip->options & NAND_BUSWIDTH_16)
>  		pl353_smc_set_buswidth(pdev->dev.parent,
> @@ -1021,9 +981,7 @@ static int pl353_nand_probe(struct platform_device
> *pdev)
>  		return -ENXIO;
>  	}
> 
> -	ppdata.of_node = pdev->dev.of_node;
> -
> -	mtd_device_parse_register(&xnand->mtd, NULL, &ppdata, NULL, 0);
> +	mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
> 
>  	return 0;
>  }
> @@ -1042,7 +1000,7 @@ static int pl353_nand_remove(struct
> platform_device *pdev)
>  	struct pl353_nand_info *xnand = platform_get_drvdata(pdev);
> 
>  	/* Release resources, unregister device */
> -	nand_release(&xnand->mtd);
> +	nand_release(nand_to_mtd(&xnand->chip));
> 
>  	return 0;
>  }


From wens at csie.org  Mon Oct 24 21:10:26 2016
From: wens at csie.org (Chen-Yu Tsai)
Date: Tue, 25 Oct 2016 12:10:26 +0800
Subject: [PATCH 5/8] ARM: gr8: Add missing pwm channel 1 pin
In-Reply-To: <20161020170739.lgt2ywm346vm47zd@lukather>
References: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
 <0df42247c3348e7f6aed945e5669cec87f96f7ac.1476951078.git-series.maxime.ripard@free-electrons.com>
 <CAGb2v66w0sTzn_SWH4rrpWKOosSxALV8ot3CBQbGhwLxvX1vxw@mail.gmail.com>
 <20161020170739.lgt2ywm346vm47zd@lukather>
Message-ID: <CAGb2v64Ai+8sUPyH9aTnKUw1ROmQNxzCEqUXrT4v8Q-nipqR3Q@mail.gmail.com>

On Fri, Oct 21, 2016 at 1:07 AM, Maxime Ripard
<maxime.ripard at free-electrons.com> wrote:
> On Thu, Oct 20, 2016 at 10:10:03PM +0800, Chen-Yu Tsai wrote:
>> On Thu, Oct 20, 2016 at 4:12 PM, Maxime Ripard
>> <maxime.ripard at free-electrons.com> wrote:
>> > The PWM controller has two different channels, but only the first pin was
>> > exposed in the DTSI. Add the other one.
>> >
>> > Signed-off-by: Maxime Ripard <maxime.ripard at free-electrons.com>
>>
>> Acked-by: Chen-Yu Tsai <wens at csie.org>
>>
>> > ---
>> >  arch/arm/boot/dts/ntc-gr8.dtsi | 7 +++++++
>> >  1 file changed, 7 insertions(+), 0 deletions(-)
>> >
>> > diff --git a/arch/arm/boot/dts/ntc-gr8.dtsi b/arch/arm/boot/dts/ntc-gr8.dtsi
>> > index 74aff795e723..fad7381630f3 100644
>> > --- a/arch/arm/boot/dts/ntc-gr8.dtsi
>> > +++ b/arch/arm/boot/dts/ntc-gr8.dtsi
>> > @@ -854,6 +854,13 @@
>> >                                 allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
>> >                         };
>> >
>> > +                       pwm1_pins_a: pwm1 at 0 {
>>
>> Nit: really don't need "_a" and "@0" here.
>
> Fixed and applied.

Oops, you forgot to fix the label in the chip-pro dts:

  DTC     arch/arm/boot/dts/ntc-gr8-chip-pro.dtb
ERROR (phandle_references): Reference to non-existent node or label
"pwm1_pins_a"

ERROR: Input tree has errors, aborting (use -f to force output)
scripts/Makefile.lib:313: recipe for target
'arch/arm/boot/dts/ntc-gr8-chip-pro.dtb' failed

ChenYu


From jgunthorpe at obsidianresearch.com  Mon Oct 24 21:46:08 2016
From: jgunthorpe at obsidianresearch.com (Jason Gunthorpe)
Date: Mon, 24 Oct 2016 22:46:08 -0600
Subject: [v7, 1/3] nand: pl353: Add basic driver for arm pl353 smc nand
 interface
In-Reply-To: <03CA77BA8AF6F1469AEDFBDA1322A7B764216D8A@XAP-PVEXMBX02.xlnx.xilinx.com>
References: <1433786918-21500-2-git-send-email-punnaia@xilinx.com>
 <20161021203322.GA28655@obsidianresearch.com>
 <20161021234611.1f737144@bbrezillon>
 <CAGnW=Bb-pnJ9-xjcw-1dR-y+oKjNs53bgD+dh1LwsMTCmzdRmQ@mail.gmail.com>
 <20161024225954.GA12438@obsidianresearch.com>
 <03CA77BA8AF6F1469AEDFBDA1322A7B764216D8A@XAP-PVEXMBX02.xlnx.xilinx.com>
Message-ID: <20161025044608.GA4929@obsidianresearch.com>

On Tue, Oct 25, 2016 at 03:58:49AM +0000, Punnaiah Choudary Kalluri wrote:

> > I have hacked the v7 patchset enough to work on 4.8 and hacked it some
> > more to work on my hardware. The driver appears to be in no better
> > shape than the 3.12 out-of-tree Xilinx release I was using previously..
>
> The driver in Xilinx tree works with 4.6 kernel and adopted the
> required

I mean, the driver from the 3.12 Xilinx tree that I last looked
at years ago. This is at v7 now and is still needs lots of work, I did
some fixing, including making parts of it work on 4.8.
You can copy it out of the patch I sent you.

> Changes (may release in 1-2 weeks). Still it need some rework, now a days
> I am seeing many requests from different people for this driver and some of
> Them are using different version of IP as you know this IP has four variants and
> Xilinx is using the pl353 variant.

Well, I am using Xilinx Zynq hardware and care about making that
configuration actually work. This is the last driver I require to use
Zynq with mainline.

It clearly needs more work than just forward porting to 4.8, so please
let me know if you are able to tackle this.

> Let's wait for the next series of patches and Get the patches tested
> with others as well along with the review comments.

You now have 10 review comments from me, please respond to all of them in
your v8 patchset - no sense in continuing to drag this out.

Please cc me on future series.

Jason

> Regards,
> Punnaiah
> > I've attached the ugly, ugly patch I made, it may save you some time
> > when preparing v8.
> > 
> > Commentary:
> >  1) nand_chip already includes mtd_info, no reason for a second one in
> >     the pl353_nand_info struct. The standard accessors mtd_to_nand/etc
> >     should be used instead of priv
> >  2) I hacked out all the ECC stuff from the driver since I don't use
> >     it and it was broken.. Obviously some has to come back, but fixing
> >     other things on this list first will make that much easier and better..
> >  3) pl353_nand_write_page_swecc/pl353_nand_read_page_swecc are pure
> >     outdated copies of the core routines and should not exist in a
> >     driver. This needs to be fixed so nand_scan_tail sets them.
> >     This seems to be a side effect of #9 ?
> >  4) The hacky stuff to detect 2 vs 3 address cycle NAND doesn't work,
> >     and doesn't work without ONFI (see patch for possible fix). The
> >     driver should probably use the same scheme the core code uses..
> >     But this is all a problem because of #10
> >  5) The driver assumes alignment of the iomap, needs to use + not |
> >     when constructing the address. (yes, this blows up on my system)
> >  6) Driver unconditionally sets timing to ONFI mode 0 (slow!)
> >     Maybe timing should be common code driven by DT..
> >  7) Driver unconditionally selects a BBT format, and an ECC layout
> >     (neither match what my system uses, but I guess that is a core mtd
> >     issue these days :/)
> >  8) Driver unconditionally forces a chip-delay (wrong for my
> >     system) maybe this should be common code driven by DT..
> >  9) This buisness with pl353_nand_ecc_init and the
> >     special functions to do PL353_NAND_LAST_TRANSFER_LENGTH stuff
> >     is just horrid. I'd expect that is a big NAK.
> > 
> >     The driver needs to implement read_buf *properly* so the core
> >     routines can be used instead of trying to 'fix' the call sites
> >     to do the PL353_NAND_LAST_TRANSFER_LENGTH stuff.
> >  10) pl353_nand_cmd_function is a wonky copy of nand_command_lp,
> > maybe
> >      this driver should use cmd_ctrl, or the core code should be
> >      refactored some more..


From punnaiah.choudary.kalluri at xilinx.com  Mon Oct 24 22:02:47 2016
From: punnaiah.choudary.kalluri at xilinx.com (Punnaiah Choudary Kalluri)
Date: Tue, 25 Oct 2016 05:02:47 +0000
Subject: [v7, 1/3] nand: pl353: Add basic driver for arm pl353 smc nand
 interface
In-Reply-To: <20161025044608.GA4929@obsidianresearch.com>
References: <1433786918-21500-2-git-send-email-punnaia@xilinx.com>
 <20161021203322.GA28655@obsidianresearch.com>
 <20161021234611.1f737144@bbrezillon>
 <CAGnW=Bb-pnJ9-xjcw-1dR-y+oKjNs53bgD+dh1LwsMTCmzdRmQ@mail.gmail.com>
 <20161024225954.GA12438@obsidianresearch.com>
 <03CA77BA8AF6F1469AEDFBDA1322A7B764216D8A@XAP-PVEXMBX02.xlnx.xilinx.com>
 <20161025044608.GA4929@obsidianresearch.com>
Message-ID: <03CA77BA8AF6F1469AEDFBDA1322A7B764216E5A@XAP-PVEXMBX02.xlnx.xilinx.com>



> -----Original Message-----
> From: Jason Gunthorpe [mailto:jgunthorpe at obsidianresearch.com]
> Sent: Tuesday, October 25, 2016 10:16 AM
> To: Punnaiah Choudary Kalluri <punnaia at xilinx.com>
> Cc: Boris Brezillon <boris.brezillon at free-electrons.com>;
> mark.rutland at arm.com; linux-mtd at lists.infradead.org;
> michal.simek at xilinx.com; ezequiel.garcia at free-electrons.com; linux-
> kernel at vger.kernel.org; rob at landley.net; galak at codeaurora.org;
> computersforpeace at gmail.com; dwmw2 at infradead.org
> Subject: Re: [v7, 1/3] nand: pl353: Add basic driver for arm pl353 smc nand
> interface
>
> On Tue, Oct 25, 2016 at 03:58:49AM +0000, Punnaiah Choudary Kalluri wrote:
>
> > > I have hacked the v7 patchset enough to work on 4.8 and hacked it some
> > > more to work on my hardware. The driver appears to be in no better
> > > shape than the 3.12 out-of-tree Xilinx release I was using previously..
> >
> > The driver in Xilinx tree works with 4.6 kernel and adopted the
> > required
>
> I mean, the driver from the 3.12 Xilinx tree that I last looked
> at years ago. This is at v7 now and is still needs lots of work, I did
> some fixing, including making parts of it work on 4.8.
> You can copy it out of the patch I sent you.
>
> > Changes (may release in 1-2 weeks). Still it need some rework, now a days
> > I am seeing many requests from different people for this driver and some
> of
> > Them are using different version of IP as you know this IP has four variants
> and
> > Xilinx is using the pl353 variant.
>
> Well, I am using Xilinx Zynq hardware and care about making that
> configuration actually work. This is the last driver I require to use
> Zynq with mainline.
>

Sure.

> It clearly needs more work than just forward porting to 4.8, so please
> let me know if you are able to tackle this.

I didn't say that I am forwarding the patch working with 4.8. I said
We made changes to driver compatible for 4.6 and working on driver rework,
Most of your comments also part of that.

>
> > Let's wait for the next series of patches and Get the patches tested
> > with others as well along with the review comments.
>
> You now have 10 review comments from me, please respond to all of them
> in
> your v8 patchset - no sense in continuing to drag this out.
>

See above.

> Please cc me on future series.

Ok.

Regards,
Punnaiah

>
> Jason
>
> > Regards,
> > Punnaiah
> > > I've attached the ugly, ugly patch I made, it may save you some time
> > > when preparing v8.
> > >
> > > Commentary:
> > >  1) nand_chip already includes mtd_info, no reason for a second one in
> > >     the pl353_nand_info struct. The standard accessors mtd_to_nand/etc
> > >     should be used instead of priv
> > >  2) I hacked out all the ECC stuff from the driver since I don't use
> > >     it and it was broken.. Obviously some has to come back, but fixing
> > >     other things on this list first will make that much easier and better..
> > >  3) pl353_nand_write_page_swecc/pl353_nand_read_page_swecc are
> pure
> > >     outdated copies of the core routines and should not exist in a
> > >     driver. This needs to be fixed so nand_scan_tail sets them.
> > >     This seems to be a side effect of #9 ?
> > >  4) The hacky stuff to detect 2 vs 3 address cycle NAND doesn't work,
> > >     and doesn't work without ONFI (see patch for possible fix). The
> > >     driver should probably use the same scheme the core code uses..
> > >     But this is all a problem because of #10
> > >  5) The driver assumes alignment of the iomap, needs to use + not |
> > >     when constructing the address. (yes, this blows up on my system)
> > >  6) Driver unconditionally sets timing to ONFI mode 0 (slow!)
> > >     Maybe timing should be common code driven by DT..
> > >  7) Driver unconditionally selects a BBT format, and an ECC layout
> > >     (neither match what my system uses, but I guess that is a core mtd
> > >     issue these days :/)
> > >  8) Driver unconditionally forces a chip-delay (wrong for my
> > >     system) maybe this should be common code driven by DT..
> > >  9) This buisness with pl353_nand_ecc_init and the
> > >     special functions to do PL353_NAND_LAST_TRANSFER_LENGTH stuff
> > >     is just horrid. I'd expect that is a big NAK.
> > >
> > >     The driver needs to implement read_buf *properly* so the core
> > >     routines can be used instead of trying to 'fix' the call sites
> > >     to do the PL353_NAND_LAST_TRANSFER_LENGTH stuff.
> > >  10) pl353_nand_cmd_function is a wonky copy of nand_command_lp,
> > > maybe
> > >      this driver should use cmd_ctrl, or the core code should be
> > >      refactored some more..


This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.



From marcin.krzeminski at nokia.com  Mon Oct 24 22:43:44 2016
From: marcin.krzeminski at nokia.com (Krzeminski, Marcin (Nokia - PL/Wroclaw))
Date: Tue, 25 Oct 2016 05:43:44 +0000
Subject: [PATCH 1/3] mtd: spi-nor: Add die_cnt field and flags
In-Reply-To: <0386ac08-f41e-1e10-d0e6-a16624bba952@atmel.com>
References: <1477314214-17718-1-git-send-email-marcin.krzeminski@nokia.com>
 <1477314214-17718-2-git-send-email-marcin.krzeminski@nokia.com>
 <0386ac08-f41e-1e10-d0e6-a16624bba952@atmel.com>
Message-ID: <AM4PR0701MB2130E8217FE5642F6FF3E362FEA80@AM4PR0701MB2130.eurprd07.prod.outlook.com>

Hi Cyrille,

> -----Original Message-----
> From: Cyrille Pitchen [mailto:cyrille.pitchen at atmel.com]
> Sent: Monday, October 24, 2016 3:55 PM
> To: Krzeminski, Marcin (Nokia - PL/Wroclaw)
> <marcin.krzeminski at nokia.com>; linux-mtd at lists.infradead.org
> Cc: rfsw-patches at mlist.nokia.com; dwmw2 at infradead.org;
> computersforpeace at gmail.com; marek.vasut at gmail.com
> Subject: Re: [PATCH 1/3] mtd: spi-nor: Add die_cnt field and flags
> 
> Hi Marcin,
> 
> Le 24/10/2016 ? 15:03, marcin.krzeminski at nokia.com a ?crit :
> > From: Marcin Krzeminski <marcin.krzeminski at nokia.com>
> >
> > This commit adds new field and flags that could be used to signalize
> > that chip support die erase command.
> >
> > If DIE_ERASE flag will be selected but die_cnt field will be 0 chip
> > will not use chip erase command.
> >
> > Signed-off-by: Marcin Krzeminski <marcin.krzeminski at nokia.com>
> > ---
> >  drivers/mtd/spi-nor/spi-nor.c | 18 ++++++++++++++++++
> >  include/linux/mtd/spi-nor.h   |  5 +++++
> >  2 files changed, 23 insertions(+)
> >
> > diff --git a/drivers/mtd/spi-nor/spi-nor.c
> > b/drivers/mtd/spi-nor/spi-nor.c index d0fc165..3afe207 100644
> > --- a/drivers/mtd/spi-nor/spi-nor.c
> > +++ b/drivers/mtd/spi-nor/spi-nor.c
> > @@ -75,6 +75,7 @@ struct flash_info {
> >  					 * bit. Must be used with
> >  					 * SPI_NOR_HAS_LOCK.
> >  					 */
> > +#define DIE_ERASE			BIT(10)	/* Support for die erase cmd
> */
> >  };
> >
> >  #define JEDEC_MFR(info)	((info)->id[0])
> > @@ -295,6 +296,23 @@ static int erase_chip(struct spi_nor *nor)
> >  	return nor->write_reg(nor, SPINOR_OP_CHIP_ERASE, NULL, 0);  }
> >
> > +static int spi_nor_die_erase(struct spi_nor *nor, u32 addr) {
> > +	u8 buf[SPI_NOR_MAX_ADDR_WIDTH];
> > +	int i;
> > +
> > +	dev_dbg(nor->dev, "erase @ 0x%X\n", addr);
> > +
> > +	write_enable(nor);
> > +
> > +	for (i = nor->addr_width - 1; i >= 0; i--) {
> > +		buf[i] = addr & 0xff;
> > +		addr >>= 8;
> > +	}
> > +
> > +	return nor->write_reg(nor, SPINOR_OP_DIE_ERASE, buf,
> > +nor->addr_width);
> 
> If think you should first check whether nor->erase() is implemented by the
> SPI controller driver and call it instead of nor->write_reg().
> 
> For instance, some SPI controllers are mapped to the system memory to
> speed up Fast Read operations. In which case, they could also enable data
> cache to fasten even more the read operations.
> 
> So when the spi-nor framework calls nor->erase() or nor->write(), those
> handlers might need to invalidate the cache before performing the next
> read.
> 
> This is just an example but generally speaking, don't forget the nor->erase()
> handler! :)
> 
Thanks for extensive clarification, I will include this in v2.

Regards,
Marcin

> 
> > +}
> > +
> >  static int spi_nor_lock_and_prep(struct spi_nor *nor, enum
> > spi_nor_ops ops)  {
> >  	int ret = 0;
> > diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
> > index c425c7b..80154b2 100644
> > --- a/include/linux/mtd/spi-nor.h
> > +++ b/include/linux/mtd/spi-nor.h
> > @@ -50,6 +50,7 @@
> >  #define SPINOR_OP_BE_4K_PMC	0xd7	/* Erase 4KiB block on PMC
> chips */
> >  #define SPINOR_OP_BE_32K	0x52	/* Erase 32KiB block */
> >  #define SPINOR_OP_CHIP_ERASE	0xc7	/* Erase whole flash chip */
> > +#define SPINOR_OP_DIE_ERASE	0xc4	/* Erase whole die within chip
> */
> >  #define SPINOR_OP_SE		0xd8	/* Sector erase (usually
> 64KiB) */
> >  #define SPINOR_OP_RDID		0x9f	/* Read JEDEC ID */
> >  #define SPINOR_OP_RDCR		0x35	/* Read configuration register
> */
> > @@ -119,6 +120,7 @@ enum spi_nor_ops {  enum spi_nor_option_flags {
> >  	SNOR_F_USE_FSR		= BIT(0),
> >  	SNOR_F_HAS_SR_TB	= BIT(1),
> > +	SNOR_F_DIE_ERASE	= BIT(2),
> >  };
> >
> >  /**
> > @@ -136,6 +138,8 @@ enum spi_nor_option_flags {
> >   * @sst_write_second:	used by the SST write operation
> >   * @flags:		flag options for the current SPI-NOR (SNOR_F_*)
> >   * @cmd_buf:		used by the write_reg
> > + * @die_cnt:		number of dies in chip, if and
> SNOR_F_DIE_ERASE
> 
> The 1st flag is missing between "if" and "and", isn't it?
> > + * 			flasg is enabled CE command will be disabled
> 
> typo: s/flasg/flags/
> >   * @prepare:		[OPTIONAL] do some preparations for the
> >   *			read/write/erase/lock/unlock operations
> >   * @unprepare:		[OPTIONAL] do some post work after the
> > @@ -167,6 +171,7 @@ struct spi_nor {
> >  	bool			sst_write_second;
> >  	u32			flags;
> >  	u8			cmd_buf[SPI_NOR_MAX_CMD_SIZE];
> > +	u32			die_cnt;
> >
> >  	int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);
> >  	void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops);
> >
> 
> Best regards,
> 
> Cyrille


From naga.sureshkumar.relli at xilinx.com  Mon Oct 24 22:52:49 2016
From: naga.sureshkumar.relli at xilinx.com (Naga Sureshkumar Relli)
Date: Tue, 25 Oct 2016 05:52:49 +0000
Subject: UBIFS with dma on 4.6 kernel is not working
In-Reply-To: <20161021131505.GA25942@infradead.org>
References: <DA6901612C71B84D91459DE817C418AE26DF0F2B@XAP-PVEXMBX01.xlnx.xilinx.com>
 <519a83bf-1244-5151-b873-bb8e1f2db3c6@nod.at>
 <20161021125313.GA16754@infradead.org>
 <c0b0098d-3a68-3a4a-0b7e-a1d95dd4aafc@nod.at>
 <20161021131505.GA25942@infradead.org>
Message-ID: <DA6901612C71B84D91459DE817C418AE26E0015A@XAP-PVEXMBX01.xlnx.xilinx.com>

Hi,

Thanks everybody for your valuable information.

I am not aware of all these dma related APIs but where to handle these dma stuff?
Is it in UBI/UBIFS(at the time of vmalloc allocations)? Or in controller driver?

And also is there a way to know the memory allocated using vmalloc is contiguous or not?
Based on that I can switch my driver to work in dma or non-dma mode for ubifs use.

Thanks,
Naga Sureshkumar Relli

-----Original Message-----
From: Christoph Hellwig [mailto:hch at infradead.org] 
Sent: Friday, October 21, 2016 6:45 PM
To: Richard Weinberger <richard at nod.at>
Cc: Christoph Hellwig <hch at infradead.org>; Naga Sureshkumar Relli <nagasure at xilinx.com>; dwmw2 at infradead.org; computersforpeace at gmail.com; dedekind1 at gmail.com; adrian.hunter at intel.com; michal.simek at xilinx.com; Punnaiah Choudary Kalluri <punnaia at xilinx.com>; linux-mtd at lists.infradead.org; linux-kernel at vger.kernel.org; Boris Brezillon <boris.brezillon at free-electrons.com>
Subject: Re: UBIFS with dma on 4.6 kernel is not working

On Fri, Oct 21, 2016 at 03:07:57PM +0200, Richard Weinberger wrote:
> Hmm, thought this is still problematic on VIVT architectures.
> Boris tried to provide a solution for that some time ago:
> http://www.spinics.net/lists/arm-kernel/msg494025.html

Things have been working fine for approx 10 years when using flush_kernel_vmap_range before doing I/O using the physical addresses and then invalidate_kernel_vmap_range when completing the I/O and going back to using the virtual mapping for XFS.

Of course all this assumes at least the higher level that did the vm_map_ram operation knows about this dance between virtually mapped and physiscal addresses. 


From naga.sureshkumar.relli at xilinx.com  Mon Oct 24 23:05:32 2016
From: naga.sureshkumar.relli at xilinx.com (Naga Sureshkumar Relli)
Date: Tue, 25 Oct 2016 06:05:32 +0000
Subject: UBIFS LEB properties tree with odd addresses
Message-ID: <DA6901612C71B84D91459DE817C418AE26E0016D@XAP-PVEXMBX01.xlnx.xilinx.com>

Hi,

We are testing UBIFS (NOR) on Zynq Ultrascale+ MPSoC GQSPI controller driver.
Apart from my previous mail thread about UBIFS, i.e along with dma issue I am facing one more
Problem related to offsets.

Info about GQSPI Controller:
This controller can access the flash device in the following modes.
1. Single flash mode
2. Two spi flash memories with separate buses (dual parallel)

Single flash mode: it is normal configuration, one controller and one flash memory

In dual parallel mode following are the functionalities:
1) Supporting two SPI flash memories operating in parallel. 8 I/O lines.
2) Chip selects and clock are shared to both the flash devices
3) This mode is targeted for faster read/write speed and also doubles the size
4) Commands/data can be transmitted/received from both the devices(mirror), or only upper or only lower flash memory devices.
5) Data arrangement:
??? With stripe (controller configuration) enabled,
??? Even bytes i.e. 0, 2, 4,... are transmitted on Lower Data Bus
??? Odd bytes i.e. 1, 3, 5,.. are transmitted on Upper Data Bus.

Kernel version : 4.4.0
Controller limitation: ZynqMP gqspi controller supports only even addresses when two flash devices are connected (dual parallel mode).

Issue I am facing:
-> Since our controller supports even addresses in dual parallel mode
We are seeing issues with ubifs in dual parallel mode and jffs2 is working fine and we observed the following:

IN dual parallel mode, the Erase block size was 128KiB whereas single flash mode the Erase block size was 64KiB.
In single flash mode, we are getting pnode_sz value as 16 and for dual parallel mode we are getting an odd value 17
And ltab_sz value in single mode as 12 and in dual parallel mode as 11.
Because of these odd values, check_lpt_type  offset argument is odd address and hence lpt_type error.

When I ran the mnt command, I am getting the following error
"UBIFS error (ubi0:0 pid 1882): check_lpt_type: invalid type (4) in LPT node type 2"
Ran the below commands:
a)ubiformat /dev/mtd0 -e 0 -y
b)ubiattach -p /dev/mtd0
c)ubimkvol -N data -m /dev/ubi0
d)mount -t ubifs ubi0:data /mnt

So for temporary hack we did the following change
In fs/ubifs/lpt.c
In do_calc_lpt_geom(), added the following
+?????? if (c->pnode_sz % 2)
+?????????????? c->pnode_sz += 1; 
+?????? if (c->ltab_sz % 2)
+?????????????? c->ltab_sz += 1;

Please kindly suggest, I need your inputs, changing the pnode_sz and ltab_sz to even in lpt.c, will it impact on any others?
We can do the same change in spi layer (change the address to even) but the above properties won't reflect in ubi layer.
Kindly please suggest.
If I haven't provided sufficient information, please let me know.

Thanks,
Naga Sureshkumar Relli




From s.hauer at pengutronix.de  Mon Oct 24 23:09:55 2016
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Tue, 25 Oct 2016 08:09:55 +0200
Subject: [PATCH] mtd: nand: Fix data interface configuration logic
In-Reply-To: <1477320380-11062-1-git-send-email-boris.brezillon@free-electrons.com>
References: <1477320380-11062-1-git-send-email-boris.brezillon@free-electrons.com>
Message-ID: <20161025060955.4kn76hgilglhvehd@pengutronix.de>

On Mon, Oct 24, 2016 at 04:46:20PM +0200, Boris Brezillon wrote:
> When changing from one data interface setting to another, one has to
> ensure a specific sequence which is described in the ONFI spec.
> 
> One of these constraints is that the CE line has go high after a reset
> before a command can be sent with the new data interface setting, which
> is not guaranteed by the current implementation.
> 
> Rework the nand_reset() function and all the call sites to make sure the
> CE line is asserted and released when required.
> 
> Also make sure to actually apply the new data interface setting on the
> first die.
> 
> Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
> Fixes: d8e725dd8311 ("mtd: nand: automate NAND timings selection")

Reviewed-by: Sascha Hauer <s.hauer at pengutronix.de>

Sasha

> ---
>  drivers/mtd/nand/nand_base.c | 60 +++++++++++++++++++++++++++++++-------------
>  include/linux/mtd/nand.h     |  2 +-
>  2 files changed, 43 insertions(+), 19 deletions(-)
> 
> diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
> index e5718e5ecf92..3bde96a3f7bf 100644
> --- a/drivers/mtd/nand/nand_base.c
> +++ b/drivers/mtd/nand/nand_base.c
> @@ -1095,10 +1095,11 @@ static void nand_release_data_interface(struct nand_chip *chip)
>  /**
>   * nand_reset - Reset and initialize a NAND device
>   * @chip: The NAND chip
> + * @chipnr: Internal die id
>   *
>   * Returns 0 for success or negative error code otherwise
>   */
> -int nand_reset(struct nand_chip *chip)
> +int nand_reset(struct nand_chip *chip, int chipnr)
>  {
>  	struct mtd_info *mtd = nand_to_mtd(chip);
>  	int ret;
> @@ -1107,9 +1108,17 @@ int nand_reset(struct nand_chip *chip)
>  	if (ret)
>  		return ret;
>  
> +	/*
> +	 * The CS line has to be released before we can apply the new NAND
> +	 * interface settings, hence this weird ->select_chip() dance.
> +	 */
> +	chip->select_chip(mtd, chipnr);
>  	chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
> +	chip->select_chip(mtd, -1);
>  
> +	chip->select_chip(mtd, chipnr);
>  	ret = nand_setup_data_interface(chip);
> +	chip->select_chip(mtd, -1);
>  	if (ret)
>  		return ret;
>  
> @@ -1185,8 +1194,6 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
>  	/* Shift to get chip number */
>  	chipnr = ofs >> chip->chip_shift;
>  
> -	chip->select_chip(mtd, chipnr);
> -
>  	/*
>  	 * Reset the chip.
>  	 * If we want to check the WP through READ STATUS and check the bit 7
> @@ -1194,7 +1201,9 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
>  	 * some operation can also clear the bit 7 of status register
>  	 * eg. erase/program a locked block
>  	 */
> -	nand_reset(chip);
> +	nand_reset(chip, chipnr);
> +
> +	chip->select_chip(mtd, chipnr);
>  
>  	/* Check, if it is write protected */
>  	if (nand_check_wp(mtd)) {
> @@ -1244,8 +1253,6 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
>  	/* Shift to get chip number */
>  	chipnr = ofs >> chip->chip_shift;
>  
> -	chip->select_chip(mtd, chipnr);
> -
>  	/*
>  	 * Reset the chip.
>  	 * If we want to check the WP through READ STATUS and check the bit 7
> @@ -1253,7 +1260,9 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
>  	 * some operation can also clear the bit 7 of status register
>  	 * eg. erase/program a locked block
>  	 */
> -	nand_reset(chip);
> +	nand_reset(chip, chipnr);
> +
> +	chip->select_chip(mtd, chipnr);
>  
>  	/* Check, if it is write protected */
>  	if (nand_check_wp(mtd)) {
> @@ -2940,10 +2949,6 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
>  	}
>  
>  	chipnr = (int)(to >> chip->chip_shift);
> -	chip->select_chip(mtd, chipnr);
> -
> -	/* Shift to get page */
> -	page = (int)(to >> chip->page_shift);
>  
>  	/*
>  	 * Reset the chip. Some chips (like the Toshiba TC5832DC found in one
> @@ -2951,7 +2956,12 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
>  	 * if we don't do this. I have no clue why, but I seem to have 'fixed'
>  	 * it in the doc2000 driver in August 1999.  dwmw2.
>  	 */
> -	nand_reset(chip);
> +	nand_reset(chip, chipnr);
> +
> +	chip->select_chip(mtd, chipnr);
> +
> +	/* Shift to get page */
> +	page = (int)(to >> chip->page_shift);
>  
>  	/* Check, if it is write protected */
>  	if (nand_check_wp(mtd)) {
> @@ -3984,14 +3994,14 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
>  	int i, maf_idx;
>  	u8 id_data[8];
>  
> -	/* Select the device */
> -	chip->select_chip(mtd, 0);
> -
>  	/*
>  	 * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
>  	 * after power-up.
>  	 */
> -	nand_reset(chip);
> +	nand_reset(chip, 0);
> +
> +	/* Select the device */
> +	chip->select_chip(mtd, 0);
>  
>  	/* Send the command for reading device ID */
>  	chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
> @@ -4329,17 +4339,31 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
>  		return PTR_ERR(type);
>  	}
>  
> +	/* Initialize the ->data_interface field. */
>  	ret = nand_init_data_interface(chip);
>  	if (ret)
>  		return ret;
>  
> +	/*
> +	 * Setup the data interface correctly on the chip and controller side.
> +	 * This explicit call to nand_setup_data_interface() is only required
> +	 * for the first die, because nand_reset() has been called before
> +	 * ->data_interface and ->default_onfi_timing_mode were set.
> +	 * For the other dies, nand_reset() will automatically switch to the
> +	 * best mode for us.
> +	 */
> +	ret = nand_setup_data_interface(chip);
> +	if (ret)
> +		return ret;
> +
>  	chip->select_chip(mtd, -1);
>  
>  	/* Check for a chip array */
>  	for (i = 1; i < maxchips; i++) {
> -		chip->select_chip(mtd, i);
>  		/* See comment in nand_get_flash_type for reset */
> -		nand_reset(chip);
> +		nand_reset(chip, i);
> +
> +		chip->select_chip(mtd, i);
>  		/* Send the command for reading device ID */
>  		chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
>  		/* Read manufacturer and device IDs */
> diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
> index c5d3d5024fc8..d8905a229f34 100644
> --- a/include/linux/mtd/nand.h
> +++ b/include/linux/mtd/nand.h
> @@ -1184,7 +1184,7 @@ int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
>  			   int page);
>  
>  /* Reset and initialize a NAND device */
> -int nand_reset(struct nand_chip *chip);
> +int nand_reset(struct nand_chip *chip, int chipnr);
>  
>  /* Free resources held by the NAND device */
>  void nand_cleanup(struct nand_chip *chip);
> -- 
> 2.7.4
> 
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From cyrille.pitchen at atmel.com  Tue Oct 25 01:52:01 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Tue, 25 Oct 2016 10:52:01 +0200
Subject: [PATCH v3 1/9] mtd: spi-nor: improve macronix_quad_enable()
In-Reply-To: <74f0fa1b-3212-8a21-f966-14f153d2bf43@denx.de>
References: <cover.1477325128.git.cyrille.pitchen@atmel.com>
 <c63d3715903e640c7ea5328614bd4468688b761d.1477325128.git.cyrille.pitchen@atmel.com>
 <74f0fa1b-3212-8a21-f966-14f153d2bf43@denx.de>
Message-ID: <6948ab96-62ab-c383-4f50-e897be0999b3@atmel.com>

Hi Marek,

Le 25/10/2016 ? 00:00, Marek Vasut a ?crit :
> On 10/24/2016 06:34 PM, Cyrille Pitchen wrote:
>> The patch checks whether the Quad Enable bit is already set in the Status
>> Register. If so, the function exits immediately with a successful return
>> code. Otherwise, a message is now printed telling we're setting the
>> non-volatile bit.
>>
>> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
>> Reviewed-by: Jagan Teki <jagan at openedev.com>
>> ---
>>  drivers/mtd/spi-nor/spi-nor.c | 5 +++++
>>  1 file changed, 5 insertions(+)
>>
>> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
>> index d0fc165d7d66..5c87b2d99507 100644
>> --- a/drivers/mtd/spi-nor/spi-nor.c
>> +++ b/drivers/mtd/spi-nor/spi-nor.c
>> @@ -1211,6 +1211,11 @@ static int macronix_quad_enable(struct spi_nor *nor)
>>  	val = read_sr(nor);
>>  	if (val < 0)
>>  		return val;
>> +	if (val & SR_QUAD_EN_MX)
>> +		return 0;
>> +
>> +	/* Update the Quad Enable bit. */
>> +	dev_info(nor->dev, "setting Macronix Quad Enable (non-volatile) bit\n");
> 
> Should probably be dev_dbg(), since this is just churn in the kernel
> log. The user doesn't care and the developer can just up the debug level
> or add his own printk .
>

The Quad Enable bit is non-volatile so this trace should be printed only once
but I'm perfectly fine with using dev_dbg(). I'll change it in the next version.

Best regards,

Cyrille
 
>>  	write_enable(nor);
>>  
>>  	write_sr(nor, val | SR_QUAD_EN_MX);
>>
> 
> 



From jagan at openedev.com  Tue Oct 25 02:08:24 2016
From: jagan at openedev.com (Jagan Teki)
Date: Tue, 25 Oct 2016 14:38:24 +0530
Subject: [PATCH v2 0/9] mtd: spi-nor: parse SFDP tables to setup (Q)SPI
 memories
In-Reply-To: <1181d557-c149-8dfd-7fd1-bc83056541cf@atmel.com>
References: <cover.1475668319.git.cyrille.pitchen@atmel.com>
 <CAD6G_RR4Av8+szo9v2oucCFvwnow86gMVC-Ku_-Qfy18TVMGgA@mail.gmail.com>
 <c022e6fc-6bd7-d124-7233-e1e742049657@denx.de>
 <CAD6G_RQ2BjtF2cmPUJvYNk7KZZ6eTVAQsEqWs26xn710A4Dz-w@mail.gmail.com>
 <558d668a-69b0-8066-b7da-090517d3161d@atmel.com>
 <1181d557-c149-8dfd-7fd1-bc83056541cf@atmel.com>
Message-ID: <CAD6G_RRJUsdPBbbsP_AieAZjRykHN=bk-+RJ7pUuuHWJrgBd8A@mail.gmail.com>

On Mon, Oct 24, 2016 at 7:37 PM, Cyrille Pitchen
<cyrille.pitchen at atmel.com> wrote:
> Le 24/10/2016 ? 14:09, Cyrille Pitchen a ?crit :
>> Hi Jagan,
>>
>> Le 24/10/2016 ? 09:41, Jagan Teki a ?crit :
>>> On Sun, Oct 23, 2016 at 2:03 AM, Marek Vasut <marex at denx.de> wrote:
>>>> On 10/22/2016 01:00 PM, Jagan Teki wrote:
>>>>> On Wed, Oct 5, 2016 at 5:30 PM, Cyrille Pitchen
>>>>> <cyrille.pitchen at atmel.com> wrote:
>>>>>> Hi all,
>>>>>>
>>>>>> This series extends support of SPI protocols to new protocols such as
>>>>>> SPI x-2-2 and SPI x-4-4. Also spi_nor_scan() tries now to select the right
>>>>>> op codes, timing parameters (number of mode and dummy cycles) and erase
>>>>>> sector size by parsing the Serial Flash Discoverable Parameter (SFDP)
>>>>>> tables, when available, as defined in the JEDEC JESD216 specifications.
>>>>>>
>>>>>> When SFDP tables are not available, legacy settings are still used for
>>>>>> backward compatibility (SPI and earlier QSPI memories).
>>>>>>
>>>>>> Support of SPI memories >128Mbits is also improved by using the 4byte
>>>>>> address instruction set, when available. Using those dedicated op codes
>>>>>> is stateless as opposed to enter the 4byte address mode, hence a better
>>>>>> compatibility with some boot loaders which expect to use 3byte address
>>>>>> op codes.
>>>>>
>>>>> The memories which are > 128Mbits should have 4-bytes addressing
>>>>> support based on my experience, do you think BAR is also required
>>>>> atleast from spi-nor side?
>>>>
>>>> Yes, I believe BAR is still required for broken/dumb flash chips.
>>>> Not all chips > 16 MiB support dedicated 4-byte addressing opcodes :-(
>>>
>>> Do you have list for those broken chips? because I never find any
>>> chips which has > 16 MiB with not support of 4-byte address opcodes
>>> and I've seen the controller has dependable with BAR though it can
>>> access > 16MiB ex: zynq qspi/
>>>
>>> thanks!
>>>
>>
>> Let's take the case of Micron n25q256* memories. Depending of the part number,
>> the 12h op code is associated with either 4-byte address Page Program 1-1-1
>> or 3-byte address Page Program 1-4-4.
>> Then considering parts where the 12h op code is used for 3-byte address Page
>> Program 1-4-4, there is no op code for a 4-byte address Page Program 1-1-1.
>>
>> Note 15, extracted from the Micron n25q_256mb_3v_65nm.pdf datasheet, about
>> the 3-byte address Page Program 1-4-4 (Extended Quad Input Fast Program):
>> The code 38h is valid only for part numbers N25Q256A83ESF40x, N25Q256A83E1240x
>> and N25Q256A83ESFA0F; the code 12h is valid for the other part numbers.
>>
>> Hence most of the Micron n25q256* memories has no op code for 4-byte address
>> Page Program 1-1-1.
>> Then we could use the 34h op code instead to perform 4-byte address Page
>> Program 1-1-4 but some SPI controllers might not support the SPI 1-1-4 protocol
>> for Page Program operations. Sp entering the 4-byte address mode or using
>> the BAR might still be the only solutions in those cases.
>>
>> Also, I'm pretty sure some other SPI NOR memories support 4-byte address Fast
>> Read op codes but only 3-byte address op codes for Page Program and Sector
>> Erase. I will look at the datasheets I have to find and provide an example.
>>
>>
>
> Even worse, let's take the example for Macronix MX25L25635* and MX25L25673*:
> they both share the very same JEDEC ID. The older part (35) doesn't support
> the 4-byte address instruction set at all whereas the newer part (73) does.

So, though we have a support of 4-byte opcode, few of the reads will
still way back to use 3-byte opcode is it?
If ie the case may be we can directly rely on 4-byte opcode page
program or reads instead of creating check for which opcode support
which bytes address, IMHO.

thanks!
-- 
Jagan Teki
Free Software Engineer | www.openedev.com
U-Boot, Linux | Upstream Maintainer
Hyderabad, India.


From cyrille.pitchen at atmel.com  Tue Oct 25 02:18:44 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Tue, 25 Oct 2016 11:18:44 +0200
Subject: [PATCH v3 2/9] mtd: spi-nor: add an alternative method to support
 memory >16MiB
In-Reply-To: <6eb07d71-cd1c-fa96-f576-c3ab6a62d246@denx.de>
References: <cover.1477325128.git.cyrille.pitchen@atmel.com>
 <87ace1a307f4d9899a84108de999a2eeb151da1a.1477325128.git.cyrille.pitchen@atmel.com>
 <6eb07d71-cd1c-fa96-f576-c3ab6a62d246@denx.de>
Message-ID: <dbcbf5d3-61cd-844d-c2e3-7e8d83914f97@atmel.com>

Le 25/10/2016 ? 00:10, Marek Vasut a ?crit :
> On 10/24/2016 06:34 PM, Cyrille Pitchen wrote:
>> This patch provides an alternative mean to support memory above 16MiB
>> (128Mib) by replacing 3byte address op codes by their associated 4byte
>> address versions.
>>
>> Using the dedicated 4byte address op codes doesn't change the internal
>> state of the SPI NOR memory as opposed to using other means such as
>> updating a Base Address Register (BAR) and sending command to enter/leave
>> the 4byte mode.
>>
>> Hence when a CPU reset occurs, early bootloaders don't need to be aware
>> of BAR value or 4byte mode being enabled: they can still access the first
>> 16MiB of the SPI NOR memory using the regular 3byte address op codes.
>>
>> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
>> Tested-by: Vignesh R <vigneshr at ti.com>
>> ---
>>  drivers/mtd/devices/serial_flash_cmds.h |   7 ---
>>  drivers/mtd/devices/st_spi_fsm.c        |  28 ++++-----
>>  drivers/mtd/spi-nor/spi-nor.c           | 104 +++++++++++++++++++++++++-------
>>  include/linux/mtd/spi-nor.h             |  22 +++++--
>>  4 files changed, 113 insertions(+), 48 deletions(-)
>>
>> diff --git a/drivers/mtd/devices/serial_flash_cmds.h b/drivers/mtd/devices/serial_flash_cmds.h
>> index f59a125295d0..8b81e15105dd 100644
>> --- a/drivers/mtd/devices/serial_flash_cmds.h
>> +++ b/drivers/mtd/devices/serial_flash_cmds.h
>> @@ -18,19 +18,12 @@
>>  #define SPINOR_OP_RDVCR		0x85
>>  
>>  /* JEDEC Standard - Serial Flash Discoverable Parmeters (SFDP) Commands */
>> -#define SPINOR_OP_READ_1_2_2	0xbb	/* DUAL I/O READ */
>> -#define SPINOR_OP_READ_1_4_4	0xeb	/* QUAD I/O READ */
>> -
>>  #define SPINOR_OP_WRITE		0x02	/* PAGE PROGRAM */
>>  #define SPINOR_OP_WRITE_1_1_2	0xa2	/* DUAL INPUT PROGRAM */
>>  #define SPINOR_OP_WRITE_1_2_2	0xd2	/* DUAL INPUT EXT PROGRAM */
>>  #define SPINOR_OP_WRITE_1_1_4	0x32	/* QUAD INPUT PROGRAM */
>>  #define SPINOR_OP_WRITE_1_4_4	0x12	/* QUAD INPUT EXT PROGRAM */
>>  
>> -/* READ commands with 32-bit addressing */
>> -#define SPINOR_OP_READ4_1_2_2	0xbc
>> -#define SPINOR_OP_READ4_1_4_4	0xec
>> -
> 
> It'd be nice to have this move/rename bit factored out into a separate
> patch.
> 

OK, I will try to do this. Anyway, this rename seems to break the freshly
merged drivers/spi/spi-bcm-qspi.c, which uses the SPINOR_OP_READ4_* macro so
I have to do something about this driver. IMHO, the broadcom driver should not
select its own op code but use the one provided by read_opcode member of the
struct spi_flash_read_message.

>>  /* Configuration flags */
>>  #define FLASH_FLAG_SINGLE	0x000000ff
>>  #define FLASH_FLAG_READ_WRITE	0x00000001
>> diff --git a/drivers/mtd/devices/st_spi_fsm.c b/drivers/mtd/devices/st_spi_fsm.c
>> index 5454b4113589..804313a33f2b 100644
> 
> [...]
> 
>> +static u8 spi_nor_convert_opcode(u8 opcode,
>> +				 const struct spi_nor_address_entry *entries,
>> +				 size_t num_entries)
>> +{
>> +	int min, max;
>> +
>> +	min = 0;
>> +	max = num_entries - 1;
>> +	while (min <= max) {
> 
> It's really not clear at all what this function does, so please add a
> comment.
> 

This is just a dichotomic search to reduce the number of comparisons: it 
assumes the entries[] array is sorted by ascending src_opcode.

I will add a comment to clarify this point.

>> +		int mid = (min + max) >> 1;
>> +		const struct spi_nor_address_entry *entry = &entries[mid];
>> +
>> +		if (opcode == entry->src_opcode)
>> +			return entry->dst_opcode;
>> +
>> +		if (opcode < entry->src_opcode)
>> +			max = mid - 1;
>> +		else
>> +			min = mid + 1;
>> +	}
>> +
>> +	/* No conversion found */
>> +	return opcode;
>> +}
>> +
>> +static u8 spi_nor_3to4_opcode(u8 opcode)
>> +{
>> +	/* MUST be sorted by 3byte opcode */
> 
> Because ... why ?
>

As explained above, the dichotomic search implemented in
spi_nor_convert_opcode() assumes that the input array is sorted by src_opcode.
 
>> +#define ENTRY_3TO4(_opcode)	{ _opcode, _opcode##_4B }
> 
> Will this break/be unflexible for flashes with some different 4B opcodes ?
>

Of course I cannot provide any guarantee that it will never happen but
currently it seems that all manufacturers use the same op codes. Besides, 
the 4-byte address instruction set is part the of JESD216B specification,
so there is a standard for these op codes and new SPI NOR memories tend
to match this specification by providing the SFDP tables.

Indeed this instruction set is maybe one of the few things where all
manufacturers seem to agree :)
 
>> +	static const struct spi_nor_address_entry spi_nor_3to4_table[] = {
>> +		ENTRY_3TO4(SPINOR_OP_PP),		/* 0x02 */
>> +		ENTRY_3TO4(SPINOR_OP_READ),		/* 0x03 */
>> +		ENTRY_3TO4(SPINOR_OP_READ_FAST),	/* 0x0b */
>> +		ENTRY_3TO4(SPINOR_OP_BE_4K),		/* 0x20 */
>> +		ENTRY_3TO4(SPINOR_OP_PP_1_1_4),		/* 0x32 */
>> +		ENTRY_3TO4(SPINOR_OP_PP_1_4_4),		/* 0x38 */
>> +		ENTRY_3TO4(SPINOR_OP_READ_1_1_2),	/* 0x3b */
>> +		ENTRY_3TO4(SPINOR_OP_BE_32K),		/* 0x52 */
>> +		ENTRY_3TO4(SPINOR_OP_READ_1_1_4),	/* 0x6b */
>> +		ENTRY_3TO4(SPINOR_OP_READ_1_2_2),	/* 0xbb */
>> +		ENTRY_3TO4(SPINOR_OP_SE),		/* 0xd8 */
>> +		ENTRY_3TO4(SPINOR_OP_READ_1_4_4),	/* 0xeb */
>> +	};
>> +#undef ENTRY_3TO4
>> +
>> +	return spi_nor_convert_opcode(opcode, spi_nor_3to4_table,
>> +				      ARRAY_SIZE(spi_nor_3to4_table));
>> +}
>> +
> 
> [...]
> 



From cyrille.pitchen at atmel.com  Tue Oct 25 02:39:11 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Tue, 25 Oct 2016 11:39:11 +0200
Subject: [PATCH v3 8/9] mtd: spi-nor: add support to Macronix mx66l1g45g
In-Reply-To: <b043147d-cc39-9238-c6e7-432af67f684e@denx.de>
References: <cover.1477325128.git.cyrille.pitchen@atmel.com>
 <4db277dccf52acd48e592d9f285724aab70704d1.1477325128.git.cyrille.pitchen@atmel.com>
 <b043147d-cc39-9238-c6e7-432af67f684e@denx.de>
Message-ID: <1d74bddb-fcf7-cb0c-5c0f-a86a54c9a033@atmel.com>

Hi Marek,

Le 25/10/2016 ? 00:16, Marek Vasut a ?crit :
> On 10/24/2016 06:34 PM, Cyrille Pitchen wrote:
>> This patch adds an entry in the spi_nor_ids[] table to add support
>> to the Macronix mx66l1g45g.
>>
>> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
>> ---
>>  drivers/mtd/spi-nor/spi-nor.c | 1 +
>>  1 file changed, 1 insertion(+)
>>
>> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
>> index db4874d4af79..eb21d3d4e4e6 100644
>> --- a/drivers/mtd/spi-nor/spi-nor.c
>> +++ b/drivers/mtd/spi-nor/spi-nor.c
>> @@ -937,6 +937,7 @@ static const struct flash_info spi_nor_ids[] = {
>>  	{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
>>  	{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
>>  	{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) },
>> +	{ "mx66l1g45g",  INFO(0xc2201b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
>>  	{ "mx66l1g55g",  INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
>>  
>>  	/* Micron */
>>
> This should be submitted separately as it could be applied right away.
> 

I totally agree with you. Indeed I have only provided patch 8 and 9 because
I refer to these memories in the cover letter and to "prove" that I did really
test every memory of the list. If everyone trust me about the test I do, I
will remove patch 8 and 9 in the next version.

By the way, I need to add a remark about the Spansion S25FL127S. The sample I
have is compliant with neither the JESD216B specification nor the Cypress
datasheet. More precisely, the Cypress datasheet claims that the S25FL127S
is compliant with the JESD216B (minor 6) so its Basic Flash Parameter Table
(BFPT) should contain 16 DWORDS.
However my sample claims to be JESD216B compliant (I read minor 6) and that
the BFPT has 16 DWORDS but the 7 last DWORDS of this table are all 0xFFFFFFFF.
Only the first 9 DWORDS are properly filled, the DWORDS described in JESD216
(minor 0).
Also my sample pretend to provide the optional 4-byte address instruction set
(4BAIS) table but the data I read are once again all 0xFFFFFFFF.

It's surprising that this 128Mbit memory supports the 4-byte address
instruction set but the 4-byte Fast Read actually seems to be supported.

Consequently, Fast Read operations work but Sector Erase cannot due to the
0xFF op code read from the 4BAIS table. I think I just have a broken sample so
if anyone can test with another sample and confirm that the SFDP series also
work with Spansion S25FL127S it would be nice! :)

Best regards,

Cyrille


From marc_gonzalez at sigmadesigns.com  Tue Oct 25 04:30:39 2016
From: marc_gonzalez at sigmadesigns.com (Marc Gonzalez)
Date: Tue, 25 Oct 2016 13:30:39 +0200
Subject: [PATCH v6 4/4] mtd: nand: tango: import driver for tango chips
In-Reply-To: <20161024171026.710d0f6a@bbrezillon>
References: <580E0318.5020004@sigmadesigns.com>
 <580E04B4.7040102@sigmadesigns.com> <20161024171026.710d0f6a@bbrezillon>
Message-ID: <580F425F.8090000@sigmadesigns.com>

Heya :-)

On 24/10/2016 17:10, Boris Brezillon wrote:

> Marc Gonzalez wrote:
> 
>> This driver supports the NAND Flash controller embedded in recent
>> Tango chips, such as SMP8758 and SMP8759.
> 
> A few comments below (most of them are about coding style).

20c25f430311 tweak chip->options
cd1f53e6d2b8 Move ECC init code around
b90efb09a921 Increment ecc_stats.failed on error
2236f67af8d6 move brace for checkpatch
83c1c0311c2a braces in for loop
13faec8fa36b proper braces for if-block
f879bf99d5c3 Move test before DMA write
a2d319b18702 no brackets for readl_poll_timeout
67acc45e26e1 Remove nice alignment
dd71ae037721 fix TIMING macro

Time to squash and send v7, along with the bindings doc.


>> +#define TIMING(t0, t1, t2, t3) (t0 << 24 | t1 << 16 | t2 << 8 | t3 << 0)
> 
> Wrap tX params with parenthesis to make sure the shift operation is
> applied to the correct value (for example, if t0 = a + b, then the
> resulting operation will be a + (b << 24) instead of (a + b) << 24 if
> you don't put those parenthesis).

Fixed.

For the record, addition has higher precedence than shift.
Thus a + b << n = (a + b) << n
But your point is valid for bit-wise operations, e.g.
a & b << n = a & (b << n)

>> +	writel_relaxed(page, nfc->reg_base + NFC_ADDR_PAGE);
>> +	writel_relaxed(   0, nfc->reg_base + NFC_ADDR_OFFSET);
>> +	writel_relaxed( cmd, nfc->reg_base + NFC_FLASH_CMD);
> 
> A vestige of you weird alignment policy ;). Please fix that.

Fixed. Even checkpatch complains...
(Sad puppy face)

Regards.



From marc_gonzalez at sigmadesigns.com  Tue Oct 25 05:29:55 2016
From: marc_gonzalez at sigmadesigns.com (Marc Gonzalez)
Date: Tue, 25 Oct 2016 14:29:55 +0200
Subject: [PATCH] mtd: nand: Fix data interface configuration logic
In-Reply-To: <1477320380-11062-1-git-send-email-boris.brezillon@free-electrons.com>
References: <1477320380-11062-1-git-send-email-boris.brezillon@free-electrons.com>
Message-ID: <580F5043.6060901@sigmadesigns.com>

On 24/10/2016 16:46, Boris Brezillon wrote:

> When changing from one data interface setting to another, one has to
> ensure a specific sequence which is described in the ONFI spec.
> 
> One of these constraints is that the CE line has go high after a reset
> before a command can be sent with the new data interface setting, which
> is not guaranteed by the current implementation.
> 
> Rework the nand_reset() function and all the call sites to make sure the
> CE line is asserted and released when required.
> 
> Also make sure to actually apply the new data interface setting on the
> first die.
> 
> Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
> Fixes: d8e725dd8311 ("mtd: nand: automate NAND timings selection")
> ---
>  drivers/mtd/nand/nand_base.c | 60 +++++++++++++++++++++++++++++++-------------
>  include/linux/mtd/nand.h     |  2 +-
>  2 files changed, 43 insertions(+), 19 deletions(-)

Tested-by: Marc Gonzalez <marc_gonzalez at sigmadesigns.com>

Regards.



From marc_gonzalez at sigmadesigns.com  Tue Oct 25 05:31:47 2016
From: marc_gonzalez at sigmadesigns.com (Marc Gonzalez)
Date: Tue, 25 Oct 2016 14:31:47 +0200
Subject: [PATCH 0/2] mtd: nand: Enforce tCCS wait time after a column
 change
In-Reply-To: <1475310243-32625-1-git-send-email-boris.brezillon@free-electrons.com>
References: <1475310243-32625-1-git-send-email-boris.brezillon@free-electrons.com>
Message-ID: <580F50B3.1070702@sigmadesigns.com>

On 01/10/2016 10:24, Boris Brezillon wrote:

> Marc recently struggled with the RNDIN/RNDOUT commands when trying to
> add support for the Tango NAND controller.
> After some investigation it appeared that nothing in the
> nand_command_lp() code waits tCCS, which is required to make sure the
> NAND chip is ready to receive/send data on the bus after a column
> change.
> 
> This series adds some more timings to the nand_sdr_timings struct
> (including tCCS) and try to extract them from the ONFI parameter table
> (if available).
> 
> It then adds a new flags to ask the core to enforce the tCCS
> constraint.
> As noted in the commit message, this is an opt-in flag to avoid perf
> regressions on existing implementations (adding an ndelay() might be
> useless if the controller IP or driver already takes care of that),
> but it might appear that some implementations are actually broken and
> needs this flag as well.
> 
> Regards,
> 
> Boris
> 
> Boris Brezillon (2):
>   mtd: nand: Add a few more timings to nand_sdr_timings
>   mtd: nand: Wait tCCS after a column change
> 
>  drivers/mtd/nand/nand_base.c    | 26 +++++++++++++++++++++++++-
>  drivers/mtd/nand/nand_timings.c | 26 +++++++++++++++++++++++++-
>  include/linux/mtd/nand.h        | 18 ++++++++++++++++++
>  3 files changed, 68 insertions(+), 2 deletions(-)

Tested-by: Marc Gonzalez <marc_gonzalez at sigmadesigns.com>

Regards.



From marc_gonzalez at sigmadesigns.com  Tue Oct 25 06:15:50 2016
From: marc_gonzalez at sigmadesigns.com (Marc Gonzalez)
Date: Tue, 25 Oct 2016 15:15:50 +0200
Subject: [PATCH v7 1/2] mtd: nand: add tango NFC dt bindings doc
In-Reply-To: <580F5AD2.9020909@sigmadesigns.com>
References: <580F5AD2.9020909@sigmadesigns.com>
Message-ID: <580F5B06.6030608@sigmadesigns.com>

Add the tango NAND Flash Controller dt bindings documentation.

Signed-off-by: Marc Gonzalez <marc_gonzalez at sigmadesigns.com>
---
 Documentation/devicetree/bindings/mtd/tango-nand.txt | 38 ++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/Documentation/devicetree/bindings/mtd/tango-nand.txt b/Documentation/devicetree/bindings/mtd/tango-nand.txt
new file mode 100644
index 000000000000..3cbf95d6595a
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/tango-nand.txt
@@ -0,0 +1,38 @@
+Sigma Designs Tango4 NAND Flash Controller (NFC)
+
+Required properties:
+
+- compatible: "sigma,smp8758-nand"
+- reg: address/size of nfc_reg, nfc_mem, and pbus_reg
+- dmas: reference to the DMA channel used by the controller
+- dma-names: "nfc_sbox"
+- clocks: reference to the system clock
+- #address-cells: <1>
+- #size-cells: <0>
+
+Children nodes represent the available NAND chips.
+See Documentation/devicetree/bindings/mtd/nand.txt for generic bindings.
+
+Example:
+
+	nand: nand at 2c000 {
+		compatible = "sigma,smp8758-nand";
+		reg = <0x2c000 0x30 0x2d000 0x800 0x20000 0x1000>;
+		dmas = <&dma0 3>;
+		dma-names = "nfc_sbox";
+		clocks = <&clkgen SYS_CLK>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		nand at 0 {
+			reg = <0>; /* CS0 */
+			nand-ecc-strength = <14>;
+			nand-ecc-step-size = <1024>;
+		};
+
+		nand at 1 {
+			reg = <1>; /* CS1 */
+			nand-ecc-strength = <14>;
+			nand-ecc-step-size = <1024>;
+		};
+	};
-- 
2.9.0


From marc_gonzalez at sigmadesigns.com  Tue Oct 25 06:14:58 2016
From: marc_gonzalez at sigmadesigns.com (Marc Gonzalez)
Date: Tue, 25 Oct 2016 15:14:58 +0200
Subject: [PATCH v7 0/2] tango NFC support + bindings doc
Message-ID: <580F5AD2.9020909@sigmadesigns.com>

Hello,

This patch series adds support for the NAND Flash controller
on recent Tango chips, along with the bindings documentation.

Marc Gonzalez (2):
  mtd: nand: add tango NFC dt bindings doc
  mtd: nand: add tango NAND flash controller support

 Documentation/devicetree/bindings/mtd/tango-nand.txt |  38 ++
 drivers/mtd/nand/Kconfig                             |   6 +
 drivers/mtd/nand/Makefile                            |   1 +
 drivers/mtd/nand/tango_nand.c                        | 654 +++++++++++++++++++++++++++++
 4 files changed, 699 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/tango-nand.txt
 create mode 100644 drivers/mtd/nand/tango_nand.c

Regards.


From marc_gonzalez at sigmadesigns.com  Tue Oct 25 06:16:39 2016
From: marc_gonzalez at sigmadesigns.com (Marc Gonzalez)
Date: Tue, 25 Oct 2016 15:16:39 +0200
Subject: [PATCH v7 2/2] mtd: nand: add tango NAND flash controller support
In-Reply-To: <580F5AD2.9020909@sigmadesigns.com>
References: <580F5AD2.9020909@sigmadesigns.com>
Message-ID: <580F5B37.5090100@sigmadesigns.com>

This driver supports the NAND Flash controller embedded in recent
Tango chips, such as SMP8758 and SMP8759.

Signed-off-by: Marc Gonzalez <marc_gonzalez at sigmadesigns.com>
---
 drivers/mtd/nand/Kconfig      |   6 +
 drivers/mtd/nand/Makefile     |   1 +
 drivers/mtd/nand/tango_nand.c | 654 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 661 insertions(+)

diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 7b7a887b4709..844ab20a23a4 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -205,6 +205,12 @@ config MTD_NAND_S3C2410_CLKSTOP
 	  when the is NAND chip selected or released, but will save
 	  approximately 5mA of power when there is nothing happening.
 
+config MTD_NAND_TANGO
+	tristate "NAND Flash support for Tango chips"
+	depends on ARCH_TANGO
+	help
+	  Enables the NAND Flash controller on Tango chips.
+
 config MTD_NAND_DISKONCHIP
 	tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation)"
 	depends on HAS_IOMEM
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index cafde6f3d957..4904ad3614fb 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_MTD_NAND_DENALI_DT)	+= denali_dt.o
 obj-$(CONFIG_MTD_NAND_AU1550)		+= au1550nd.o
 obj-$(CONFIG_MTD_NAND_BF5XX)		+= bf5xx_nand.o
 obj-$(CONFIG_MTD_NAND_S3C2410)		+= s3c2410.o
+obj-$(CONFIG_MTD_NAND_TANGO)		+= tango_nand.o
 obj-$(CONFIG_MTD_NAND_DAVINCI)		+= davinci_nand.o
 obj-$(CONFIG_MTD_NAND_DISKONCHIP)	+= diskonchip.o
 obj-$(CONFIG_MTD_NAND_DOCG4)		+= docg4.o
diff --git a/drivers/mtd/nand/tango_nand.c b/drivers/mtd/nand/tango_nand.c
new file mode 100644
index 000000000000..74e39a92771c
--- /dev/null
+++ b/drivers/mtd/nand/tango_nand.c
@@ -0,0 +1,654 @@
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/mtd/nand.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+
+/* Offsets relative to chip->base */
+#define PBUS_CMD	0
+#define PBUS_ADDR	4
+#define PBUS_DATA	8
+
+/* Offsets relative to reg_base */
+#define NFC_STATUS	0x00
+#define NFC_FLASH_CMD	0x04
+#define NFC_DEVICE_CFG	0x08
+#define NFC_TIMING1	0x0c
+#define NFC_TIMING2	0x10
+#define NFC_XFER_CFG	0x14
+#define NFC_PKT_0_CFG	0x18
+#define NFC_PKT_N_CFG	0x1c
+#define NFC_BB_CFG	0x20
+#define NFC_ADDR_PAGE	0x24
+#define NFC_ADDR_OFFSET	0x28
+#define NFC_XFER_STATUS	0x2c
+
+/* NFC_STATUS values */
+#define CMD_READY	BIT(31)
+
+/* NFC_FLASH_CMD values */
+#define NFC_READ	1
+#define NFC_WRITE	2
+
+/* NFC_XFER_STATUS values */
+#define PAGE_IS_EMPTY	BIT(16)
+
+/* Offsets relative to mem_base */
+#define METADATA	0x000
+#define ERROR_REPORT	0x1c0
+
+/*
+ * Error reports are split in two bytes:
+ * byte 0 for the first packet in the page (PKT_0)
+ * byte 1 for other packets in the page (PKT_N, for N > 0)
+ * ERR_COUNT_PKT_N is the max error count over all but the first packet.
+ */
+#define DECODE_OK_PKT_0(v)	(v & BIT(7))
+#define DECODE_OK_PKT_N(v)	(v & BIT(15))
+#define ERR_COUNT_PKT_0(v)	((v >> 0) & 0x3f)
+#define ERR_COUNT_PKT_N(v)	((v >> 8) & 0x3f)
+
+/* Offsets relative to pbus_base */
+#define PBUS_CS_CTRL	0x83c
+#define PBUS_PAD_MODE	0x8f0
+
+/* PBUS_CS_CTRL values */
+#define PBUS_IORDY	BIT(31)
+
+/*
+ * PBUS_PAD_MODE values
+ * In raw mode, the driver communicates directly with the NAND chips.
+ * In NFC mode, the NAND Flash controller manages the communication.
+ * We use NFC mode for read and write; raw mode for everything else.
+ */
+#define MODE_RAW	0
+#define MODE_NFC	BIT(31)
+
+#define METADATA_SIZE	4
+#define BBM_SIZE	6
+#define FIELD_ORDER	15
+
+#define MAX_CS		4
+
+struct tango_nfc {
+	struct nand_hw_control hw;
+	void __iomem *reg_base;
+	void __iomem *mem_base;
+	void __iomem *pbus_base;
+	struct tango_chip *chips[MAX_CS];
+	struct dma_chan *chan;
+	int freq_kHz;
+};
+
+#define to_tango_nfc(ptr) container_of(ptr, struct tango_nfc, hw)
+
+struct tango_chip {
+	struct nand_chip nand_chip;
+	void __iomem *base;
+	u32 timing1;
+	u32 timing2;
+	u32 xfer_cfg;
+	u32 pkt_0_cfg;
+	u32 pkt_n_cfg;
+	u32 bb_cfg;
+};
+
+#define to_tango_chip(ptr) container_of(ptr, struct tango_chip, nand_chip)
+
+#define XFER_CFG(cs, page_count, steps, metadata_size)	\
+	((cs) << 24 | (page_count) << 16 | (steps) << 8 | (metadata_size))
+
+#define PKT_CFG(size, strength) ((size) << 16 | (strength))
+
+#define BB_CFG(bb_offset, bb_size) ((bb_offset) << 16 | (bb_size))
+
+#define TIMING(t0, t1, t2, t3) ((t0) << 24 | (t1) << 16 | (t2) << 8 | (t3))
+
+static void tango_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+{
+	struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+
+	if (ctrl & NAND_CLE)
+		writeb_relaxed(dat, tchip->base + PBUS_CMD);
+
+	if (ctrl & NAND_ALE)
+		writeb_relaxed(dat, tchip->base + PBUS_ADDR);
+}
+
+static int tango_dev_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+
+	return readl_relaxed(nfc->pbus_base + PBUS_CS_CTRL) & PBUS_IORDY;
+}
+
+static uint8_t tango_read_byte(struct mtd_info *mtd)
+{
+	struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+
+	return readb_relaxed(tchip->base + PBUS_DATA);
+}
+
+static void tango_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+
+	ioread8_rep(tchip->base + PBUS_DATA, buf, len);
+}
+
+static void tango_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+	struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+
+	iowrite8_rep(tchip->base + PBUS_DATA, buf, len);
+}
+
+static void tango_select_chip(struct mtd_info *mtd, int idx)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+	struct tango_chip *tchip = to_tango_chip(chip);
+
+	if (idx < 0)
+		return; /* No "chip unselect" function */
+
+	writel_relaxed(tchip->timing1, nfc->reg_base + NFC_TIMING1);
+	writel_relaxed(tchip->timing2, nfc->reg_base + NFC_TIMING2);
+	writel_relaxed(tchip->xfer_cfg, nfc->reg_base + NFC_XFER_CFG);
+	writel_relaxed(tchip->pkt_0_cfg, nfc->reg_base + NFC_PKT_0_CFG);
+	writel_relaxed(tchip->pkt_n_cfg, nfc->reg_base + NFC_PKT_N_CFG);
+	writel_relaxed(tchip->bb_cfg, nfc->reg_base + NFC_BB_CFG);
+}
+
+/*
+ * The controller does not check for bitflips in erased pages,
+ * therefore software must check instead.
+ */
+static int check_erased_page(struct nand_chip *chip, u8 *buf)
+{
+	u8 *meta = chip->oob_poi + BBM_SIZE;
+	u8 *ecc = chip->oob_poi + BBM_SIZE + METADATA_SIZE;
+	const int ecc_size = chip->ecc.bytes;
+	const int pkt_size = chip->ecc.size;
+	int i, res, meta_len, bitflips = 0;
+
+	for (i = 0; i < chip->ecc.steps; ++i) {
+		meta_len = i ? 0 : METADATA_SIZE;
+		res = nand_check_erased_ecc_chunk(buf, pkt_size, ecc, ecc_size,
+				meta, meta_len, chip->ecc.strength);
+		if (res < 0)
+			chip->mtd.ecc_stats.failed++;
+
+		bitflips = max(res, bitflips);
+		buf += pkt_size;
+		ecc += ecc_size;
+	}
+
+	return bitflips;
+}
+
+static int decode_error_report(struct tango_nfc *nfc)
+{
+	u32 status, res;
+
+	status = readl_relaxed(nfc->reg_base + NFC_XFER_STATUS);
+	if (status & PAGE_IS_EMPTY)
+		return 0;
+
+	res = readl_relaxed(nfc->mem_base + ERROR_REPORT);
+
+	if (DECODE_OK_PKT_0(res) && DECODE_OK_PKT_N(res))
+		return max(ERR_COUNT_PKT_0(res), ERR_COUNT_PKT_N(res));
+
+	return -EBADMSG;
+}
+
+static void tango_dma_callback(void *arg)
+{
+	complete(arg);
+}
+
+static int do_dma(struct tango_nfc *nfc, int dir, int cmd,
+		const void *buf, int len, int page)
+{
+	void __iomem *addr = nfc->reg_base + NFC_STATUS;
+	struct dma_chan *chan = nfc->chan;
+	struct dma_async_tx_descriptor *desc;
+	struct scatterlist sg;
+	struct completion tx_done;
+	int err = -EIO;
+	u32 res, val;
+
+	sg_init_one(&sg, buf, len);
+	if (dma_map_sg(chan->device->dev, &sg, 1, dir) != 1)
+		return -EIO;
+
+	desc = dmaengine_prep_slave_sg(chan, &sg, 1, dir, DMA_PREP_INTERRUPT);
+	if (!desc)
+		goto dma_unmap;
+
+	desc->callback = tango_dma_callback;
+	desc->callback_param = &tx_done;
+	init_completion(&tx_done);
+
+	writel_relaxed(MODE_NFC, nfc->pbus_base + PBUS_PAD_MODE);
+
+	writel_relaxed(page, nfc->reg_base + NFC_ADDR_PAGE);
+	writel_relaxed(0, nfc->reg_base + NFC_ADDR_OFFSET);
+	writel_relaxed(cmd, nfc->reg_base + NFC_FLASH_CMD);
+
+	dmaengine_submit(desc);
+	dma_async_issue_pending(chan);
+
+	res = wait_for_completion_timeout(&tx_done, HZ);
+	if (res > 0)
+		err = readl_poll_timeout(addr, val, val & CMD_READY, 0, 1000);
+
+	writel_relaxed(MODE_RAW, nfc->pbus_base + PBUS_PAD_MODE);
+
+dma_unmap:
+	dma_unmap_sg(chan->device->dev, &sg, 1, dir);
+
+	return err;
+}
+
+static int tango_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+		uint8_t *buf, int oob_required, int page)
+{
+	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+	int err, res, len = mtd->writesize;
+
+	if (oob_required)
+		chip->ecc.read_oob(mtd, chip, page);
+
+	err = do_dma(nfc, DMA_FROM_DEVICE, NFC_READ, buf, len, page);
+	if (err)
+		return err;
+
+	res = decode_error_report(nfc);
+	if (res < 0) {
+		chip->ecc.read_oob_raw(mtd, chip, page);
+		res = check_erased_page(chip, buf);
+	}
+
+	return res;
+}
+
+static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+		const uint8_t *buf, int oob_required, int page)
+{
+	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+	int err, len = mtd->writesize;
+
+	/* Calling tango_write_oob() would send PAGEPROG twice */
+	if (oob_required)
+		return -ENOTSUPP;
+
+	writel_relaxed(0xffffffff, nfc->mem_base + METADATA);
+	err = do_dma(nfc, DMA_TO_DEVICE, NFC_WRITE, buf, len, page);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos)
+{
+	*pos += len;
+
+	if (*buf == NULL) {
+		/* skip over "len" bytes */
+		chip->cmdfunc(&chip->mtd, NAND_CMD_RNDOUT, *pos, -1);
+	} else {
+		tango_read_buf(&chip->mtd, *buf, len);
+		*buf += len;
+	}
+}
+
+static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos)
+{
+	*pos += len;
+
+	if (*buf == NULL) {
+		/* skip over "len" bytes */
+		chip->cmdfunc(&chip->mtd, NAND_CMD_SEQIN, *pos, -1);
+	} else {
+		tango_write_buf(&chip->mtd, *buf, len);
+		*buf += len;
+	}
+}
+
+/*
+ * Physical page layout (not drawn to scale)
+ *
+ * NB: Bad Block Marker area splits PKT_N in two (N1, N2).
+ *
+ * +---+-----------------+-------+-----+-----------+-----+----+-------+
+ * | M |      PKT_0      | ECC_0 | ... |     N1    | BBM | N2 | ECC_N |
+ * +---+-----------------+-------+-----+-----------+-----+----+-------+
+ *
+ * Logical page layout:
+ *
+ *       +-----+---+-------+-----+-------+
+ * oob = | BBM | M | ECC_0 | ... | ECC_N |
+ *       +-----+---+-------+-----+-------+
+ *
+ *       +-----------------+-----+-----------------+
+ * buf = |      PKT_0      | ... |      PKT_N      |
+ *       +-----------------+-----+-----------------+
+ */
+static int raw_read(struct nand_chip *chip, u8 *buf, u8 *oob)
+{
+	u8 *oob_orig = oob;
+	const int page_size = chip->mtd.writesize;
+	const int ecc_size = chip->ecc.bytes;
+	const int pkt_size = chip->ecc.size;
+	int pos = 0; /* position within physical page */
+	int rem = page_size; /* bytes remaining until BBM area */
+
+	if (oob != NULL)
+		oob += BBM_SIZE;
+
+	aux_read(chip, &oob, METADATA_SIZE, &pos);
+
+	while (rem > pkt_size) {
+		aux_read(chip, &buf, pkt_size, &pos);
+		aux_read(chip, &oob, ecc_size, &pos);
+		rem = page_size - pos;
+	}
+
+	aux_read(chip, &buf, rem, &pos);
+	aux_read(chip, &oob_orig, BBM_SIZE, &pos);
+	aux_read(chip, &buf, pkt_size - rem, &pos);
+	aux_read(chip, &oob, ecc_size, &pos);
+
+	return 0;
+}
+
+static int raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob)
+{
+	const u8 *oob_orig = oob;
+	const int page_size = chip->mtd.writesize;
+	const int ecc_size = chip->ecc.bytes;
+	const int pkt_size = chip->ecc.size;
+	int pos = 0; /* position within physical page */
+	int rem = page_size; /* bytes remaining until BBM area */
+
+	if (oob != NULL)
+		oob += BBM_SIZE;
+
+	aux_write(chip, &oob, METADATA_SIZE, &pos);
+
+	while (rem > pkt_size) {
+		aux_write(chip, &buf, pkt_size, &pos);
+		aux_write(chip, &oob, ecc_size, &pos);
+		rem = page_size - pos;
+	}
+
+	aux_write(chip, &buf, rem, &pos);
+	aux_write(chip, &oob_orig, BBM_SIZE, &pos);
+	aux_write(chip, &buf, pkt_size - rem, &pos);
+	aux_write(chip, &oob, ecc_size, &pos);
+
+	return 0;
+}
+
+static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+		uint8_t *buf, int oob_required, int page)
+{
+	return raw_read(chip, buf, chip->oob_poi);
+}
+
+static int tango_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+		const uint8_t *buf, int oob_required, int page)
+{
+	return raw_write(chip, buf, chip->oob_poi);
+}
+
+static int tango_read_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
+{
+	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+	return raw_read(chip, NULL, chip->oob_poi);
+}
+
+static int tango_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
+{
+	chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page);
+	raw_write(chip, NULL, chip->oob_poi);
+	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+	chip->waitfunc(mtd, chip);
+	return 0;
+}
+
+static int oob_ecc(struct mtd_info *mtd, int idx, struct mtd_oob_region *res)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+	if (idx >= ecc->steps)
+		return -ERANGE;
+
+	res->offset = BBM_SIZE + METADATA_SIZE + ecc->bytes * idx;
+	res->length = ecc->bytes;
+
+	return 0;
+}
+
+static int oob_free(struct mtd_info *mtd, int idx, struct mtd_oob_region *res)
+{
+	return -ERANGE; /* no free space in spare area */
+}
+
+static const struct mtd_ooblayout_ops tango_nand_ooblayout_ops = {
+	.ecc	= oob_ecc,
+	.free	= oob_free,
+};
+
+static u32 to_ticks(int kHz, int ps)
+{
+	return DIV_ROUND_UP_ULL((u64)kHz * ps, NSEC_PER_SEC);
+}
+
+static int tango_set_timings(struct mtd_info *mtd,
+		const struct nand_data_interface *conf, bool check_only)
+{
+	const struct nand_sdr_timings *sdr = nand_get_sdr_timings(conf);
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+	struct tango_chip *tchip = to_tango_chip(chip);
+	u32 Trdy, Textw, Twc, Twpw, Tacc, Thold, Trpw, Textr;
+	int kHz = nfc->freq_kHz;
+
+	if (IS_ERR(sdr))
+		return PTR_ERR(sdr);
+
+	if (check_only)
+		return 0;
+
+	Trdy = to_ticks(kHz, sdr->tCEA_max - sdr->tREA_max);
+	Textw = to_ticks(kHz, sdr->tWB_max);
+	Twc = to_ticks(kHz, sdr->tWC_min);
+	Twpw = to_ticks(kHz, sdr->tWC_min - sdr->tWP_min);
+
+	Tacc = to_ticks(kHz, sdr->tREA_max);
+	Thold = to_ticks(kHz, sdr->tREH_min);
+	Trpw = to_ticks(kHz, sdr->tRC_min - sdr->tREH_min);
+	Textr = to_ticks(kHz, sdr->tRHZ_max);
+
+	tchip->timing1 = TIMING(Trdy, Textw, Twc, Twpw);
+	tchip->timing2 = TIMING(Tacc, Thold, Trpw, Textr);
+
+	return 0;
+}
+
+static int chip_init(struct device *dev, struct device_node *np)
+{
+	u32 cs;
+	int err, res;
+	struct mtd_info *mtd;
+	struct nand_chip *chip;
+	struct tango_chip *tchip;
+	struct nand_ecc_ctrl *ecc;
+	struct tango_nfc *nfc = dev_get_drvdata(dev);
+
+	tchip = devm_kzalloc(dev, sizeof(*tchip), GFP_KERNEL);
+	if (!tchip)
+		return -ENOMEM;
+
+	res = of_property_count_u32_elems(np, "reg");
+	if (res < 0)
+		return res;
+
+	if (res != 1)
+		return -ENOTSUPP; /* Multi-CS chips are not supported */
+
+	err = of_property_read_u32_index(np, "reg", 0, &cs);
+	if (err)
+		return err;
+
+	if (cs >= MAX_CS)
+		return -EINVAL;
+
+	chip = &tchip->nand_chip;
+	ecc = &chip->ecc;
+	mtd = &chip->mtd;
+
+	chip->read_byte = tango_read_byte;
+	chip->write_buf = tango_write_buf;
+	chip->read_buf = tango_read_buf;
+	chip->select_chip = tango_select_chip;
+	chip->cmd_ctrl = tango_cmd_ctrl;
+	chip->dev_ready = tango_dev_ready;
+	chip->setup_data_interface = tango_set_timings;
+	chip->options = NAND_USE_BOUNCE_BUFFER
+		| NAND_NO_SUBPAGE_WRITE
+		| NAND_WAIT_TCCS;
+	chip->controller = &nfc->hw;
+	tchip->base = nfc->pbus_base + (cs * 256);
+
+	nand_set_flash_node(chip, np);
+	mtd_set_ooblayout(mtd, &tango_nand_ooblayout_ops);
+	mtd->dev.parent = dev;
+
+	err = nand_scan_ident(mtd, 1, NULL);
+	if (err)
+		return err;
+
+	ecc->mode = NAND_ECC_HW;
+	ecc->algo = NAND_ECC_BCH;
+	ecc->bytes = DIV_ROUND_UP(ecc->strength * FIELD_ORDER, BITS_PER_BYTE);
+
+	ecc->read_page_raw = tango_read_page_raw;
+	ecc->write_page_raw = tango_write_page_raw;
+	ecc->read_page = tango_read_page;
+	ecc->write_page = tango_write_page;
+	ecc->read_oob = tango_read_oob;
+	ecc->write_oob = tango_write_oob;
+
+	err = nand_scan_tail(mtd);
+	if (err)
+		return err;
+
+	tchip->xfer_cfg = XFER_CFG(cs, 1, ecc->steps, METADATA_SIZE);
+	tchip->pkt_0_cfg = PKT_CFG(ecc->size + METADATA_SIZE, ecc->strength);
+	tchip->pkt_n_cfg = PKT_CFG(ecc->size, ecc->strength);
+	tchip->bb_cfg = BB_CFG(mtd->writesize, BBM_SIZE);
+
+	err = mtd_device_register(mtd, NULL, 0);
+	if (err)
+		return err;
+
+	nfc->chips[cs] = tchip;
+
+	return 0;
+}
+
+static int tango_nand_remove(struct platform_device *pdev)
+{
+	int cs;
+	struct tango_nfc *nfc = platform_get_drvdata(pdev);
+
+	dma_release_channel(nfc->chan);
+
+	for (cs = 0; cs < MAX_CS; ++cs) {
+		if (nfc->chips[cs] != NULL)
+			nand_release(&nfc->chips[cs]->nand_chip.mtd);
+	}
+
+	return 0;
+}
+
+static int tango_nand_probe(struct platform_device *pdev)
+{
+	int err;
+	struct clk *clk;
+	struct resource *res;
+	struct tango_nfc *nfc;
+	struct device_node *np;
+
+	nfc = devm_kzalloc(&pdev->dev, sizeof(*nfc), GFP_KERNEL);
+	if (!nfc)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	nfc->reg_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(nfc->reg_base))
+		return PTR_ERR(nfc->reg_base);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	nfc->mem_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(nfc->mem_base))
+		return PTR_ERR(nfc->mem_base);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	nfc->pbus_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(nfc->pbus_base))
+		return PTR_ERR(nfc->pbus_base);
+
+	clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	nfc->chan = dma_request_chan(&pdev->dev, "nfc_sbox");
+	if (IS_ERR(nfc->chan))
+		return PTR_ERR(nfc->chan);
+
+	platform_set_drvdata(pdev, nfc);
+	nand_hw_control_init(&nfc->hw);
+	nfc->freq_kHz = clk_get_rate(clk) / 1000;
+
+	for_each_child_of_node(pdev->dev.of_node, np) {
+		err = chip_init(&pdev->dev, np);
+		if (err) {
+			tango_nand_remove(pdev);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+static const struct of_device_id tango_nand_ids[] = {
+	{ .compatible = "sigma,smp8758-nand" },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver tango_nand_driver = {
+	.probe	= tango_nand_probe,
+	.remove	= tango_nand_remove,
+	.driver	= {
+		.name		= "tango-nand",
+		.of_match_table	= tango_nand_ids,
+	},
+};
+
+module_platform_driver(tango_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sigma Designs");
+MODULE_DESCRIPTION("Tango4 NAND Flash controller driver");
-- 
2.9.0


From boris.brezillon at free-electrons.com  Tue Oct 25 06:25:57 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Tue, 25 Oct 2016 15:25:57 +0200
Subject: [PATCH v7 1/2] mtd: nand: add tango NFC dt bindings doc
In-Reply-To: <580F5B06.6030608@sigmadesigns.com>
References: <580F5AD2.9020909@sigmadesigns.com>
 <580F5B06.6030608@sigmadesigns.com>
Message-ID: <20161025152557.15006ca7@bbrezillon>

On Tue, 25 Oct 2016 15:15:50 +0200
Marc Gonzalez <marc_gonzalez at sigmadesigns.com> wrote:

> Add the tango NAND Flash Controller dt bindings documentation.
> 
> Signed-off-by: Marc Gonzalez <marc_gonzalez at sigmadesigns.com>
> ---
>  Documentation/devicetree/bindings/mtd/tango-nand.txt | 38 ++++++++++++++++++++++++++++++
>  1 file changed, 38 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/mtd/tango-nand.txt b/Documentation/devicetree/bindings/mtd/tango-nand.txt
> new file mode 100644
> index 000000000000..3cbf95d6595a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mtd/tango-nand.txt
> @@ -0,0 +1,38 @@
> +Sigma Designs Tango4 NAND Flash Controller (NFC)
> +
> +Required properties:
> +
> +- compatible: "sigma,smp8758-nand"
> +- reg: address/size of nfc_reg, nfc_mem, and pbus_reg
> +- dmas: reference to the DMA channel used by the controller
> +- dma-names: "nfc_sbox"
> +- clocks: reference to the system clock
> +- #address-cells: <1>
> +- #size-cells: <0>
> +
> +Children nodes represent the available NAND chips.
> +See Documentation/devicetree/bindings/mtd/nand.txt for generic bindings.
> +
> +Example:
> +
> +	nand: nand at 2c000 {

	nandc: nand-controller at 2c000 {

No need to resend a new version for that (I can fix it when applying),
unless I find other things in patch 2.

> +		compatible = "sigma,smp8758-nand";
> +		reg = <0x2c000 0x30 0x2d000 0x800 0x20000 0x1000>;
> +		dmas = <&dma0 3>;
> +		dma-names = "nfc_sbox";
> +		clocks = <&clkgen SYS_CLK>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		nand at 0 {
> +			reg = <0>; /* CS0 */
> +			nand-ecc-strength = <14>;
> +			nand-ecc-step-size = <1024>;
> +		};
> +
> +		nand at 1 {
> +			reg = <1>; /* CS1 */
> +			nand-ecc-strength = <14>;
> +			nand-ecc-step-size = <1024>;
> +		};
> +	};



From marc_gonzalez at sigmadesigns.com  Tue Oct 25 09:10:47 2016
From: marc_gonzalez at sigmadesigns.com (Marc Gonzalez)
Date: Tue, 25 Oct 2016 18:10:47 +0200
Subject: [PATCH v8] mtd: nand: add tango NAND flash controller support
In-Reply-To: <580F5B37.5090100@sigmadesigns.com>
References: <580F5AD2.9020909@sigmadesigns.com>
 <580F5B37.5090100@sigmadesigns.com>
Message-ID: <580F8407.5070706@sigmadesigns.com>

This driver supports the NAND Flash controller embedded in recent
Tango chips, such as SMP8758 and SMP8759.

Signed-off-by: Marc Gonzalez <marc_gonzalez at sigmadesigns.com>
---
 drivers/mtd/nand/Kconfig      |   7 +
 drivers/mtd/nand/Makefile     |   1 +
 drivers/mtd/nand/tango_nand.c | 654 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 662 insertions(+)
 create mode 100644 drivers/mtd/nand/tango_nand.c

diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 7b7a887b4709..84ce3fe6e5e2 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -205,6 +205,13 @@ config MTD_NAND_S3C2410_CLKSTOP
 	  when the is NAND chip selected or released, but will save
 	  approximately 5mA of power when there is nothing happening.
 
+config MTD_NAND_TANGO
+	tristate "NAND Flash support for Tango chips"
+	depends on ARCH_TANGO || COMPILE_TEST
+	depends on HAS_DMA
+	help
+	  Enables the NAND Flash controller on Tango chips.
+
 config MTD_NAND_DISKONCHIP
 	tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation)"
 	depends on HAS_IOMEM
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index cafde6f3d957..4904ad3614fb 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_MTD_NAND_DENALI_DT)	+= denali_dt.o
 obj-$(CONFIG_MTD_NAND_AU1550)		+= au1550nd.o
 obj-$(CONFIG_MTD_NAND_BF5XX)		+= bf5xx_nand.o
 obj-$(CONFIG_MTD_NAND_S3C2410)		+= s3c2410.o
+obj-$(CONFIG_MTD_NAND_TANGO)		+= tango_nand.o
 obj-$(CONFIG_MTD_NAND_DAVINCI)		+= davinci_nand.o
 obj-$(CONFIG_MTD_NAND_DISKONCHIP)	+= diskonchip.o
 obj-$(CONFIG_MTD_NAND_DOCG4)		+= docg4.o
diff --git a/drivers/mtd/nand/tango_nand.c b/drivers/mtd/nand/tango_nand.c
new file mode 100644
index 000000000000..74e39a92771c
--- /dev/null
+++ b/drivers/mtd/nand/tango_nand.c
@@ -0,0 +1,654 @@
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/mtd/nand.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+
+/* Offsets relative to chip->base */
+#define PBUS_CMD	0
+#define PBUS_ADDR	4
+#define PBUS_DATA	8
+
+/* Offsets relative to reg_base */
+#define NFC_STATUS	0x00
+#define NFC_FLASH_CMD	0x04
+#define NFC_DEVICE_CFG	0x08
+#define NFC_TIMING1	0x0c
+#define NFC_TIMING2	0x10
+#define NFC_XFER_CFG	0x14
+#define NFC_PKT_0_CFG	0x18
+#define NFC_PKT_N_CFG	0x1c
+#define NFC_BB_CFG	0x20
+#define NFC_ADDR_PAGE	0x24
+#define NFC_ADDR_OFFSET	0x28
+#define NFC_XFER_STATUS	0x2c
+
+/* NFC_STATUS values */
+#define CMD_READY	BIT(31)
+
+/* NFC_FLASH_CMD values */
+#define NFC_READ	1
+#define NFC_WRITE	2
+
+/* NFC_XFER_STATUS values */
+#define PAGE_IS_EMPTY	BIT(16)
+
+/* Offsets relative to mem_base */
+#define METADATA	0x000
+#define ERROR_REPORT	0x1c0
+
+/*
+ * Error reports are split in two bytes:
+ * byte 0 for the first packet in the page (PKT_0)
+ * byte 1 for other packets in the page (PKT_N, for N > 0)
+ * ERR_COUNT_PKT_N is the max error count over all but the first packet.
+ */
+#define DECODE_OK_PKT_0(v)	(v & BIT(7))
+#define DECODE_OK_PKT_N(v)	(v & BIT(15))
+#define ERR_COUNT_PKT_0(v)	((v >> 0) & 0x3f)
+#define ERR_COUNT_PKT_N(v)	((v >> 8) & 0x3f)
+
+/* Offsets relative to pbus_base */
+#define PBUS_CS_CTRL	0x83c
+#define PBUS_PAD_MODE	0x8f0
+
+/* PBUS_CS_CTRL values */
+#define PBUS_IORDY	BIT(31)
+
+/*
+ * PBUS_PAD_MODE values
+ * In raw mode, the driver communicates directly with the NAND chips.
+ * In NFC mode, the NAND Flash controller manages the communication.
+ * We use NFC mode for read and write; raw mode for everything else.
+ */
+#define MODE_RAW	0
+#define MODE_NFC	BIT(31)
+
+#define METADATA_SIZE	4
+#define BBM_SIZE	6
+#define FIELD_ORDER	15
+
+#define MAX_CS		4
+
+struct tango_nfc {
+	struct nand_hw_control hw;
+	void __iomem *reg_base;
+	void __iomem *mem_base;
+	void __iomem *pbus_base;
+	struct tango_chip *chips[MAX_CS];
+	struct dma_chan *chan;
+	int freq_kHz;
+};
+
+#define to_tango_nfc(ptr) container_of(ptr, struct tango_nfc, hw)
+
+struct tango_chip {
+	struct nand_chip nand_chip;
+	void __iomem *base;
+	u32 timing1;
+	u32 timing2;
+	u32 xfer_cfg;
+	u32 pkt_0_cfg;
+	u32 pkt_n_cfg;
+	u32 bb_cfg;
+};
+
+#define to_tango_chip(ptr) container_of(ptr, struct tango_chip, nand_chip)
+
+#define XFER_CFG(cs, page_count, steps, metadata_size)	\
+	((cs) << 24 | (page_count) << 16 | (steps) << 8 | (metadata_size))
+
+#define PKT_CFG(size, strength) ((size) << 16 | (strength))
+
+#define BB_CFG(bb_offset, bb_size) ((bb_offset) << 16 | (bb_size))
+
+#define TIMING(t0, t1, t2, t3) ((t0) << 24 | (t1) << 16 | (t2) << 8 | (t3))
+
+static void tango_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+{
+	struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+
+	if (ctrl & NAND_CLE)
+		writeb_relaxed(dat, tchip->base + PBUS_CMD);
+
+	if (ctrl & NAND_ALE)
+		writeb_relaxed(dat, tchip->base + PBUS_ADDR);
+}
+
+static int tango_dev_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+
+	return readl_relaxed(nfc->pbus_base + PBUS_CS_CTRL) & PBUS_IORDY;
+}
+
+static uint8_t tango_read_byte(struct mtd_info *mtd)
+{
+	struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+
+	return readb_relaxed(tchip->base + PBUS_DATA);
+}
+
+static void tango_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+
+	ioread8_rep(tchip->base + PBUS_DATA, buf, len);
+}
+
+static void tango_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+	struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+
+	iowrite8_rep(tchip->base + PBUS_DATA, buf, len);
+}
+
+static void tango_select_chip(struct mtd_info *mtd, int idx)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+	struct tango_chip *tchip = to_tango_chip(chip);
+
+	if (idx < 0)
+		return; /* No "chip unselect" function */
+
+	writel_relaxed(tchip->timing1, nfc->reg_base + NFC_TIMING1);
+	writel_relaxed(tchip->timing2, nfc->reg_base + NFC_TIMING2);
+	writel_relaxed(tchip->xfer_cfg, nfc->reg_base + NFC_XFER_CFG);
+	writel_relaxed(tchip->pkt_0_cfg, nfc->reg_base + NFC_PKT_0_CFG);
+	writel_relaxed(tchip->pkt_n_cfg, nfc->reg_base + NFC_PKT_N_CFG);
+	writel_relaxed(tchip->bb_cfg, nfc->reg_base + NFC_BB_CFG);
+}
+
+/*
+ * The controller does not check for bitflips in erased pages,
+ * therefore software must check instead.
+ */
+static int check_erased_page(struct nand_chip *chip, u8 *buf)
+{
+	u8 *meta = chip->oob_poi + BBM_SIZE;
+	u8 *ecc = chip->oob_poi + BBM_SIZE + METADATA_SIZE;
+	const int ecc_size = chip->ecc.bytes;
+	const int pkt_size = chip->ecc.size;
+	int i, res, meta_len, bitflips = 0;
+
+	for (i = 0; i < chip->ecc.steps; ++i) {
+		meta_len = i ? 0 : METADATA_SIZE;
+		res = nand_check_erased_ecc_chunk(buf, pkt_size, ecc, ecc_size,
+				meta, meta_len, chip->ecc.strength);
+		if (res < 0)
+			chip->mtd.ecc_stats.failed++;
+
+		bitflips = max(res, bitflips);
+		buf += pkt_size;
+		ecc += ecc_size;
+	}
+
+	return bitflips;
+}
+
+static int decode_error_report(struct tango_nfc *nfc)
+{
+	u32 status, res;
+
+	status = readl_relaxed(nfc->reg_base + NFC_XFER_STATUS);
+	if (status & PAGE_IS_EMPTY)
+		return 0;
+
+	res = readl_relaxed(nfc->mem_base + ERROR_REPORT);
+
+	if (DECODE_OK_PKT_0(res) && DECODE_OK_PKT_N(res))
+		return max(ERR_COUNT_PKT_0(res), ERR_COUNT_PKT_N(res));
+
+	return -EBADMSG;
+}
+
+static void tango_dma_callback(void *arg)
+{
+	complete(arg);
+}
+
+static int do_dma(struct tango_nfc *nfc, int dir, int cmd,
+		const void *buf, int len, int page)
+{
+	void __iomem *addr = nfc->reg_base + NFC_STATUS;
+	struct dma_chan *chan = nfc->chan;
+	struct dma_async_tx_descriptor *desc;
+	struct scatterlist sg;
+	struct completion tx_done;
+	int err = -EIO;
+	u32 res, val;
+
+	sg_init_one(&sg, buf, len);
+	if (dma_map_sg(chan->device->dev, &sg, 1, dir) != 1)
+		return -EIO;
+
+	desc = dmaengine_prep_slave_sg(chan, &sg, 1, dir, DMA_PREP_INTERRUPT);
+	if (!desc)
+		goto dma_unmap;
+
+	desc->callback = tango_dma_callback;
+	desc->callback_param = &tx_done;
+	init_completion(&tx_done);
+
+	writel_relaxed(MODE_NFC, nfc->pbus_base + PBUS_PAD_MODE);
+
+	writel_relaxed(page, nfc->reg_base + NFC_ADDR_PAGE);
+	writel_relaxed(0, nfc->reg_base + NFC_ADDR_OFFSET);
+	writel_relaxed(cmd, nfc->reg_base + NFC_FLASH_CMD);
+
+	dmaengine_submit(desc);
+	dma_async_issue_pending(chan);
+
+	res = wait_for_completion_timeout(&tx_done, HZ);
+	if (res > 0)
+		err = readl_poll_timeout(addr, val, val & CMD_READY, 0, 1000);
+
+	writel_relaxed(MODE_RAW, nfc->pbus_base + PBUS_PAD_MODE);
+
+dma_unmap:
+	dma_unmap_sg(chan->device->dev, &sg, 1, dir);
+
+	return err;
+}
+
+static int tango_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+		uint8_t *buf, int oob_required, int page)
+{
+	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+	int err, res, len = mtd->writesize;
+
+	if (oob_required)
+		chip->ecc.read_oob(mtd, chip, page);
+
+	err = do_dma(nfc, DMA_FROM_DEVICE, NFC_READ, buf, len, page);
+	if (err)
+		return err;
+
+	res = decode_error_report(nfc);
+	if (res < 0) {
+		chip->ecc.read_oob_raw(mtd, chip, page);
+		res = check_erased_page(chip, buf);
+	}
+
+	return res;
+}
+
+static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+		const uint8_t *buf, int oob_required, int page)
+{
+	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+	int err, len = mtd->writesize;
+
+	/* Calling tango_write_oob() would send PAGEPROG twice */
+	if (oob_required)
+		return -ENOTSUPP;
+
+	writel_relaxed(0xffffffff, nfc->mem_base + METADATA);
+	err = do_dma(nfc, DMA_TO_DEVICE, NFC_WRITE, buf, len, page);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos)
+{
+	*pos += len;
+
+	if (*buf == NULL) {
+		/* skip over "len" bytes */
+		chip->cmdfunc(&chip->mtd, NAND_CMD_RNDOUT, *pos, -1);
+	} else {
+		tango_read_buf(&chip->mtd, *buf, len);
+		*buf += len;
+	}
+}
+
+static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos)
+{
+	*pos += len;
+
+	if (*buf == NULL) {
+		/* skip over "len" bytes */
+		chip->cmdfunc(&chip->mtd, NAND_CMD_SEQIN, *pos, -1);
+	} else {
+		tango_write_buf(&chip->mtd, *buf, len);
+		*buf += len;
+	}
+}
+
+/*
+ * Physical page layout (not drawn to scale)
+ *
+ * NB: Bad Block Marker area splits PKT_N in two (N1, N2).
+ *
+ * +---+-----------------+-------+-----+-----------+-----+----+-------+
+ * | M |      PKT_0      | ECC_0 | ... |     N1    | BBM | N2 | ECC_N |
+ * +---+-----------------+-------+-----+-----------+-----+----+-------+
+ *
+ * Logical page layout:
+ *
+ *       +-----+---+-------+-----+-------+
+ * oob = | BBM | M | ECC_0 | ... | ECC_N |
+ *       +-----+---+-------+-----+-------+
+ *
+ *       +-----------------+-----+-----------------+
+ * buf = |      PKT_0      | ... |      PKT_N      |
+ *       +-----------------+-----+-----------------+
+ */
+static int raw_read(struct nand_chip *chip, u8 *buf, u8 *oob)
+{
+	u8 *oob_orig = oob;
+	const int page_size = chip->mtd.writesize;
+	const int ecc_size = chip->ecc.bytes;
+	const int pkt_size = chip->ecc.size;
+	int pos = 0; /* position within physical page */
+	int rem = page_size; /* bytes remaining until BBM area */
+
+	if (oob != NULL)
+		oob += BBM_SIZE;
+
+	aux_read(chip, &oob, METADATA_SIZE, &pos);
+
+	while (rem > pkt_size) {
+		aux_read(chip, &buf, pkt_size, &pos);
+		aux_read(chip, &oob, ecc_size, &pos);
+		rem = page_size - pos;
+	}
+
+	aux_read(chip, &buf, rem, &pos);
+	aux_read(chip, &oob_orig, BBM_SIZE, &pos);
+	aux_read(chip, &buf, pkt_size - rem, &pos);
+	aux_read(chip, &oob, ecc_size, &pos);
+
+	return 0;
+}
+
+static int raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob)
+{
+	const u8 *oob_orig = oob;
+	const int page_size = chip->mtd.writesize;
+	const int ecc_size = chip->ecc.bytes;
+	const int pkt_size = chip->ecc.size;
+	int pos = 0; /* position within physical page */
+	int rem = page_size; /* bytes remaining until BBM area */
+
+	if (oob != NULL)
+		oob += BBM_SIZE;
+
+	aux_write(chip, &oob, METADATA_SIZE, &pos);
+
+	while (rem > pkt_size) {
+		aux_write(chip, &buf, pkt_size, &pos);
+		aux_write(chip, &oob, ecc_size, &pos);
+		rem = page_size - pos;
+	}
+
+	aux_write(chip, &buf, rem, &pos);
+	aux_write(chip, &oob_orig, BBM_SIZE, &pos);
+	aux_write(chip, &buf, pkt_size - rem, &pos);
+	aux_write(chip, &oob, ecc_size, &pos);
+
+	return 0;
+}
+
+static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+		uint8_t *buf, int oob_required, int page)
+{
+	return raw_read(chip, buf, chip->oob_poi);
+}
+
+static int tango_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+		const uint8_t *buf, int oob_required, int page)
+{
+	return raw_write(chip, buf, chip->oob_poi);
+}
+
+static int tango_read_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
+{
+	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+	return raw_read(chip, NULL, chip->oob_poi);
+}
+
+static int tango_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
+{
+	chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page);
+	raw_write(chip, NULL, chip->oob_poi);
+	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+	chip->waitfunc(mtd, chip);
+	return 0;
+}
+
+static int oob_ecc(struct mtd_info *mtd, int idx, struct mtd_oob_region *res)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+	if (idx >= ecc->steps)
+		return -ERANGE;
+
+	res->offset = BBM_SIZE + METADATA_SIZE + ecc->bytes * idx;
+	res->length = ecc->bytes;
+
+	return 0;
+}
+
+static int oob_free(struct mtd_info *mtd, int idx, struct mtd_oob_region *res)
+{
+	return -ERANGE; /* no free space in spare area */
+}
+
+static const struct mtd_ooblayout_ops tango_nand_ooblayout_ops = {
+	.ecc	= oob_ecc,
+	.free	= oob_free,
+};
+
+static u32 to_ticks(int kHz, int ps)
+{
+	return DIV_ROUND_UP_ULL((u64)kHz * ps, NSEC_PER_SEC);
+}
+
+static int tango_set_timings(struct mtd_info *mtd,
+		const struct nand_data_interface *conf, bool check_only)
+{
+	const struct nand_sdr_timings *sdr = nand_get_sdr_timings(conf);
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+	struct tango_chip *tchip = to_tango_chip(chip);
+	u32 Trdy, Textw, Twc, Twpw, Tacc, Thold, Trpw, Textr;
+	int kHz = nfc->freq_kHz;
+
+	if (IS_ERR(sdr))
+		return PTR_ERR(sdr);
+
+	if (check_only)
+		return 0;
+
+	Trdy = to_ticks(kHz, sdr->tCEA_max - sdr->tREA_max);
+	Textw = to_ticks(kHz, sdr->tWB_max);
+	Twc = to_ticks(kHz, sdr->tWC_min);
+	Twpw = to_ticks(kHz, sdr->tWC_min - sdr->tWP_min);
+
+	Tacc = to_ticks(kHz, sdr->tREA_max);
+	Thold = to_ticks(kHz, sdr->tREH_min);
+	Trpw = to_ticks(kHz, sdr->tRC_min - sdr->tREH_min);
+	Textr = to_ticks(kHz, sdr->tRHZ_max);
+
+	tchip->timing1 = TIMING(Trdy, Textw, Twc, Twpw);
+	tchip->timing2 = TIMING(Tacc, Thold, Trpw, Textr);
+
+	return 0;
+}
+
+static int chip_init(struct device *dev, struct device_node *np)
+{
+	u32 cs;
+	int err, res;
+	struct mtd_info *mtd;
+	struct nand_chip *chip;
+	struct tango_chip *tchip;
+	struct nand_ecc_ctrl *ecc;
+	struct tango_nfc *nfc = dev_get_drvdata(dev);
+
+	tchip = devm_kzalloc(dev, sizeof(*tchip), GFP_KERNEL);
+	if (!tchip)
+		return -ENOMEM;
+
+	res = of_property_count_u32_elems(np, "reg");
+	if (res < 0)
+		return res;
+
+	if (res != 1)
+		return -ENOTSUPP; /* Multi-CS chips are not supported */
+
+	err = of_property_read_u32_index(np, "reg", 0, &cs);
+	if (err)
+		return err;
+
+	if (cs >= MAX_CS)
+		return -EINVAL;
+
+	chip = &tchip->nand_chip;
+	ecc = &chip->ecc;
+	mtd = &chip->mtd;
+
+	chip->read_byte = tango_read_byte;
+	chip->write_buf = tango_write_buf;
+	chip->read_buf = tango_read_buf;
+	chip->select_chip = tango_select_chip;
+	chip->cmd_ctrl = tango_cmd_ctrl;
+	chip->dev_ready = tango_dev_ready;
+	chip->setup_data_interface = tango_set_timings;
+	chip->options = NAND_USE_BOUNCE_BUFFER
+		| NAND_NO_SUBPAGE_WRITE
+		| NAND_WAIT_TCCS;
+	chip->controller = &nfc->hw;
+	tchip->base = nfc->pbus_base + (cs * 256);
+
+	nand_set_flash_node(chip, np);
+	mtd_set_ooblayout(mtd, &tango_nand_ooblayout_ops);
+	mtd->dev.parent = dev;
+
+	err = nand_scan_ident(mtd, 1, NULL);
+	if (err)
+		return err;
+
+	ecc->mode = NAND_ECC_HW;
+	ecc->algo = NAND_ECC_BCH;
+	ecc->bytes = DIV_ROUND_UP(ecc->strength * FIELD_ORDER, BITS_PER_BYTE);
+
+	ecc->read_page_raw = tango_read_page_raw;
+	ecc->write_page_raw = tango_write_page_raw;
+	ecc->read_page = tango_read_page;
+	ecc->write_page = tango_write_page;
+	ecc->read_oob = tango_read_oob;
+	ecc->write_oob = tango_write_oob;
+
+	err = nand_scan_tail(mtd);
+	if (err)
+		return err;
+
+	tchip->xfer_cfg = XFER_CFG(cs, 1, ecc->steps, METADATA_SIZE);
+	tchip->pkt_0_cfg = PKT_CFG(ecc->size + METADATA_SIZE, ecc->strength);
+	tchip->pkt_n_cfg = PKT_CFG(ecc->size, ecc->strength);
+	tchip->bb_cfg = BB_CFG(mtd->writesize, BBM_SIZE);
+
+	err = mtd_device_register(mtd, NULL, 0);
+	if (err)
+		return err;
+
+	nfc->chips[cs] = tchip;
+
+	return 0;
+}
+
+static int tango_nand_remove(struct platform_device *pdev)
+{
+	int cs;
+	struct tango_nfc *nfc = platform_get_drvdata(pdev);
+
+	dma_release_channel(nfc->chan);
+
+	for (cs = 0; cs < MAX_CS; ++cs) {
+		if (nfc->chips[cs] != NULL)
+			nand_release(&nfc->chips[cs]->nand_chip.mtd);
+	}
+
+	return 0;
+}
+
+static int tango_nand_probe(struct platform_device *pdev)
+{
+	int err;
+	struct clk *clk;
+	struct resource *res;
+	struct tango_nfc *nfc;
+	struct device_node *np;
+
+	nfc = devm_kzalloc(&pdev->dev, sizeof(*nfc), GFP_KERNEL);
+	if (!nfc)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	nfc->reg_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(nfc->reg_base))
+		return PTR_ERR(nfc->reg_base);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	nfc->mem_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(nfc->mem_base))
+		return PTR_ERR(nfc->mem_base);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	nfc->pbus_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(nfc->pbus_base))
+		return PTR_ERR(nfc->pbus_base);
+
+	clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	nfc->chan = dma_request_chan(&pdev->dev, "nfc_sbox");
+	if (IS_ERR(nfc->chan))
+		return PTR_ERR(nfc->chan);
+
+	platform_set_drvdata(pdev, nfc);
+	nand_hw_control_init(&nfc->hw);
+	nfc->freq_kHz = clk_get_rate(clk) / 1000;
+
+	for_each_child_of_node(pdev->dev.of_node, np) {
+		err = chip_init(&pdev->dev, np);
+		if (err) {
+			tango_nand_remove(pdev);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+static const struct of_device_id tango_nand_ids[] = {
+	{ .compatible = "sigma,smp8758-nand" },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver tango_nand_driver = {
+	.probe	= tango_nand_probe,
+	.remove	= tango_nand_remove,
+	.driver	= {
+		.name		= "tango-nand",
+		.of_match_table	= tango_nand_ids,
+	},
+};
+
+module_platform_driver(tango_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sigma Designs");
+MODULE_DESCRIPTION("Tango4 NAND Flash controller driver");
-- 
2.9.0


From marex at denx.de  Tue Oct 25 07:49:04 2016
From: marex at denx.de (Marek Vasut)
Date: Tue, 25 Oct 2016 16:49:04 +0200
Subject: [PATCH v3 1/9] mtd: spi-nor: improve macronix_quad_enable()
In-Reply-To: <6948ab96-62ab-c383-4f50-e897be0999b3@atmel.com>
References: <cover.1477325128.git.cyrille.pitchen@atmel.com>
 <c63d3715903e640c7ea5328614bd4468688b761d.1477325128.git.cyrille.pitchen@atmel.com>
 <74f0fa1b-3212-8a21-f966-14f153d2bf43@denx.de>
 <6948ab96-62ab-c383-4f50-e897be0999b3@atmel.com>
Message-ID: <32ea0535-97a6-34d6-7263-24f155d3da62@denx.de>

On 10/25/2016 10:52 AM, Cyrille Pitchen wrote:
> Hi Marek,
> 
> Le 25/10/2016 ? 00:00, Marek Vasut a ?crit :
>> On 10/24/2016 06:34 PM, Cyrille Pitchen wrote:
>>> The patch checks whether the Quad Enable bit is already set in the Status
>>> Register. If so, the function exits immediately with a successful return
>>> code. Otherwise, a message is now printed telling we're setting the
>>> non-volatile bit.
>>>
>>> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
>>> Reviewed-by: Jagan Teki <jagan at openedev.com>
>>> ---
>>>  drivers/mtd/spi-nor/spi-nor.c | 5 +++++
>>>  1 file changed, 5 insertions(+)
>>>
>>> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
>>> index d0fc165d7d66..5c87b2d99507 100644
>>> --- a/drivers/mtd/spi-nor/spi-nor.c
>>> +++ b/drivers/mtd/spi-nor/spi-nor.c
>>> @@ -1211,6 +1211,11 @@ static int macronix_quad_enable(struct spi_nor *nor)
>>>  	val = read_sr(nor);
>>>  	if (val < 0)
>>>  		return val;
>>> +	if (val & SR_QUAD_EN_MX)
>>> +		return 0;
>>> +
>>> +	/* Update the Quad Enable bit. */
>>> +	dev_info(nor->dev, "setting Macronix Quad Enable (non-volatile) bit\n");
>>
>> Should probably be dev_dbg(), since this is just churn in the kernel
>> log. The user doesn't care and the developer can just up the debug level
>> or add his own printk .
>>
> 
> The Quad Enable bit is non-volatile so this trace should be printed only once
> but I'm perfectly fine with using dev_dbg(). I'll change it in the next version.

I get it, but what's the value of it ? Who will make use of this
information being in the kernel log? The kernel is already chatty enough :)

-- 
Best regards,
Marek Vasut


From marex at denx.de  Tue Oct 25 07:58:03 2016
From: marex at denx.de (Marek Vasut)
Date: Tue, 25 Oct 2016 16:58:03 +0200
Subject: [PATCH v3 8/9] mtd: spi-nor: add support to Macronix mx66l1g45g
In-Reply-To: <1d74bddb-fcf7-cb0c-5c0f-a86a54c9a033@atmel.com>
References: <cover.1477325128.git.cyrille.pitchen@atmel.com>
 <4db277dccf52acd48e592d9f285724aab70704d1.1477325128.git.cyrille.pitchen@atmel.com>
 <b043147d-cc39-9238-c6e7-432af67f684e@denx.de>
 <1d74bddb-fcf7-cb0c-5c0f-a86a54c9a033@atmel.com>
Message-ID: <e636f1e4-e8d8-ed9b-2ecd-dc1f248d923e@denx.de>

On 10/25/2016 11:39 AM, Cyrille Pitchen wrote:
> Hi Marek,

Hi,

> Le 25/10/2016 ? 00:16, Marek Vasut a ?crit :
>> On 10/24/2016 06:34 PM, Cyrille Pitchen wrote:
>>> This patch adds an entry in the spi_nor_ids[] table to add support
>>> to the Macronix mx66l1g45g.
>>>
>>> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
>>> ---
>>>  drivers/mtd/spi-nor/spi-nor.c | 1 +
>>>  1 file changed, 1 insertion(+)
>>>
>>> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
>>> index db4874d4af79..eb21d3d4e4e6 100644
>>> --- a/drivers/mtd/spi-nor/spi-nor.c
>>> +++ b/drivers/mtd/spi-nor/spi-nor.c
>>> @@ -937,6 +937,7 @@ static const struct flash_info spi_nor_ids[] = {
>>>  	{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
>>>  	{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
>>>  	{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) },
>>> +	{ "mx66l1g45g",  INFO(0xc2201b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
>>>  	{ "mx66l1g55g",  INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
>>>  
>>>  	/* Micron */
>>>
>> This should be submitted separately as it could be applied right away.
>>
> 
> I totally agree with you. Indeed I have only provided patch 8 and 9 because
> I refer to these memories in the cover letter and to "prove" that I did really
> test every memory of the list. If everyone trust me about the test I do, I
> will remove patch 8 and 9 in the next version.

I think 9 needs to stay or be separated somehow differently from the
series, since it also adds some code to support the flash. Otherwise,
go for submitting them separately.

> By the way, I need to add a remark about the Spansion S25FL127S. The sample I
> have is compliant with neither the JESD216B specification nor the Cypress
> datasheet. More precisely, the Cypress datasheet claims that the S25FL127S
> is compliant with the JESD216B (minor 6) so its Basic Flash Parameter Table
> (BFPT) should contain 16 DWORDS.
> However my sample claims to be JESD216B compliant (I read minor 6) and that
> the BFPT has 16 DWORDS but the 7 last DWORDS of this table are all 0xFFFFFFFF.
> Only the first 9 DWORDS are properly filled, the DWORDS described in JESD216
> (minor 0).
> Also my sample pretend to provide the optional 4-byte address instruction set
> (4BAIS) table but the data I read are once again all 0xFFFFFFFF.
> 
> It's surprising that this 128Mbit memory supports the 4-byte address
> instruction set but the 4-byte Fast Read actually seems to be supported.

They probably use the same HDL design for the controller block in many
memories, they just burn in different ID/SFDP/geometry tables for each
chip they roll out from the factory based on how well the memory array
works.

> Consequently, Fast Read operations work but Sector Erase cannot due to the
> 0xFF op code read from the 4BAIS table. I think I just have a broken sample so
> if anyone can test with another sample and confirm that the SFDP series also
> work with Spansion S25FL127S it would be nice! :)

I don't have one, sorry.

-- 
Best regards,
Marek Vasut


From marex at denx.de  Tue Oct 25 07:53:02 2016
From: marex at denx.de (Marek Vasut)
Date: Tue, 25 Oct 2016 16:53:02 +0200
Subject: [PATCH v3 2/9] mtd: spi-nor: add an alternative method to support
 memory >16MiB
In-Reply-To: <dbcbf5d3-61cd-844d-c2e3-7e8d83914f97@atmel.com>
References: <cover.1477325128.git.cyrille.pitchen@atmel.com>
 <87ace1a307f4d9899a84108de999a2eeb151da1a.1477325128.git.cyrille.pitchen@atmel.com>
 <6eb07d71-cd1c-fa96-f576-c3ab6a62d246@denx.de>
 <dbcbf5d3-61cd-844d-c2e3-7e8d83914f97@atmel.com>
Message-ID: <adf69d0e-adac-5de3-28a2-87733e720915@denx.de>

On 10/25/2016 11:18 AM, Cyrille Pitchen wrote:
> Le 25/10/2016 ? 00:10, Marek Vasut a ?crit :
>> On 10/24/2016 06:34 PM, Cyrille Pitchen wrote:
>>> This patch provides an alternative mean to support memory above 16MiB
>>> (128Mib) by replacing 3byte address op codes by their associated 4byte
>>> address versions.
>>>
>>> Using the dedicated 4byte address op codes doesn't change the internal
>>> state of the SPI NOR memory as opposed to using other means such as
>>> updating a Base Address Register (BAR) and sending command to enter/leave
>>> the 4byte mode.
>>>
>>> Hence when a CPU reset occurs, early bootloaders don't need to be aware
>>> of BAR value or 4byte mode being enabled: they can still access the first
>>> 16MiB of the SPI NOR memory using the regular 3byte address op codes.
>>>
>>> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
>>> Tested-by: Vignesh R <vigneshr at ti.com>
>>> ---
>>>  drivers/mtd/devices/serial_flash_cmds.h |   7 ---
>>>  drivers/mtd/devices/st_spi_fsm.c        |  28 ++++-----
>>>  drivers/mtd/spi-nor/spi-nor.c           | 104 +++++++++++++++++++++++++-------
>>>  include/linux/mtd/spi-nor.h             |  22 +++++--
>>>  4 files changed, 113 insertions(+), 48 deletions(-)
>>>
>>> diff --git a/drivers/mtd/devices/serial_flash_cmds.h b/drivers/mtd/devices/serial_flash_cmds.h
>>> index f59a125295d0..8b81e15105dd 100644
>>> --- a/drivers/mtd/devices/serial_flash_cmds.h
>>> +++ b/drivers/mtd/devices/serial_flash_cmds.h
>>> @@ -18,19 +18,12 @@
>>>  #define SPINOR_OP_RDVCR		0x85
>>>  
>>>  /* JEDEC Standard - Serial Flash Discoverable Parmeters (SFDP) Commands */
>>> -#define SPINOR_OP_READ_1_2_2	0xbb	/* DUAL I/O READ */
>>> -#define SPINOR_OP_READ_1_4_4	0xeb	/* QUAD I/O READ */
>>> -
>>>  #define SPINOR_OP_WRITE		0x02	/* PAGE PROGRAM */
>>>  #define SPINOR_OP_WRITE_1_1_2	0xa2	/* DUAL INPUT PROGRAM */
>>>  #define SPINOR_OP_WRITE_1_2_2	0xd2	/* DUAL INPUT EXT PROGRAM */
>>>  #define SPINOR_OP_WRITE_1_1_4	0x32	/* QUAD INPUT PROGRAM */
>>>  #define SPINOR_OP_WRITE_1_4_4	0x12	/* QUAD INPUT EXT PROGRAM */
>>>  
>>> -/* READ commands with 32-bit addressing */
>>> -#define SPINOR_OP_READ4_1_2_2	0xbc
>>> -#define SPINOR_OP_READ4_1_4_4	0xec
>>> -
>>
>> It'd be nice to have this move/rename bit factored out into a separate
>> patch.
>>
> 
> OK, I will try to do this. Anyway, this rename seems to break the freshly
> merged drivers/spi/spi-bcm-qspi.c, which uses the SPINOR_OP_READ4_* macro so
> I have to do something about this driver. IMHO, the broadcom driver should not
> select its own op code but use the one provided by read_opcode member of the
> struct spi_flash_read_message.

Thanks

>>>  /* Configuration flags */
>>>  #define FLASH_FLAG_SINGLE	0x000000ff
>>>  #define FLASH_FLAG_READ_WRITE	0x00000001
>>> diff --git a/drivers/mtd/devices/st_spi_fsm.c b/drivers/mtd/devices/st_spi_fsm.c
>>> index 5454b4113589..804313a33f2b 100644
>>
>> [...]
>>
>>> +static u8 spi_nor_convert_opcode(u8 opcode,
>>> +				 const struct spi_nor_address_entry *entries,
>>> +				 size_t num_entries)
>>> +{
>>> +	int min, max;
>>> +
>>> +	min = 0;
>>> +	max = num_entries - 1;
>>> +	while (min <= max) {
>>
>> It's really not clear at all what this function does, so please add a
>> comment.
>>
> 
> This is just a dichotomic search to reduce the number of comparisons: it 
> assumes the entries[] array is sorted by ascending src_opcode.
> 
> I will add a comment to clarify this point.

Cool, that'd help. Are you invoking this every time an opcode is
submitted to the SPI NOR ?

>>> +		int mid = (min + max) >> 1;
>>> +		const struct spi_nor_address_entry *entry = &entries[mid];
>>> +
>>> +		if (opcode == entry->src_opcode)
>>> +			return entry->dst_opcode;
>>> +
>>> +		if (opcode < entry->src_opcode)
>>> +			max = mid - 1;
>>> +		else
>>> +			min = mid + 1;
>>> +	}
>>> +
>>> +	/* No conversion found */
>>> +	return opcode;
>>> +}
>>> +
>>> +static u8 spi_nor_3to4_opcode(u8 opcode)
>>> +{
>>> +	/* MUST be sorted by 3byte opcode */
>>
>> Because ... why ?
>>
> 
> As explained above, the dichotomic search implemented in
> spi_nor_convert_opcode() assumes that the input array is sorted by src_opcode.

Maybe you should drop that assumption and do normal traversal of the
array ? I feel this is a bit fragile and will break once someone will
cluelessly add a new opcode.

... or add a comment with a big WARNING statement.

>>> +#define ENTRY_3TO4(_opcode)	{ _opcode, _opcode##_4B }
>>
>> Will this break/be unflexible for flashes with some different 4B opcodes ?
>>
> 
> Of course I cannot provide any guarantee that it will never happen but
> currently it seems that all manufacturers use the same op codes. Besides, 
> the 4-byte address instruction set is part the of JESD216B specification,
> so there is a standard for these op codes and new SPI NOR memories tend
> to match this specification by providing the SFDP tables.

Great. Still, will the code need an overhaul if some vendor decides to
deviate ?

> Indeed this instruction set is maybe one of the few things where all
> manufacturers seem to agree :)

That's a good start :)

>>> +	static const struct spi_nor_address_entry spi_nor_3to4_table[] = {
>>> +		ENTRY_3TO4(SPINOR_OP_PP),		/* 0x02 */
>>> +		ENTRY_3TO4(SPINOR_OP_READ),		/* 0x03 */
>>> +		ENTRY_3TO4(SPINOR_OP_READ_FAST),	/* 0x0b */
>>> +		ENTRY_3TO4(SPINOR_OP_BE_4K),		/* 0x20 */
>>> +		ENTRY_3TO4(SPINOR_OP_PP_1_1_4),		/* 0x32 */
>>> +		ENTRY_3TO4(SPINOR_OP_PP_1_4_4),		/* 0x38 */
>>> +		ENTRY_3TO4(SPINOR_OP_READ_1_1_2),	/* 0x3b */
>>> +		ENTRY_3TO4(SPINOR_OP_BE_32K),		/* 0x52 */
>>> +		ENTRY_3TO4(SPINOR_OP_READ_1_1_4),	/* 0x6b */
>>> +		ENTRY_3TO4(SPINOR_OP_READ_1_2_2),	/* 0xbb */
>>> +		ENTRY_3TO4(SPINOR_OP_SE),		/* 0xd8 */
>>> +		ENTRY_3TO4(SPINOR_OP_READ_1_4_4),	/* 0xeb */
>>> +	};
>>> +#undef ENTRY_3TO4
>>> +
>>> +	return spi_nor_convert_opcode(opcode, spi_nor_3to4_table,
>>> +				      ARRAY_SIZE(spi_nor_3to4_table));
>>> +}
>>> +
>>
>> [...]
>>
> 


-- 
Best regards,
Marek Vasut


From peda at axentia.se  Tue Oct 25 12:39:55 2016
From: peda at axentia.se (Peter Rosin)
Date: Tue, 25 Oct 2016 21:39:55 +0200
Subject: Regression caused by commit c83ed4c9dbb3 "ubifs: Abort readdir on
 error"
Message-ID: <ce65141e-87d2-344e-82d2-a1c4ed0bdbf1@lysator.liu.se>

Hi!

Early on in my boot procedure I create an overlay and shuffle
things around a bit so that the original rootfs stays readonly
at the bottom of an overlayed readwrite fs. This way I can just
toss out the overlayed fs and have a clean and reliable way to
do a "factory-reset". Both the read-only root and and the overlay
are ubifs on nand.

Bisection points to commit c83ed4c9dbb3 "ubifs: Abort readdir
on error". Reverting that commit on top of v4.9-rc2 fixes things.

My "shuffle script" is as follows (with an added comment
indicating the first point of failure) and runs as the first
script by init.

If I add a line
	ls -l /mnt || echo "ls -l /mnt failed"
where that comment is right before the failure, I get no failure
indication even with the broken commit, so directory traversal
seems ok.

Cheers,
Peter

#! /bin/bash

test "x$1" == xstart || exit 0

mkdir /tmp/log

/bin/mount -o remount,rw /dev

/bin/mount | /bin/grep -q "^overlay on / type overlay" && exit 0

if test -e /etc/factory-reset; then
  /usr/sbin/ubiformat /dev/mtd7
  rm /etc/factory-reset
fi

/usr/sbin/ubiattach /dev/ubi_ctrl -m 7
/usr/sbin/ubimkvol /dev/ubi1 -N ovl -m

/bin/mkdir -p /mnt/ovl
/bin/mkdir -p /mnt/roroot
/bin/mkdir -p /mnt/merge
/bin/mount -t ubifs /dev/ubi1_0 /mnt/ovl

/bin/mkdir -p /mnt/ovl/ovl
/bin/mkdir -p /mnt/ovl/work
# with c83ed4c9dbb3, the following mount fails with
# mount: mounting overlay on /mnt/merge failed: No such file or directory
/bin/mount -t overlay -o lowerdir=/,upperdir=/mnt/ovl/ovl,workdir=/mnt/ovl/work overlay /mnt/merge

cd /mnt/merge

/sbin/pivot_root . /mnt/merge/mnt/roroot

/bin/mount --rbind /mnt/roroot/proc /proc
/bin/mount --rbind /mnt/roroot/sys /sys
/bin/mount --rbind /mnt/roroot/dev /dev
/bin/mount --rbind /mnt/roroot/tmp /tmp
/bin/mount --rbind /mnt/roroot/run /run
/bin/mount --rbind /mnt/roroot/mnt/ovl /mnt/ovl

kill $PPID
kill -QUIT 1


From jagan at openedev.com  Tue Oct 25 12:59:52 2016
From: jagan at openedev.com (Jagan Teki)
Date: Wed, 26 Oct 2016 01:29:52 +0530
Subject: [PATCH v2 0/9] mtd: spi-nor: parse SFDP tables to setup (Q)SPI
 memories
In-Reply-To: <CAD6G_RRJUsdPBbbsP_AieAZjRykHN=bk-+RJ7pUuuHWJrgBd8A@mail.gmail.com>
References: <cover.1475668319.git.cyrille.pitchen@atmel.com>
 <CAD6G_RR4Av8+szo9v2oucCFvwnow86gMVC-Ku_-Qfy18TVMGgA@mail.gmail.com>
 <c022e6fc-6bd7-d124-7233-e1e742049657@denx.de>
 <CAD6G_RQ2BjtF2cmPUJvYNk7KZZ6eTVAQsEqWs26xn710A4Dz-w@mail.gmail.com>
 <558d668a-69b0-8066-b7da-090517d3161d@atmel.com>
 <1181d557-c149-8dfd-7fd1-bc83056541cf@atmel.com>
 <CAD6G_RRJUsdPBbbsP_AieAZjRykHN=bk-+RJ7pUuuHWJrgBd8A@mail.gmail.com>
Message-ID: <CAD6G_RQc8JJefBP4=i721zTWShKrojKX2HWSJ+6EsgadL-Srww@mail.gmail.com>

Hi Cyrille,

On Tue, Oct 25, 2016 at 2:38 PM, Jagan Teki <jagan at openedev.com> wrote:
> On Mon, Oct 24, 2016 at 7:37 PM, Cyrille Pitchen
> <cyrille.pitchen at atmel.com> wrote:
>> Le 24/10/2016 ? 14:09, Cyrille Pitchen a ?crit :
>>> Hi Jagan,
>>>
>>> Le 24/10/2016 ? 09:41, Jagan Teki a ?crit :
>>>> On Sun, Oct 23, 2016 at 2:03 AM, Marek Vasut <marex at denx.de> wrote:
>>>>> On 10/22/2016 01:00 PM, Jagan Teki wrote:
>>>>>> On Wed, Oct 5, 2016 at 5:30 PM, Cyrille Pitchen
>>>>>> <cyrille.pitchen at atmel.com> wrote:
>>>>>>> Hi all,
>>>>>>>
>>>>>>> This series extends support of SPI protocols to new protocols such as
>>>>>>> SPI x-2-2 and SPI x-4-4. Also spi_nor_scan() tries now to select the right
>>>>>>> op codes, timing parameters (number of mode and dummy cycles) and erase
>>>>>>> sector size by parsing the Serial Flash Discoverable Parameter (SFDP)
>>>>>>> tables, when available, as defined in the JEDEC JESD216 specifications.
>>>>>>>
>>>>>>> When SFDP tables are not available, legacy settings are still used for
>>>>>>> backward compatibility (SPI and earlier QSPI memories).
>>>>>>>
>>>>>>> Support of SPI memories >128Mbits is also improved by using the 4byte
>>>>>>> address instruction set, when available. Using those dedicated op codes
>>>>>>> is stateless as opposed to enter the 4byte address mode, hence a better
>>>>>>> compatibility with some boot loaders which expect to use 3byte address
>>>>>>> op codes.
>>>>>>
>>>>>> The memories which are > 128Mbits should have 4-bytes addressing
>>>>>> support based on my experience, do you think BAR is also required
>>>>>> atleast from spi-nor side?
>>>>>
>>>>> Yes, I believe BAR is still required for broken/dumb flash chips.
>>>>> Not all chips > 16 MiB support dedicated 4-byte addressing opcodes :-(
>>>>
>>>> Do you have list for those broken chips? because I never find any
>>>> chips which has > 16 MiB with not support of 4-byte address opcodes
>>>> and I've seen the controller has dependable with BAR though it can
>>>> access > 16MiB ex: zynq qspi/
>>>>
>>>> thanks!
>>>>
>>>
>>> Let's take the case of Micron n25q256* memories. Depending of the part number,
>>> the 12h op code is associated with either 4-byte address Page Program 1-1-1
>>> or 3-byte address Page Program 1-4-4.
>>> Then considering parts where the 12h op code is used for 3-byte address Page
>>> Program 1-4-4, there is no op code for a 4-byte address Page Program 1-1-1.
>>>
>>> Note 15, extracted from the Micron n25q_256mb_3v_65nm.pdf datasheet, about
>>> the 3-byte address Page Program 1-4-4 (Extended Quad Input Fast Program):
>>> The code 38h is valid only for part numbers N25Q256A83ESF40x, N25Q256A83E1240x
>>> and N25Q256A83ESFA0F; the code 12h is valid for the other part numbers.

I am trying to understand the conflict more clearly with an example of
Micron, so on Table 18 from Micron n25q_256mb_3v_65nm.pdf datasheet,
Page program 3-byte has 02h and Quad page program 3-byte has 32h but
for 4-byte addressing only quad page program (no support of page
program) can be either 02h/32h/12h and indeed these can change based
on the n25q256* parts so why can't we rely on Quad page program for
4-byte addressing? and so there is no necessity for BAR here.

And also other than the un-supported-controller can't we rely directly
on supported page program opcodes for 4-byte addressing? say if it is
supporting QPP on 4-byte then use it as it is and no need to take care
of PP here.

thanks!
-- 
Jagan Teki
Free Software Engineer | www.openedev.com
U-Boot, Linux | Upstream Maintainer
Hyderabad, India.


From richard at nod.at  Tue Oct 25 13:09:59 2016
From: richard at nod.at (Richard Weinberger)
Date: Tue, 25 Oct 2016 22:09:59 +0200
Subject: Regression caused by commit c83ed4c9dbb3 "ubifs: Abort readdir on
 error"
In-Reply-To: <ce65141e-87d2-344e-82d2-a1c4ed0bdbf1@lysator.liu.se>
References: <ce65141e-87d2-344e-82d2-a1c4ed0bdbf1@lysator.liu.se>
Message-ID: <e4cbe883-003e-5522-400a-da79a98a0ec4@nod.at>

Peter,

On 25.10.2016 21:39, Peter Rosin wrote:
> Hi!
> 
> Early on in my boot procedure I create an overlay and shuffle
> things around a bit so that the original rootfs stays readonly
> at the bottom of an overlayed readwrite fs. This way I can just
> toss out the overlayed fs and have a clean and reliable way to
> do a "factory-reset". Both the read-only root and and the overlay
> are ubifs on nand.
> 
> Bisection points to commit c83ed4c9dbb3 "ubifs: Abort readdir
> on error". Reverting that commit on top of v4.9-rc2 fixes things.
> 
> My "shuffle script" is as follows (with an added comment
> indicating the first point of failure) and runs as the first
> script by init.
> 
> If I add a line
> 	ls -l /mnt || echo "ls -l /mnt failed"
> where that comment is right before the failure, I get no failure
> indication even with the broken commit, so directory traversal
> seems ok.
> 
> Cheers,
> Peter
> 
> #! /bin/bash
> 
> test "x$1" == xstart || exit 0
> 
> mkdir /tmp/log
> 
> /bin/mount -o remount,rw /dev
> 
> /bin/mount | /bin/grep -q "^overlay on / type overlay" && exit 0
> 
> if test -e /etc/factory-reset; then
>   /usr/sbin/ubiformat /dev/mtd7
>   rm /etc/factory-reset
> fi
> 
> /usr/sbin/ubiattach /dev/ubi_ctrl -m 7
> /usr/sbin/ubimkvol /dev/ubi1 -N ovl -m
> 
> /bin/mkdir -p /mnt/ovl
> /bin/mkdir -p /mnt/roroot
> /bin/mkdir -p /mnt/merge
> /bin/mount -t ubifs /dev/ubi1_0 /mnt/ovl
> 
> /bin/mkdir -p /mnt/ovl/ovl
> /bin/mkdir -p /mnt/ovl/work
> # with c83ed4c9dbb3, the following mount fails with
> # mount: mounting overlay on /mnt/merge failed: No such file or directory
> /bin/mount -t overlay -o lowerdir=/,upperdir=/mnt/ovl/ovl,workdir=/mnt/ovl/work overlay /mnt/merge

Uhhhh! Thanks for catching this.
I think I know what is going on, the fix exposes now internal UBIFS return codes to VFS.
Let me prepare a fix.

Thanks,
//richard


From richard at nod.at  Tue Oct 25 13:50:17 2016
From: richard at nod.at (Richard Weinberger)
Date: Tue, 25 Oct 2016 22:50:17 +0200
Subject: Regression caused by commit c83ed4c9dbb3 "ubifs: Abort readdir on
 error"
In-Reply-To: <e4cbe883-003e-5522-400a-da79a98a0ec4@nod.at>
References: <ce65141e-87d2-344e-82d2-a1c4ed0bdbf1@lysator.liu.se>
 <e4cbe883-003e-5522-400a-da79a98a0ec4@nod.at>
Message-ID: <2e3cf9f7-d747-7129-455f-a1105f5474de@nod.at>

Peter,

On 25.10.2016 22:09, Richard Weinberger wrote:
>> /bin/mkdir -p /mnt/ovl/ovl
>> /bin/mkdir -p /mnt/ovl/work
>> # with c83ed4c9dbb3, the following mount fails with
>> # mount: mounting overlay on /mnt/merge failed: No such file or directory
>> /bin/mount -t overlay -o lowerdir=/,upperdir=/mnt/ovl/ovl,workdir=/mnt/ovl/work overlay /mnt/merge
> 
> Uhhhh! Thanks for catching this.
> I think I know what is going on, the fix exposes now internal UBIFS return codes to VFS.
> Let me prepare a fix.

Does the attached patch cure the issue?

Thanks,
//richard
-------------- next part --------------
A non-text attachment was scrubbed...
Name: ubifs_readdir_fix_fix.diff
Type: text/x-patch
Size: 596 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20161025/53be1357/attachment.bin>

From dan.carpenter at oracle.com  Tue Oct 25 13:46:07 2016
From: dan.carpenter at oracle.com (Dan Carpenter)
Date: Tue, 25 Oct 2016 23:46:07 +0300
Subject: [bug report] UBI: Fastmap: Do not add vol if it already exists
Message-ID: <20161025204607.GA27826@elgon.mountain>

Hello shengyong,

The patch e96a8a3bb671: "UBI: Fastmap: Do not add vol if it already
exists" from May 26, 2015, leads to the following static checker
warning:

	drivers/mtd/ubi/fastmap.c:712 ubi_attach_fastmap()
	warn: PTR_ERR(av) is never (-22)

drivers/mtd/ubi/fastmap.c
   703  
   704                  av = add_vol(ai, be32_to_cpu(fmvhdr->vol_id),
   705                               be32_to_cpu(fmvhdr->used_ebs),
   706                               be32_to_cpu(fmvhdr->data_pad),
   707                               fmvhdr->vol_type,
   708                               be32_to_cpu(fmvhdr->last_eb_bytes));
   709  
   710                  if (!av)
   711                          goto fail_bad;
   712                  if (PTR_ERR(av) == -EINVAL) {

av is either -EEXIST or -ENOMEM.  It's never -EINVAL.

   713                          ubi_err(ubi, "volume (ID %i) already exists",
   714                                  fmvhdr->vol_id);
   715                          goto fail_bad;
   716                  }
   717  

regards,
dan carpenter


From richard at nod.at  Tue Oct 25 14:14:07 2016
From: richard at nod.at (Richard Weinberger)
Date: Tue, 25 Oct 2016 23:14:07 +0200
Subject: UBIFS LEB properties tree with odd addresses
In-Reply-To: <DA6901612C71B84D91459DE817C418AE26E0016D@XAP-PVEXMBX01.xlnx.xilinx.com>
References: <DA6901612C71B84D91459DE817C418AE26E0016D@XAP-PVEXMBX01.xlnx.xilinx.com>
Message-ID: <e7f63f72-0dc1-54f4-b94c-2efef3e7af6b@nod.at>

Naga Sureshkumar Relli,

On 25.10.2016 08:05, Naga Sureshkumar Relli wrote:
> Hi,
> 
> We are testing UBIFS (NOR) on Zynq Ultrascale+ MPSoC GQSPI controller driver.
> Apart from my previous mail thread about UBIFS, i.e along with dma issue I am facing one more
> Problem related to offsets.
> 
> Info about GQSPI Controller:
> This controller can access the flash device in the following modes.
> 1. Single flash mode
> 2. Two spi flash memories with separate buses (dual parallel)
> 
> Single flash mode: it is normal configuration, one controller and one flash memory
> 
> In dual parallel mode following are the functionalities:
> 1) Supporting two SPI flash memories operating in parallel. 8 I/O lines.
> 2) Chip selects and clock are shared to both the flash devices
> 3) This mode is targeted for faster read/write speed and also doubles the size
> 4) Commands/data can be transmitted/received from both the devices(mirror), or only upper or only lower flash memory devices.
> 5) Data arrangement:
>     With stripe (controller configuration) enabled,
>     Even bytes i.e. 0, 2, 4,... are transmitted on Lower Data Bus
>     Odd bytes i.e. 1, 3, 5,.. are transmitted on Upper Data Bus.

But these details are hidden from UBI?

> Kernel version : 4.4.0
> Controller limitation: ZynqMP gqspi controller supports only even addresses when two flash devices are connected (dual parallel mode).
> 
> Issue I am facing:
> -> Since our controller supports even addresses in dual parallel mode
> We are seeing issues with ubifs in dual parallel mode and jffs2 is working fine and we observed the following:
> 
> IN dual parallel mode, the Erase block size was 128KiB whereas single flash mode the Erase block size was 64KiB.
> In single flash mode, we are getting pnode_sz value as 16 and for dual parallel mode we are getting an odd value 17
> And ltab_sz value in single mode as 12 and in dual parallel mode as 11.
> Because of these odd values, check_lpt_type  offset argument is odd address and hence lpt_type error.
> 
> When I ran the mnt command, I am getting the following error
> "UBIFS error (ubi0:0 pid 1882): check_lpt_type: invalid type (4) in LPT node type 2"
> Ran the below commands:
> a)ubiformat /dev/mtd0 -e 0 -y
> b)ubiattach -p /dev/mtd0
> c)ubimkvol -N data -m /dev/ubi0
> d)mount -t ubifs ubi0:data /mnt
> 
> So for temporary hack we did the following change
> In fs/ubifs/lpt.c
> In do_calc_lpt_geom(), added the following
> +       if (c->pnode_sz % 2)
> +               c->pnode_sz += 1; 
> +       if (c->ltab_sz % 2)
> +               c->ltab_sz += 1;
> 
> Please kindly suggest, I need your inputs, changing the pnode_sz and ltab_sz to even in lpt.c, will it impact on any others?

Hmm, the calculations in lpt.c use basic properties of the MTD (number of blocks, etc...).
Can you please double check which property causes the failure and also verify whether the MTD driver
provides correct properties. i.e. page sizes, block size, number of blocks, ...

Thanks,
//richard


From shengyong1 at huawei.com  Tue Oct 25 18:46:51 2016
From: shengyong1 at huawei.com (Sheng Yong)
Date: Wed, 26 Oct 2016 09:46:51 +0800
Subject: [bug report] UBI: Fastmap: Do not add vol if it already exists
In-Reply-To: <20161025204607.GA27826@elgon.mountain>
References: <20161025204607.GA27826@elgon.mountain>
Message-ID: <58100B0B.3030906@huawei.com>

Hi Dan,

On 10/26/2016 4:46 AM, Dan Carpenter wrote:
> Hello shengyong,
> 
> The patch e96a8a3bb671: "UBI: Fastmap: Do not add vol if it already
> exists" from May 26, 2015, leads to the following static checker
> warning:
> 
> 	drivers/mtd/ubi/fastmap.c:712 ubi_attach_fastmap()
> 	warn: PTR_ERR(av) is never (-22)
> 
> drivers/mtd/ubi/fastmap.c
>    703  
>    704                  av = add_vol(ai, be32_to_cpu(fmvhdr->vol_id),
>    705                               be32_to_cpu(fmvhdr->used_ebs),
>    706                               be32_to_cpu(fmvhdr->data_pad),
>    707                               fmvhdr->vol_type,
>    708                               be32_to_cpu(fmvhdr->last_eb_bytes));
>    709  
>    710                  if (!av)
>    711                          goto fail_bad;
>    712                  if (PTR_ERR(av) == -EINVAL) {
> 
> av is either -EEXIST or -ENOMEM.  It's never -EINVAL.
The commit e96a8a3bb671 ("UBI: Fastmap: Do not add vol if it already exists")
adds a "return ERR_PTR(-EINVAL);" to add_vol(). So I think av could be -EINVAL.
You mean add_vol should return -EEXIST instead of -EINVAL?

thanks,
Sheng
> 
>    713                          ubi_err(ubi, "volume (ID %i) already exists",
>    714                                  fmvhdr->vol_id);
>    715                          goto fail_bad;
>    716                  }
>    717  
> 
> regards,
> dan carpenter
> 
> .
> 



From peda at axentia.se  Tue Oct 25 19:40:29 2016
From: peda at axentia.se (Peter Rosin)
Date: Wed, 26 Oct 2016 04:40:29 +0200
Subject: Regression caused by commit c83ed4c9dbb3 "ubifs: Abort readdir
 on error"
In-Reply-To: <2e3cf9f7-d747-7129-455f-a1105f5474de@nod.at>
References: <ce65141e-87d2-344e-82d2-a1c4ed0bdbf1@lysator.liu.se>
 <e4cbe883-003e-5522-400a-da79a98a0ec4@nod.at>
 <2e3cf9f7-d747-7129-455f-a1105f5474de@nod.at>
Message-ID: <5810179D.90104@axentia.se>

Hi Richard,

On 2016-10-25 22:50, Richard Weinberger wrote:
> Peter,
> 
> On 25.10.2016 22:09, Richard Weinberger wrote:
>>> /bin/mkdir -p /mnt/ovl/ovl
>>> /bin/mkdir -p /mnt/ovl/work
>>> # with c83ed4c9dbb3, the following mount fails with
>>> # mount: mounting overlay on /mnt/merge failed: No such file or directory
>>> /bin/mount -t overlay -o lowerdir=/,upperdir=/mnt/ovl/ovl,workdir=/mnt/ovl/work overlay /mnt/merge
>>
>> Uhhhh! Thanks for catching this.
>> I think I know what is going on, the fix exposes now internal UBIFS return codes to VFS.
>> Let me prepare a fix.
> 
> Does the attached patch cure the issue?

Yup, back to normal AFAICT. Thanks for the speedy fix!

Reported-by: Peter Rosin <peda at axentia.se>
Tested-by: Peter Rosin <peda at axentia.se>

Cheers,
Peter


From nobuhiro.iwamatsu.kw at hitachi.com  Tue Oct 25 22:20:46 2016
From: nobuhiro.iwamatsu.kw at hitachi.com (=?utf-8?B?5bKp5p2+5L+h5rSLIC8gSVdBTUFUU1XvvIxOT0JVSElSTw==?=)
Date: Wed, 26 Oct 2016 05:20:46 +0000
Subject: [PATCH] mtd: spi-nor: Add support for N25Q256A13
In-Reply-To: <CAD6G_RSTKULAU6v=W=GS-x10x206oMTjd6kfNhDuNc=jwqN93g@mail.gmail.com>
References: <1475637910-2324-1-git-send-email-nobuhiro.iwamatsu.kw@hitachi.com>
 <CAD6G_RT8s5=vDP2bc__SULyxt=NnqZrLDuepcUkxs75HG9=ZQg@mail.gmail.com>
 <25b5dc82-a5fa-1d0f-8915-60b121a65751@gmail.com>
 <CAD6G_RSTKULAU6v=W=GS-x10x206oMTjd6kfNhDuNc=jwqN93g@mail.gmail.com>
Message-ID: <F89ECF87BC754A49BB74E794F6A0EC2FF7F15E@GSjpTKYDCembx31.service.hitachi.net>

Hi, all.

> -----Original Message-----
> From: Jagan Teki [mailto:jagan at openedev.com]
> Sent: Monday, October 24, 2016 10:21 PM
> To: Marek Vasut
> Cc: ???? / IWAMATSU?NOBUHIRO; linux-mtd at lists.infradead.org; Brian
> Norris; ???? / OSAFUNE?TATSUAKI; David Woodhouse
> Subject: Re: [PATCH] mtd: spi-nor: Add support for N25Q256A13
> 
> On Mon, Oct 24, 2016 at 6:39 PM, Marek Vasut <marek.vasut at gmail.com> wrote:
> > On 10/24/2016 10:04 AM, Jagan Teki wrote:
> >> On Wed, Oct 5, 2016 at 8:55 AM, Nobuhiro Iwamatsu
> >> <nobuhiro.iwamatsu.kw at hitachi.com> wrote:
> >>> Add Micron N25Q256A13 256Mbit NOR Flash in the list of supported
> >>> devices. This chip is the same structure as the N25Q256A but ID is
> >>> different.
> >>>
> >>> Signed-off-by: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.kw at hitachi.com>
> >>> ---
> >>>
> >>>  drivers/mtd/spi-nor/spi-nor.c | 1 +
> >>>  1 file changed, 1 insertion(+)
> >>>
> >>> diff --git a/drivers/mtd/spi-nor/spi-nor.c
> >>> b/drivers/mtd/spi-nor/spi-nor.c index d0fc165..ce67ccd 100644
> >>> --- a/drivers/mtd/spi-nor/spi-nor.c
> >>> +++ b/drivers/mtd/spi-nor/spi-nor.c
> >>> @@ -884,6 +884,7 @@ static const struct flash_info spi_nor_ids[] = {
> >>>         { "n25q128a11",  INFO(0x20bb18, 0, 64 * 1024,  256, SECT_4K
> | SPI_NOR_QUAD_READ) },
> >>>         { "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024,  256, SECT_4K
> | SPI_NOR_QUAD_READ) },
> >>>         { "n25q256a",    INFO(0x20ba19, 0, 64 * 1024,  512, SECT_4K
> | SPI_NOR_QUAD_READ) },
> >>> +       { "n25q256a13",  INFO(0x20bb19, 0, 64 * 1024,  512, SECT_4K
> >>> + | SPI_NOR_QUAD_READ) },
> >>
> >> Since the previous chips follow 'a' notation for bb chips, better to
> >> use n25q256a for bb and n25q256 for ba
> >
> > Do you mind expanding on this? I don't understand the remark.
> 
> { "n25q064",     INFO(0x20ba17,
> { "n25q064a",   INFO(0x20bb17,
> 
> What I am saying is n25q256a is should be n25q256 and the new addition can
> be n25q256a
> 

I see. I will update patch.

Thanks!

Nobuhiro

From dan.carpenter at oracle.com  Wed Oct 26 01:25:36 2016
From: dan.carpenter at oracle.com (Dan Carpenter)
Date: Wed, 26 Oct 2016 11:25:36 +0300
Subject: [bug report] UBI: Fastmap: Do not add vol if it already exists
In-Reply-To: <58100B0B.3030906@huawei.com>
References: <20161025204607.GA27826@elgon.mountain>
 <58100B0B.3030906@huawei.com>
Message-ID: <20161026082536.GP4418@mwanda>

On Wed, Oct 26, 2016 at 09:46:51AM +0800, Sheng Yong wrote:
> Hi Dan,
> 
> On 10/26/2016 4:46 AM, Dan Carpenter wrote:
> > Hello shengyong,
> > 
> > The patch e96a8a3bb671: "UBI: Fastmap: Do not add vol if it already
> > exists" from May 26, 2015, leads to the following static checker
> > warning:
> > 
> > 	drivers/mtd/ubi/fastmap.c:712 ubi_attach_fastmap()
> > 	warn: PTR_ERR(av) is never (-22)
> > 
> > drivers/mtd/ubi/fastmap.c
> >    703  
> >    704                  av = add_vol(ai, be32_to_cpu(fmvhdr->vol_id),
> >    705                               be32_to_cpu(fmvhdr->used_ebs),
> >    706                               be32_to_cpu(fmvhdr->data_pad),
> >    707                               fmvhdr->vol_type,
> >    708                               be32_to_cpu(fmvhdr->last_eb_bytes));
> >    709  
> >    710                  if (!av)
> >    711                          goto fail_bad;
> >    712                  if (PTR_ERR(av) == -EINVAL) {
> > 
> > av is either -EEXIST or -ENOMEM.  It's never -EINVAL.
> The commit e96a8a3bb671 ("UBI: Fastmap: Do not add vol if it already exists")
> adds a "return ERR_PTR(-EINVAL);" to add_vol(). So I think av could be -EINVAL.
> You mean add_vol should return -EEXIST instead of -EINVAL?
>

Oh, ah.  I'm on linux-next.  Commit de4c455b3e9f ("UBI: factorize code
used to manipulate volumes at attach time") removed the -EINVAL.

It's really Boris to blame for this warning.  I'm not sure what the fix
is.

regards,
dan carpenter



From boris.brezillon at free-electrons.com  Wed Oct 26 02:23:46 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Wed, 26 Oct 2016 11:23:46 +0200
Subject: [bug report] UBI: Fastmap: Do not add vol if it already exists
In-Reply-To: <20161026082536.GP4418@mwanda>
References: <20161025204607.GA27826@elgon.mountain>
 <58100B0B.3030906@huawei.com> <20161026082536.GP4418@mwanda>
Message-ID: <20161026112346.40588a81@bbrezillon>

+ Richard

On Wed, 26 Oct 2016 11:25:36 +0300
Dan Carpenter <dan.carpenter at oracle.com> wrote:

> On Wed, Oct 26, 2016 at 09:46:51AM +0800, Sheng Yong wrote:
> > Hi Dan,
> > 
> > On 10/26/2016 4:46 AM, Dan Carpenter wrote:  
> > > Hello shengyong,
> > > 
> > > The patch e96a8a3bb671: "UBI: Fastmap: Do not add vol if it already
> > > exists" from May 26, 2015, leads to the following static checker
> > > warning:
> > > 
> > > 	drivers/mtd/ubi/fastmap.c:712 ubi_attach_fastmap()
> > > 	warn: PTR_ERR(av) is never (-22)
> > > 
> > > drivers/mtd/ubi/fastmap.c
> > >    703  
> > >    704                  av = add_vol(ai, be32_to_cpu(fmvhdr->vol_id),
> > >    705                               be32_to_cpu(fmvhdr->used_ebs),
> > >    706                               be32_to_cpu(fmvhdr->data_pad),
> > >    707                               fmvhdr->vol_type,
> > >    708                               be32_to_cpu(fmvhdr->last_eb_bytes));
> > >    709  
> > >    710                  if (!av)
> > >    711                          goto fail_bad;
> > >    712                  if (PTR_ERR(av) == -EINVAL) {
> > > 
> > > av is either -EEXIST or -ENOMEM.  It's never -EINVAL.  
> > The commit e96a8a3bb671 ("UBI: Fastmap: Do not add vol if it already exists")
> > adds a "return ERR_PTR(-EINVAL);" to add_vol(). So I think av could be -EINVAL.
> > You mean add_vol should return -EEXIST instead of -EINVAL?
> >  
> 
> Oh, ah.  I'm on linux-next.  Commit de4c455b3e9f ("UBI: factorize code
> used to manipulate volumes at attach time") removed the -EINVAL.
> 
> It's really Boris to blame for this warning.  I'm not sure what the fix
> is.

Yes, sorry, I didn't notice the caller was explicitly testing for
-EINVAL.

Here is a patch fixing the problem:

--->8---
From 66d46bb212a8fcdcdd54def051492abb1668f1b2 Mon Sep 17 00:00:00 2001
From: Boris Brezillon <boris.brezillon at free-electrons.com>
Date: Wed, 26 Oct 2016 11:17:03 +0200
Subject: [PATCH] UBI: fastmap: Fix add_vol() return value test in
 ubi_attach_fastmap()

Commit e96a8a3bb671 ("UBI: Fastmap: Do not add vol if it already
exists") introduced a bug by changing the possible error codes returned
by add_vol():
- this functions no longer returns NULL in case of allocation failure
  but return ERR_PTR(-ENOMEM)
- when a duplicate entry in the volume RB tree is found it returns
  ERR_PTR(-EEXIST) instead of ERR_PTR(-EINVAL)

Fix the tests done of add_vol() return value accordingly.

Fixes: e96a8a3bb671 ("UBI: Fastmap: Do not add vol if it already exists")
Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/ubi/fastmap.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c
index d6384d965788..eb39c44726e3 100644
--- a/drivers/mtd/ubi/fastmap.c
+++ b/drivers/mtd/ubi/fastmap.c
@@ -707,11 +707,11 @@ static int ubi_attach_fastmap(struct ubi_device *ubi,
 			     fmvhdr->vol_type,
 			     be32_to_cpu(fmvhdr->last_eb_bytes));
 
-		if (!av)
-			goto fail_bad;
-		if (PTR_ERR(av) == -EINVAL) {
-			ubi_err(ubi, "volume (ID %i) already exists",
-				fmvhdr->vol_id);
+		if (IS_ERR(av)) {
+			if (PTR_ERR(av) == -EEXIST)
+				ubi_err(ubi, "volume (ID %i) already exists",
+					fmvhdr->vol_id);
+
 			goto fail_bad;
 		}


From ricard.wanderlof at axis.com  Wed Oct 26 04:27:00 2016
From: ricard.wanderlof at axis.com (Ricard Wanderlof)
Date: Wed, 26 Oct 2016 13:27:00 +0200
Subject: [PATCH 1/4] of: Add device tree bindings for Evatronix
In-Reply-To: <20160610175454.327f51a2@bbrezillon>
References: <alpine.DEB.2.02.1606020946500.19416@lnxricardw1.se.axis.com>
 <20160603162207.0688c9e6@bbrezillon>
 <alpine.DEB.2.02.1606060757180.23377@lnxricardw1.se.axis.com>
 <20160608175018.16c88207@bbrezillon>
 <alpine.DEB.2.02.1606101641050.30757@lnxricardw1.se.axis.com>
 <20160610175454.327f51a2@bbrezillon>
Message-ID: <alpine.DEB.2.02.1610261152170.9986@lnxricardw1.se.axis.com>


Hi Boris,

Juggling the rework of the Evatronix NAND flash driver with other projects 
I'm plodding on and will hopefully have something that can be reviewed in 
a few weeks' time.

In the meantime there is an issue which I want to bring up, regarding the 
timing configuration. Back in June we had this discussion, regarding my 
suggestion to put the raw values for the timing control registers in the 
IP in the DT:

On Fri, 10 Jun 2016, Boris Brezillon wrote:

> On Fri, 10 Jun 2016 17:35:24 +0200
> Ricard Wanderlof <ricard.wanderlof at axis.com> wrote:
>
> > > > > > +		     TIME_SEQ_1, TIMINGS_ASYN, TIME_GEN_SEQ_0, TIME_GEN_SEQ_1,
> > > > > > +		     TIME_GEN_SEQ_2 and TIME_GEN_SEQ_3 registers, respectively.    
> > > > > 
> > > > > 
> > > > > Can this be extracted from the timing mode exposed by the NAND chip.
> > > > > IMO it shouldn't be defined in the DT. 
> >
> > [ ... ]
> > 
> > > Just because it's complicated to extract these information at the driver 
> > > level level doesn't mean you should put it in the DT. That's exactly the 
> > > opposite: the DT is supposed to encode the hardware representation, not 
> > > how you want to configure it.  
> > 
> > [ ... ]
> > 
> > > How about using a default/safe timing mode for now (ONFI timing mode 0
> > > should work for all NANDs).
> > > The only thing you'll have to do is retrieve the source clk rate and
> > > calculate timing register values accordingly. Or you can even assume
> > > you always have a 100MHz source clk and hardcode it in your driver.  
> > 
> > Yes, that is certainly possible of course, and the driver already has a 
> > hard-coded default setup for this case.
> > 
> > In that case though the driver could have pre-set setups for other ONFi 
> > modes, and we could have an _optional_ DT property to select them, the 
> > reason for that being in order to handle non-ONFi flashes whose timing 
> > cannot be gleaned from the device itself.
> > 
> > I.e. something like
> > 
> > evatronix,onfi-timing-mode = <2>;
> > 
> Actually this has been added to the nand_flash_dev structure, and it's
> called onfi_timing_mode_default.
> If you need a different timing, define a full ID entry for your NAND.

In our products, we use 1, 2 and 4 Gbit SLC NAND flashes, some of which 
are ONFi complient and some not, depending on the manufacturer. For the 
non-ONFi flashes, the ones which we have looked at and which we specify in 
our products actually support ONFi mode 2. However, in practice, as part 
of the nand_scan_ident() procedure, the chip->onfi_timing_mode_default 
value is set to 0, because the EXTENDED_ID_NAND() macro used for these 
flashes doesn't set the timing mode to anything else. There are some full 
ID listings which apparently set a different timing mode for certain 
flashes (such as Toshiba TC58NVG0S3E).

What I would like to have in the device tree, either as a general mtd or 
proprietary property, is something like the above, possibly called 
something like force-onfi-timing-mode, which forcibly sets the timing mode 
of the hardware. When this property is not set, the timing mode used will 
default to onfi_timing_mode_default for non-ONFi flashes, or 
onfi_get_async_timing_mode() for ONFi flashes.

The reationale behind this is that it is impractical to list all specific 
flash chips which actually support a given timing mode. Say another chip 
comes out on the market either from an existing or a new manufacturer, 
which correctly identifies itself using the ID bytes, but not using the 
full ID. In order to support the speed of this device, we would need to 
upgrade the kernel in the product. If we on the other hand have a hardware 
specification that says that we only use flashes which support a certain 
specified timing mode (because of memory bandwidth requirements), we can 
simply put force-onfi-timing-mode = <2> in the DT, and it will work for 
all flashes that meet the specifications, whether they match the full ID 
or not.

For the case of a .dts file specifying a more general board which can be 
populated with any flash chip, the property can be left out, and the 
timing mode will then be determined using the ID and ONFi parameter page, 
as applicable.

Alternatively having this property as a proprietary one (i.e. 
"evatronix,force-onfi-timing-mode") is an alternative, but I still wanted 
to bring up the discussion for the general case.

/Ricard
-- 
Ricard Wolf Wanderl?f                           ricardw(at)axis.com
Axis Communications AB, Lund, Sweden            www.axis.com
Phone +46 46 272 2016                           Fax +46 46 13 61 30


From shengyong1 at huawei.com  Wed Oct 26 04:28:33 2016
From: shengyong1 at huawei.com (Sheng Yong)
Date: Wed, 26 Oct 2016 19:28:33 +0800
Subject: [bug report] UBI: Fastmap: Do not add vol if it already exists
In-Reply-To: <20161026082536.GP4418@mwanda>
References: <20161025204607.GA27826@elgon.mountain>
 <58100B0B.3030906@huawei.com> <20161026082536.GP4418@mwanda>
Message-ID: <58109360.1050202@huawei.com>



On 10/26/2016 4:25 PM, Dan Carpenter wrote:
> On Wed, Oct 26, 2016 at 09:46:51AM +0800, Sheng Yong wrote:
>> Hi Dan,
>>
>> On 10/26/2016 4:46 AM, Dan Carpenter wrote:
>>> Hello shengyong,
>>>
>>> The patch e96a8a3bb671: "UBI: Fastmap: Do not add vol if it already
>>> exists" from May 26, 2015, leads to the following static checker
>>> warning:
>>>
>>> 	drivers/mtd/ubi/fastmap.c:712 ubi_attach_fastmap()
>>> 	warn: PTR_ERR(av) is never (-22)
>>>
>>> drivers/mtd/ubi/fastmap.c
>>>    703  
>>>    704                  av = add_vol(ai, be32_to_cpu(fmvhdr->vol_id),
>>>    705                               be32_to_cpu(fmvhdr->used_ebs),
>>>    706                               be32_to_cpu(fmvhdr->data_pad),
>>>    707                               fmvhdr->vol_type,
>>>    708                               be32_to_cpu(fmvhdr->last_eb_bytes));
>>>    709  
>>>    710                  if (!av)
>>>    711                          goto fail_bad;
>>>    712                  if (PTR_ERR(av) == -EINVAL) {
>>>
>>> av is either -EEXIST or -ENOMEM.  It's never -EINVAL.
>> The commit e96a8a3bb671 ("UBI: Fastmap: Do not add vol if it already exists")
>> adds a "return ERR_PTR(-EINVAL);" to add_vol(). So I think av could be -EINVAL.
>> You mean add_vol should return -EEXIST instead of -EINVAL?
>>
> 
> Oh, ah.  I'm on linux-next.  Commit de4c455b3e9f ("UBI: factorize code
> used to manipulate volumes at attach time") removed the -EINVAL.
Sorry, my bad. I didn't check linux-next. You're right, the caller of add_vol should
have checked -EEXIST. And Boris's patch could fix it. Thanks Dan for pointing that
out.

thanks,
Sheng
> 
> It's really Boris to blame for this warning.  I'm not sure what the fix
> is.
> 
> regards,
> dan carpenter
> 
> 
> .
> 



From shengyong1 at huawei.com  Wed Oct 26 04:30:13 2016
From: shengyong1 at huawei.com (Sheng Yong)
Date: Wed, 26 Oct 2016 19:30:13 +0800
Subject: [bug report] UBI: Fastmap: Do not add vol if it already exists
In-Reply-To: <20161026112346.40588a81@bbrezillon>
References: <20161025204607.GA27826@elgon.mountain>	<58100B0B.3030906@huawei.com>	<20161026082536.GP4418@mwanda>
 <20161026112346.40588a81@bbrezillon>
Message-ID: <581093C5.7080105@huawei.com>



On 10/26/2016 5:23 PM, Boris Brezillon wrote:
> + Richard
> 
> On Wed, 26 Oct 2016 11:25:36 +0300
> Dan Carpenter <dan.carpenter at oracle.com> wrote:
> 
>> On Wed, Oct 26, 2016 at 09:46:51AM +0800, Sheng Yong wrote:
>>> Hi Dan,
>>>
>>> On 10/26/2016 4:46 AM, Dan Carpenter wrote:  
>>>> Hello shengyong,
>>>>
>>>> The patch e96a8a3bb671: "UBI: Fastmap: Do not add vol if it already
>>>> exists" from May 26, 2015, leads to the following static checker
>>>> warning:
>>>>
>>>> 	drivers/mtd/ubi/fastmap.c:712 ubi_attach_fastmap()
>>>> 	warn: PTR_ERR(av) is never (-22)
>>>>
>>>> drivers/mtd/ubi/fastmap.c
>>>>    703  
>>>>    704                  av = add_vol(ai, be32_to_cpu(fmvhdr->vol_id),
>>>>    705                               be32_to_cpu(fmvhdr->used_ebs),
>>>>    706                               be32_to_cpu(fmvhdr->data_pad),
>>>>    707                               fmvhdr->vol_type,
>>>>    708                               be32_to_cpu(fmvhdr->last_eb_bytes));
>>>>    709  
>>>>    710                  if (!av)
>>>>    711                          goto fail_bad;
>>>>    712                  if (PTR_ERR(av) == -EINVAL) {
>>>>
>>>> av is either -EEXIST or -ENOMEM.  It's never -EINVAL.  
>>> The commit e96a8a3bb671 ("UBI: Fastmap: Do not add vol if it already exists")
>>> adds a "return ERR_PTR(-EINVAL);" to add_vol(). So I think av could be -EINVAL.
>>> You mean add_vol should return -EEXIST instead of -EINVAL?
>>>  
>>
>> Oh, ah.  I'm on linux-next.  Commit de4c455b3e9f ("UBI: factorize code
>> used to manipulate volumes at attach time") removed the -EINVAL.
>>
>> It's really Boris to blame for this warning.  I'm not sure what the fix
>> is.
> 
> Yes, sorry, I didn't notice the caller was explicitly testing for
> -EINVAL.
> 
> Here is a patch fixing the problem:
> 
> --->8---
>>From 66d46bb212a8fcdcdd54def051492abb1668f1b2 Mon Sep 17 00:00:00 2001
> From: Boris Brezillon <boris.brezillon at free-electrons.com>
> Date: Wed, 26 Oct 2016 11:17:03 +0200
> Subject: [PATCH] UBI: fastmap: Fix add_vol() return value test in
>  ubi_attach_fastmap()
> 
> Commit e96a8a3bb671 ("UBI: Fastmap: Do not add vol if it already
> exists") introduced a bug by changing the possible error codes returned
> by add_vol():
> - this functions no longer returns NULL in case of allocation failure
>   but return ERR_PTR(-ENOMEM)
> - when a duplicate entry in the volume RB tree is found it returns
>   ERR_PTR(-EEXIST) instead of ERR_PTR(-EINVAL)
> 
> Fix the tests done of add_vol() return value accordingly.
> 
> Fixes: e96a8a3bb671 ("UBI: Fastmap: Do not add vol if it already exists")
> Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
> ---
>  drivers/mtd/ubi/fastmap.c | 10 +++++-----
>  1 file changed, 5 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c
> index d6384d965788..eb39c44726e3 100644
> --- a/drivers/mtd/ubi/fastmap.c
> +++ b/drivers/mtd/ubi/fastmap.c
> @@ -707,11 +707,11 @@ static int ubi_attach_fastmap(struct ubi_device *ubi,
>  			     fmvhdr->vol_type,
>  			     be32_to_cpu(fmvhdr->last_eb_bytes));
>  
> -		if (!av)
> -			goto fail_bad;
> -		if (PTR_ERR(av) == -EINVAL) {
> -			ubi_err(ubi, "volume (ID %i) already exists",
> -				fmvhdr->vol_id);
> +		if (IS_ERR(av)) {
> +			if (PTR_ERR(av) == -EEXIST)
> +				ubi_err(ubi, "volume (ID %i) already exists",
> +					fmvhdr->vol_id);
> +
>  			goto fail_bad;
>  		}
> 
> .
> 
Acked-by: Sheng Yong <shengyong1 at huawei.com>

thanks,
Sheng



From boris.brezillon at free-electrons.com  Wed Oct 26 04:52:41 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Wed, 26 Oct 2016 13:52:41 +0200
Subject: [PATCH 1/4] of: Add device tree bindings for Evatronix
In-Reply-To: <alpine.DEB.2.02.1610261152170.9986@lnxricardw1.se.axis.com>
References: <alpine.DEB.2.02.1606020946500.19416@lnxricardw1.se.axis.com>
 <20160603162207.0688c9e6@bbrezillon>
 <alpine.DEB.2.02.1606060757180.23377@lnxricardw1.se.axis.com>
 <20160608175018.16c88207@bbrezillon>
 <alpine.DEB.2.02.1606101641050.30757@lnxricardw1.se.axis.com>
 <20160610175454.327f51a2@bbrezillon>
 <alpine.DEB.2.02.1610261152170.9986@lnxricardw1.se.axis.com>
Message-ID: <20161026135241.63653c4f@bbrezillon>

Hi Ricard,

On Wed, 26 Oct 2016 13:27:00 +0200
Ricard Wanderlof <ricard.wanderlof at axis.com> wrote:

> Hi Boris,
> 
> Juggling the rework of the Evatronix NAND flash driver with other projects 
> I'm plodding on and will hopefully have something that can be reviewed in 
> a few weeks' time.
> 
> In the meantime there is an issue which I want to bring up, regarding the 
> timing configuration. Back in June we had this discussion, regarding my 
> suggestion to put the raw values for the timing control registers in the 
> IP in the DT:
> 
> On Fri, 10 Jun 2016, Boris Brezillon wrote:
> 
> > On Fri, 10 Jun 2016 17:35:24 +0200
> > Ricard Wanderlof <ricard.wanderlof at axis.com> wrote:
> >  
> > > > > > > +		     TIME_SEQ_1, TIMINGS_ASYN, TIME_GEN_SEQ_0, TIME_GEN_SEQ_1,
> > > > > > > +		     TIME_GEN_SEQ_2 and TIME_GEN_SEQ_3 registers, respectively.      
> > > > > > 
> > > > > > 
> > > > > > Can this be extracted from the timing mode exposed by the NAND chip.
> > > > > > IMO it shouldn't be defined in the DT.   
> > >
> > > [ ... ]
> > >   
> > > > Just because it's complicated to extract these information at the driver 
> > > > level level doesn't mean you should put it in the DT. That's exactly the 
> > > > opposite: the DT is supposed to encode the hardware representation, not 
> > > > how you want to configure it.    
> > > 
> > > [ ... ]
> > >   
> > > > How about using a default/safe timing mode for now (ONFI timing mode 0
> > > > should work for all NANDs).
> > > > The only thing you'll have to do is retrieve the source clk rate and
> > > > calculate timing register values accordingly. Or you can even assume
> > > > you always have a 100MHz source clk and hardcode it in your driver.    
> > > 
> > > Yes, that is certainly possible of course, and the driver already has a 
> > > hard-coded default setup for this case.
> > > 
> > > In that case though the driver could have pre-set setups for other ONFi 
> > > modes, and we could have an _optional_ DT property to select them, the 
> > > reason for that being in order to handle non-ONFi flashes whose timing 
> > > cannot be gleaned from the device itself.
> > > 
> > > I.e. something like
> > > 
> > > evatronix,onfi-timing-mode = <2>;
> > >   
> > Actually this has been added to the nand_flash_dev structure, and it's
> > called onfi_timing_mode_default.
> > If you need a different timing, define a full ID entry for your NAND.  
> 
> In our products, we use 1, 2 and 4 Gbit SLC NAND flashes, some of which 
> are ONFi complient and some not, depending on the manufacturer. For the 
> non-ONFi flashes, the ones which we have looked at and which we specify in 
> our products actually support ONFi mode 2. However, in practice, as part 
> of the nand_scan_ident() procedure, the chip->onfi_timing_mode_default 
> value is set to 0, because the EXTENDED_ID_NAND() macro used for these 
> flashes doesn't set the timing mode to anything else. There are some full 
> ID listings which apparently set a different timing mode for certain 
> flashes (such as Toshiba TC58NVG0S3E).
> 
> What I would like to have in the device tree, either as a general mtd or 
> proprietary property, is something like the above, possibly called 
> something like force-onfi-timing-mode, which forcibly sets the timing mode 
> of the hardware. When this property is not set, the timing mode used will 
> default to onfi_timing_mode_default for non-ONFi flashes, or 
> onfi_get_async_timing_mode() for ONFi flashes.

I'm not against the addition of this onfi-timing-mode property, but not
for the same reason. Your NAND might be able to support a specific
timing mode, but for some reason, the board design prevents using this
mode (interferences on the DATA or CONTROL lines for example).

To me, this property would just serve as a limitation: if the chip
supports mode 5 but the board says that it supports up to mode 2, then
the implementation should stick to mode 2. ITOH, if the 5 is defined in
the DT, but the chip only supports up to mode 2, then mode 2 should be
used.

> 
> The reationale behind this is that it is impractical to list all specific 
> flash chips which actually support a given timing mode. Say another chip 
> comes out on the market either from an existing or a new manufacturer, 
> which correctly identifies itself using the ID bytes, but not using the 
> full ID. In order to support the speed of this device, we would need to 
> upgrade the kernel in the product. If we on the other hand have a hardware 
> specification that says that we only use flashes which support a certain 
> specified timing mode (because of memory bandwidth requirements), we can 
> simply put force-onfi-timing-mode = <2> in the DT, and it will work for 
> all flashes that meet the specifications, whether they match the full ID 
> or not.

Well, I don't think this is a good argument. If you want to support
advanced features, you'll still have to define some chip/vendor
specific implementation, and these will likely be assigned depending on
the full ID. So, in the end, if you want to have good support for a
NAND chip that is not ONFi or JEDEC compliant, you'll have to update
your kernel.

Also note that I'm trying to get rid of the full-id table, and replace
it by vendor detection/initialization [1], so that you can tweak
different things on a per-chip basis (and this includes the timing
mode).

> 
> For the case of a .dts file specifying a more general board which can be 
> populated with any flash chip, the property can be left out, and the 
> timing mode will then be determined using the ID and ONFi parameter page, 
> as applicable.

I'd like to leave as much as possible in the NAND
detection/initialization code, and this includes selecting the best
timing mode (based on JEDEC, ONFi, or vendor specific ID parsing).

Also remember that DT is supposed to be represent the HW blocks, not
their configuration.

> 
> Alternatively having this property as a proprietary one (i.e. 
> "evatronix,force-onfi-timing-mode") is an alternative, but I still wanted 
> to bring up the discussion for the general case.

No, please do not define a private property. I think I'd prefer to
have a generic property, but I'm still not convinced this is necessary.

Regards,

Boris


From boris.brezillon at free-electrons.com  Wed Oct 26 05:02:00 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Wed, 26 Oct 2016 14:02:00 +0200
Subject: [PATCH 1/4] of: Add device tree bindings for Evatronix
In-Reply-To: <20161026135241.63653c4f@bbrezillon>
References: <alpine.DEB.2.02.1606020946500.19416@lnxricardw1.se.axis.com>
 <20160603162207.0688c9e6@bbrezillon>
 <alpine.DEB.2.02.1606060757180.23377@lnxricardw1.se.axis.com>
 <20160608175018.16c88207@bbrezillon>
 <alpine.DEB.2.02.1606101641050.30757@lnxricardw1.se.axis.com>
 <20160610175454.327f51a2@bbrezillon>
 <alpine.DEB.2.02.1610261152170.9986@lnxricardw1.se.axis.com>
 <20161026135241.63653c4f@bbrezillon>
Message-ID: <20161026140200.27d9556b@bbrezillon>

On Wed, 26 Oct 2016 13:52:41 +0200
Boris Brezillon <boris.brezillon at free-electrons.com> wrote:

> Hi Ricard,
> 
> On Wed, 26 Oct 2016 13:27:00 +0200
> Ricard Wanderlof <ricard.wanderlof at axis.com> wrote:
> 
> > Hi Boris,
> > 
> > Juggling the rework of the Evatronix NAND flash driver with other projects 
> > I'm plodding on and will hopefully have something that can be reviewed in 
> > a few weeks' time.
> > 
> > In the meantime there is an issue which I want to bring up, regarding the 
> > timing configuration. Back in June we had this discussion, regarding my 
> > suggestion to put the raw values for the timing control registers in the 
> > IP in the DT:
> > 
> > On Fri, 10 Jun 2016, Boris Brezillon wrote:
> >   
> > > On Fri, 10 Jun 2016 17:35:24 +0200
> > > Ricard Wanderlof <ricard.wanderlof at axis.com> wrote:
> > >    
> > > > > > > > +		     TIME_SEQ_1, TIMINGS_ASYN, TIME_GEN_SEQ_0, TIME_GEN_SEQ_1,
> > > > > > > > +		     TIME_GEN_SEQ_2 and TIME_GEN_SEQ_3 registers, respectively.        
> > > > > > > 
> > > > > > > 
> > > > > > > Can this be extracted from the timing mode exposed by the NAND chip.
> > > > > > > IMO it shouldn't be defined in the DT.     
> > > >
> > > > [ ... ]
> > > >     
> > > > > Just because it's complicated to extract these information at the driver 
> > > > > level level doesn't mean you should put it in the DT. That's exactly the 
> > > > > opposite: the DT is supposed to encode the hardware representation, not 
> > > > > how you want to configure it.      
> > > > 
> > > > [ ... ]
> > > >     
> > > > > How about using a default/safe timing mode for now (ONFI timing mode 0
> > > > > should work for all NANDs).
> > > > > The only thing you'll have to do is retrieve the source clk rate and
> > > > > calculate timing register values accordingly. Or you can even assume
> > > > > you always have a 100MHz source clk and hardcode it in your driver.      
> > > > 
> > > > Yes, that is certainly possible of course, and the driver already has a 
> > > > hard-coded default setup for this case.
> > > > 
> > > > In that case though the driver could have pre-set setups for other ONFi 
> > > > modes, and we could have an _optional_ DT property to select them, the 
> > > > reason for that being in order to handle non-ONFi flashes whose timing 
> > > > cannot be gleaned from the device itself.
> > > > 
> > > > I.e. something like
> > > > 
> > > > evatronix,onfi-timing-mode = <2>;
> > > >     
> > > Actually this has been added to the nand_flash_dev structure, and it's
> > > called onfi_timing_mode_default.
> > > If you need a different timing, define a full ID entry for your NAND.    
> > 
> > In our products, we use 1, 2 and 4 Gbit SLC NAND flashes, some of which 
> > are ONFi complient and some not, depending on the manufacturer. For the 
> > non-ONFi flashes, the ones which we have looked at and which we specify in 
> > our products actually support ONFi mode 2. However, in practice, as part 
> > of the nand_scan_ident() procedure, the chip->onfi_timing_mode_default 
> > value is set to 0, because the EXTENDED_ID_NAND() macro used for these 
> > flashes doesn't set the timing mode to anything else. There are some full 
> > ID listings which apparently set a different timing mode for certain 
> > flashes (such as Toshiba TC58NVG0S3E).
> > 
> > What I would like to have in the device tree, either as a general mtd or 
> > proprietary property, is something like the above, possibly called 
> > something like force-onfi-timing-mode, which forcibly sets the timing mode 
> > of the hardware. When this property is not set, the timing mode used will 
> > default to onfi_timing_mode_default for non-ONFi flashes, or 
> > onfi_get_async_timing_mode() for ONFi flashes.  
> 
> I'm not against the addition of this onfi-timing-mode property, but not
> for the same reason. Your NAND might be able to support a specific
> timing mode, but for some reason, the board design prevents using this
> mode (interferences on the DATA or CONTROL lines for example).
> 
> To me, this property would just serve as a limitation: if the chip
> supports mode 5 but the board says that it supports up to mode 2, then
> the implementation should stick to mode 2. ITOH, if the 5 is defined in
> the DT, but the chip only supports up to mode 2, then mode 2 should be
> used.
> 
> > 
> > The reationale behind this is that it is impractical to list all specific 
> > flash chips which actually support a given timing mode. Say another chip 
> > comes out on the market either from an existing or a new manufacturer, 
> > which correctly identifies itself using the ID bytes, but not using the 
> > full ID. In order to support the speed of this device, we would need to 
> > upgrade the kernel in the product. If we on the other hand have a hardware 
> > specification that says that we only use flashes which support a certain 
> > specified timing mode (because of memory bandwidth requirements), we can 
> > simply put force-onfi-timing-mode = <2> in the DT, and it will work for 
> > all flashes that meet the specifications, whether they match the full ID 
> > or not.  
> 
> Well, I don't think this is a good argument. If you want to support
> advanced features, you'll still have to define some chip/vendor
> specific implementation, and these will likely be assigned depending on
> the full ID. So, in the end, if you want to have good support for a
> NAND chip that is not ONFi or JEDEC compliant, you'll have to update
> your kernel.
> 
> Also note that I'm trying to get rid of the full-id table, and replace
> it by vendor detection/initialization [1], so that you can tweak
> different things on a per-chip basis (and this includes the timing
> mode).

Oops, forgot to put the reference:

[1]http://lkml.iu.edu/hypermail/linux/kernel/1606.2/02892.html

> 
> > 
> > For the case of a .dts file specifying a more general board which can be 
> > populated with any flash chip, the property can be left out, and the 
> > timing mode will then be determined using the ID and ONFi parameter page, 
> > as applicable.  
> 
> I'd like to leave as much as possible in the NAND
> detection/initialization code, and this includes selecting the best
> timing mode (based on JEDEC, ONFi, or vendor specific ID parsing).
> 
> Also remember that DT is supposed to be represent the HW blocks, not
> their configuration.
> 
> > 
> > Alternatively having this property as a proprietary one (i.e. 
> > "evatronix,force-onfi-timing-mode") is an alternative, but I still wanted 
> > to bring up the discussion for the general case.  
> 
> No, please do not define a private property. I think I'd prefer to
> have a generic property, but I'm still not convinced this is necessary.
> 
> Regards,
> 
> Boris
> 
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/



From naga.sureshkumar.relli at xilinx.com  Wed Oct 26 05:11:23 2016
From: naga.sureshkumar.relli at xilinx.com (Naga Sureshkumar Relli)
Date: Wed, 26 Oct 2016 12:11:23 +0000
Subject: UBIFS LEB properties tree with odd addresses
In-Reply-To: <e7f63f72-0dc1-54f4-b94c-2efef3e7af6b@nod.at>
References: <DA6901612C71B84D91459DE817C418AE26E0016D@XAP-PVEXMBX01.xlnx.xilinx.com>
 <e7f63f72-0dc1-54f4-b94c-2efef3e7af6b@nod.at>
Message-ID: <DA6901612C71B84D91459DE817C418AE26E0069D@XAP-PVEXMBX01.xlnx.xilinx.com>

Hi Richard,

-----Original Message-----
From: Richard Weinberger [mailto:richard at nod.at] 
Sent: Wednesday, October 26, 2016 2:44 AM
To: Naga Sureshkumar Relli <nagasure at xilinx.com>; Christoph Hellwig <hch at infradead.org>
Cc: dwmw2 at infradead.org; computersforpeace at gmail.com; dedekind1 at gmail.com; adrian.hunter at intel.com; michal.simek at xilinx.com; Punnaiah Choudary Kalluri <punnaia at xilinx.com>; linux-mtd at lists.infradead.org; linux-kernel at vger.kernel.org; Boris Brezillon <boris.brezillon at free-electrons.com>
Subject: Re: UBIFS LEB properties tree with odd addresses

Naga Sureshkumar Relli,
>     Even bytes i.e. 0, 2, 4,... are transmitted on Lower Data Bus
>     Odd bytes i.e. 1, 3, 5,.. are transmitted on Upper Data Bus.

> But these details are hidden from UBI?

Yes, Our controller driver will take care of these byte striping.

> So for temporary hack we did the following change In fs/ubifs/lpt.c In 
> do_calc_lpt_geom(), added the following
> +       if (c->pnode_sz % 2)
> +               c->pnode_sz += 1; 
> +       if (c->ltab_sz % 2)
> +               c->ltab_sz += 1;
> 
> Please kindly suggest, I need your inputs, changing the pnode_sz and ltab_sz to even in lpt.c, will it impact on any others?

> Hmm, the calculations in lpt.c use basic properties of the MTD (number of blocks, etc...).
> Can you please double check which property causes the failure and also verify whether the MTD driver provides correct properties. i.e. page sizes, block size, number of blocks, ...

Yes, only pnode_sz and ltab_sz are odd values

And MTD info, here are my logs
In Single Flash mode:
Mtd->erasesize = 64KiB
Mtd->size = 64MiB
Mtd->numeraseregions = 0
Nor->pagesize = 256

In Dual parallel mode:
Mtd->erasesize = 128KiB
Mtd->size = 128MiB
Mtd->numeraseregions = 0
Nor->pagesize = 512

Thanks,
Naga Sureshkumar Relli


From Sanjeev_Chugh at mentor.com  Wed Oct 26 05:26:25 2016
From: Sanjeev_Chugh at mentor.com (Chugh, Sanjeev)
Date: Wed, 26 Oct 2016 12:26:25 +0000
Subject: [PATCH 2/2] ubi: attach: do not return -EINVAL if the
 mtd->numeraseregions is 1
In-Reply-To: <BEFE8A70F8F03B42BC5848A2E783B9E950AC8413@EU-MBX-03.mgc.mentorg.com>
References: <1469440019-29358-1-git-send-email-rajeev_kumar@mentor.com>
 <1469440019-29358-2-git-send-email-rajeev_kumar@mentor.com>
 <5795EA8B.2040209@nod.at> <20160729182449.GA124841@google.com>
 <1470292252.2311.48.camel@gmail.com>
 <BEFE8A70F8F03B42BC5848A2E783B9E950AC8413@EU-MBX-03.mgc.mentorg.com>
Message-ID: <5abe8a4ea1cc4abfa6a34f644ebec262@svr-ies-mbx-01.mgc.mentorg.com>

>-----Original Message-----
>From: linux-mtd [mailto:linux-mtd-bounces at lists.infradead.org] On Behalf Of
>Chugh, Sanjeev
>Sent: Friday, September 23, 2016 4:51 PM
>To: dedekind1 at gmail.com; Brian Norris; Richard Weinberger
>Cc: linux-mtd at lists.infradead.org; dwmw2 at infradead.org;
>stable at vger.kernel.org
>Subject: RE: [PATCH 2/2] ubi: attach: do not return -EINVAL if the mtd-
>>numeraseregions is 1
>
>Hello Brian, Artem,
>
>Are you suggesting that this change be documented instead. Note that we are
>using NOR flash devices for our testing as you asked.
>
>Can I request you to please clarify on acceptance of this patch ?
>
>Thanks
>Sanjeev
>
>>-----Original Message-----
>>From: Artem Bityutskiy [mailto:dedekind1 at gmail.com]
>>Sent: Thursday, August 04, 2016 12:01 PM
>>To: Brian Norris; Richard Weinberger
>>Cc: Rajeev Kumar; dwmw2 at infradead.org; linux-mtd at lists.infradead.org;
>>stable at vger.kernel.org
>>Subject: Re: [PATCH 2/2] ubi: attach: do not return -EINVAL if the mtd-
>>>numeraseregions is 1
>>
>>On Fri, 2016-07-29 at 11:24 -0700, Brian Norris wrote:
>>> (Artem, any opinions, since you had the most opinion last time this
>>> came
>>> up?)
>>
>>Hi Brian,
>>
>>well, I do not have strong opinion. That UBI translates to "I do not know how to
>>deal with multiple regions", nothing else.
>>
>>I think this was my understanding of numeraseregions
>>
>>1. numaraseregions=0: no regions, just uniform flash.
>>
>>2. numeraseregions=1: basically same as above, but friendlier to the region-
>>aware software. Indeed, if I care about regions, I do not want to handle the
>>special case of numerasereions=0, I want a common case with
>>numerasereionts>0.
>>
>>Or to put it this way, from the drivers' writer POW:
>>
>>numaraseregions=0 - do not know anything about regions, do not care.
>>Also pre-regions dirivers, old stuff
>>
>>numeraseregions=1 - I want my driver to be ideal. Non-aware SW won't look to
>>the regions stuff, the aware SW will work nicely.
>>
>>So my take is: ban numeraseregions=1 if you feel like, but I recommend to just
>>document the 0 (don't care/legacy) and 1 (same as 0, but care) and allow for
>>both.
>>
>>Artem.
>______________________________________________________
>Linux MTD discussion mailing list
>http://lists.infradead.org/mailman/listinfo/linux-mtd/

Hello Brian, Artem, etc. al.

I would really appreciate if you clarify what's your opinion on the patch. I would like to close the thread if it's not going to be accepted.

Or I would try making further changes but I need inputs.

Thanks in advance.

-Sanjeev


From ricard.wanderlof at axis.com  Wed Oct 26 05:31:53 2016
From: ricard.wanderlof at axis.com (Ricard Wanderlof)
Date: Wed, 26 Oct 2016 14:31:53 +0200
Subject: [PATCH 1/4] of: Add device tree bindings for Evatronix
In-Reply-To: <20161026135241.63653c4f@bbrezillon>
References: <alpine.DEB.2.02.1606020946500.19416@lnxricardw1.se.axis.com>
 <20160603162207.0688c9e6@bbrezillon>
 <alpine.DEB.2.02.1606060757180.23377@lnxricardw1.se.axis.com>
 <20160608175018.16c88207@bbrezillon>
 <alpine.DEB.2.02.1606101641050.30757@lnxricardw1.se.axis.com>
 <20160610175454.327f51a2@bbrezillon>
 <alpine.DEB.2.02.1610261152170.9986@lnxricardw1.se.axis.com>
 <20161026135241.63653c4f@bbrezillon>
Message-ID: <alpine.DEB.2.02.1610261359290.9986@lnxricardw1.se.axis.com>


Hi Boris,

On Wed, 26 Oct 2016, Boris Brezillon wrote:

> On Wed, 26 Oct 2016 13:27:00 +0200
> Ricard Wanderlof <ricard.wanderlof at axis.com> wrote:
>
> > > > 
> > > > evatronix,onfi-timing-mode = <2>;
> > > >   
> > [ ... ]
> > In our products, we use 1, 2 and 4 Gbit SLC NAND flashes, some of which 
> > are ONFi complient and some not, depending on the manufacturer. For the 
> > non-ONFi flashes, the ones which we have looked at and which we specify in 
> > our products actually support ONFi mode 2. However, in practice, as part 
> > of the nand_scan_ident() procedure, the chip->onfi_timing_mode_default 
> > value is set to 0, because the EXTENDED_ID_NAND() macro used for these 
> > flashes doesn't set the timing mode to anything else. There are some full 
> > ID listings which apparently set a different timing mode for certain 
> > flashes (such as Toshiba TC58NVG0S3E).
> > 
> > What I would like to have in the device tree, either as a general mtd or 
> > proprietary property, is something like the above, possibly called 
> > something like force-onfi-timing-mode, which forcibly sets the timing mode 
> > of the hardware. When this property is not set, the timing mode used will 
> > default to onfi_timing_mode_default for non-ONFi flashes, or 
> > onfi_get_async_timing_mode() for ONFi flashes.
> 
> I'm not against the addition of this onfi-timing-mode property, but not
> for the same reason. Your NAND might be able to support a specific
> timing mode, but for some reason, the board design prevents using this
> mode (interferences on the DATA or CONTROL lines for example).
> 
> To me, this property would just serve as a limitation: if the chip
> supports mode 5 but the board says that it supports up to mode 2, then
> the implementation should stick to mode 2. ITOH, if the 5 is defined in
> the DT, but the chip only supports up to mode 2, then mode 2 should be
> used.

Yes, I remember you had that suggestion back in June as well. That would 
be more of a 'restrict-onfi-timing-mode' that sets the maximum speed to be 
used. I can see the use of that too, but that's not what I'm talking about 
here of course. Although the reason is the same: it sets up something that 
cannot be determined by probing.

> > The reationale behind this is that it is impractical to list all specific 
> > flash chips which actually support a given timing mode. Say another chip 
> > comes out on the market either from an existing or a new manufacturer, 
> > which correctly identifies itself using the ID bytes, but not using the 
> > full ID. In order to support the speed of this device, we would need to 
> > upgrade the kernel in the product. If we on the other hand have a hardware 
> > specification that says that we only use flashes which support a certain 
> > specified timing mode (because of memory bandwidth requirements), we can 
> > simply put force-onfi-timing-mode = <2> in the DT, and it will work for 
> > all flashes that meet the specifications, whether they match the full ID 
> > or not.
> 
> Well, I don't think this is a good argument. If you want to support
> advanced features, you'll still have to define some chip/vendor
> specific implementation, and these will likely be assigned depending on
> the full ID. So, in the end, if you want to have good support for a
> NAND chip that is not ONFi or JEDEC compliant, you'll have to update
> your kernel.

It's true that some flashes have advanced features, such as built-in ECC, 
which would be nice to support, however, our experience has been that such 
features are very vendor-specific, and we try to avoid avoid using them as 
it would tie us to a specific flash chip vendor.

However, mildly accelerated chip timing (i.e. ONFi mode 2) I wouldn't call 
an advanced feature, and it seems to be supported by all of the chips in 
the 1..4 Gb range that we've seen, although I wouldn't be so bold and go 
so far as to say that I know all available flash chips (at least in this 
size range) support that mode. That's why I'm reluctant to suggest 
changing the entries for these flashes in the table in nand_ids.c, which 
would be another alternative. And if we did make that change, it might 
cause problems in systems which currently use onfi_timing_mode_default if 
the timing suddenly becomes faster after a kernel update. Although, at 
least looking at the 4.8 tree I'm using for development, it's only the 
sunxi NAND driver which uses it, so I guess it would be alright to change 
as it is not in widespread use yet? [**]

I was looking at the timing specs for a range of 2 and 4 Gb flashes from a 
number of manufacturers a while back, and the timing specificiations were 
surprisingly similar, even across the non-ONFi manufacturers.

> Also note that I'm trying to get rid of the full-id table, and replace
> it by vendor detection/initialization [1], so that you can tweak
> different things on a per-chip basis (and this includes the timing
> mode).

I'm assuming [1] refers to https://lkml.org/lkml/2016/5/27/264 which you 
have referenced before. Has this patch set been applied yet? I did a 
cursory search for it in the kernel commit log but couldn't find it, so I 
haven't had a closer look at it since I can't really make use of any 
features contained therein yet if that is so.

> > For the case of a .dts file specifying a more general board which can be 
> > populated with any flash chip, the property can be left out, and the 
> > timing mode will then be determined using the ID and ONFi parameter page, 
> > as applicable.
> 
> I'd like to leave as much as possible in the NAND
> detection/initialization code, and this includes selecting the best
> timing mode (based on JEDEC, ONFi, or vendor specific ID parsing).
> 
> Also remember that DT is supposed to be represent the HW blocks, not
> their configuration.

Well, in the case of the timing mode, it does represent the external chip 
that is conected, in terms of information that apparently cannot be 
probed, in a similar manner that there are properties to specify how a 
given pin on an audio codec is connected, for instance. One minor tweak 
would be to have the property specify not the specific timing mode to use, 
but range of timing modes supported by the chip (i.e. a vector of bits 
like ONFI_TIMING_MODE_0 etc. However, in practice in a given setup, one 
would only want to use the fastest mode anyway, so there'd be little point 
in specifying any other (except mode 0 as it is the default).

[**] A related question is what values this parameter is supposed to have 
in the ID table. Is it the numeric timing mode (i.e. 2 for mode 2), or is 
it a bit vector which is an or of ONFI_TIMING_MODE_0, etc ? The sunxi 
driver seems to presume the latter, whereas the entries in nand_ids.c 
would seem to imply the former, with values such as 2 (for the 
TC58NVG0S3E) and 4 (for the H27UCG8T2ATR-BC) - surely these chips support 
more than a single timing mode?

/Ricard
-- 
Ricard Wolf Wanderl?f                           ricardw(at)axis.com
Axis Communications AB, Lund, Sweden            www.axis.com
Phone +46 46 272 2016                           Fax +46 46 13 61 30


From boris.brezillon at free-electrons.com  Wed Oct 26 06:05:57 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Wed, 26 Oct 2016 15:05:57 +0200
Subject: [PATCH 1/4] of: Add device tree bindings for Evatronix
In-Reply-To: <alpine.DEB.2.02.1610261359290.9986@lnxricardw1.se.axis.com>
References: <alpine.DEB.2.02.1606020946500.19416@lnxricardw1.se.axis.com>
 <20160603162207.0688c9e6@bbrezillon>
 <alpine.DEB.2.02.1606060757180.23377@lnxricardw1.se.axis.com>
 <20160608175018.16c88207@bbrezillon>
 <alpine.DEB.2.02.1606101641050.30757@lnxricardw1.se.axis.com>
 <20160610175454.327f51a2@bbrezillon>
 <alpine.DEB.2.02.1610261152170.9986@lnxricardw1.se.axis.com>
 <20161026135241.63653c4f@bbrezillon>
 <alpine.DEB.2.02.1610261359290.9986@lnxricardw1.se.axis.com>
Message-ID: <20161026150557.587a7387@bbrezillon>

On Wed, 26 Oct 2016 14:31:53 +0200
Ricard Wanderlof <ricard.wanderlof at axis.com> wrote:

> Hi Boris,
> 
> On Wed, 26 Oct 2016, Boris Brezillon wrote:
> 
> > On Wed, 26 Oct 2016 13:27:00 +0200
> > Ricard Wanderlof <ricard.wanderlof at axis.com> wrote:
> >  
> > > > > 
> > > > > evatronix,onfi-timing-mode = <2>;
> > > > >     
> > > [ ... ]
> > > In our products, we use 1, 2 and 4 Gbit SLC NAND flashes, some of which 
> > > are ONFi complient and some not, depending on the manufacturer. For the 
> > > non-ONFi flashes, the ones which we have looked at and which we specify in 
> > > our products actually support ONFi mode 2. However, in practice, as part 
> > > of the nand_scan_ident() procedure, the chip->onfi_timing_mode_default 
> > > value is set to 0, because the EXTENDED_ID_NAND() macro used for these 
> > > flashes doesn't set the timing mode to anything else. There are some full 
> > > ID listings which apparently set a different timing mode for certain 
> > > flashes (such as Toshiba TC58NVG0S3E).
> > > 
> > > What I would like to have in the device tree, either as a general mtd or 
> > > proprietary property, is something like the above, possibly called 
> > > something like force-onfi-timing-mode, which forcibly sets the timing mode 
> > > of the hardware. When this property is not set, the timing mode used will 
> > > default to onfi_timing_mode_default for non-ONFi flashes, or 
> > > onfi_get_async_timing_mode() for ONFi flashes.  
> > 
> > I'm not against the addition of this onfi-timing-mode property, but not
> > for the same reason. Your NAND might be able to support a specific
> > timing mode, but for some reason, the board design prevents using this
> > mode (interferences on the DATA or CONTROL lines for example).
> > 
> > To me, this property would just serve as a limitation: if the chip
> > supports mode 5 but the board says that it supports up to mode 2, then
> > the implementation should stick to mode 2. ITOH, if the 5 is defined in
> > the DT, but the chip only supports up to mode 2, then mode 2 should be
> > used.  
> 
> Yes, I remember you had that suggestion back in June as well. That would 
> be more of a 'restrict-onfi-timing-mode' that sets the maximum speed to be 
> used. I can see the use of that too, but that's not what I'm talking about 
> here of course. Although the reason is the same: it sets up something that 
> cannot be determined by probing.
> 
> > > The reationale behind this is that it is impractical to list all specific 
> > > flash chips which actually support a given timing mode. Say another chip 
> > > comes out on the market either from an existing or a new manufacturer, 
> > > which correctly identifies itself using the ID bytes, but not using the 
> > > full ID. In order to support the speed of this device, we would need to 
> > > upgrade the kernel in the product. If we on the other hand have a hardware 
> > > specification that says that we only use flashes which support a certain 
> > > specified timing mode (because of memory bandwidth requirements), we can 
> > > simply put force-onfi-timing-mode = <2> in the DT, and it will work for 
> > > all flashes that meet the specifications, whether they match the full ID 
> > > or not.  
> > 
> > Well, I don't think this is a good argument. If you want to support
> > advanced features, you'll still have to define some chip/vendor
> > specific implementation, and these will likely be assigned depending on
> > the full ID. So, in the end, if you want to have good support for a
> > NAND chip that is not ONFi or JEDEC compliant, you'll have to update
> > your kernel.  
> 
> It's true that some flashes have advanced features, such as built-in ECC, 
> which would be nice to support, however, our experience has been that such 
> features are very vendor-specific, and we try to avoid avoid using them as 
> it would tie us to a specific flash chip vendor.
> 
> However, mildly accelerated chip timing (i.e. ONFi mode 2) I wouldn't call 
> an advanced feature, and it seems to be supported by all of the chips in 
> the 1..4 Gb range that we've seen, although I wouldn't be so bold and go 
> so far as to say that I know all available flash chips (at least in this 
> size range) support that mode. That's why I'm reluctant to suggest 
> changing the entries for these flashes in the table in nand_ids.c, which 
> would be another alternative. And if we did make that change, it might 
> cause problems in systems which currently use onfi_timing_mode_default if 
> the timing suddenly becomes faster after a kernel update. Although, at 
> least looking at the 4.8 tree I'm using for development, it's only the 
> sunxi NAND driver which uses it, so I guess it would be alright to change 
> as it is not in widespread use yet? [**]

I would definitely prefer this approach.

> 
> I was looking at the timing specs for a range of 2 and 4 Gb flashes from a 
> number of manufacturers a while back, and the timing specificiations were 
> surprisingly similar, even across the non-ONFi manufacturers.

That's not so surprising, NAND vendors try to compete with each others,
and they are pretty much all using the same technology, which explains
why for a given generation of chip (which is usually related to a chip
size), the timings are close.

> 
> > Also note that I'm trying to get rid of the full-id table, and replace
> > it by vendor detection/initialization [1], so that you can tweak
> > different things on a per-chip basis (and this includes the timing
> > mode).  
> 
> I'm assuming [1] refers to https://lkml.org/lkml/2016/5/27/264 which you 
> have referenced before.

Yes.

> Has this patch set been applied yet?

Nope, not yet.

> I did a 
> cursory search for it in the kernel commit log but couldn't find it, so I 
> haven't had a closer look at it since I can't really make use of any 
> features contained therein yet if that is so.

I was waiting for more reviews/tests, but it did not happen. I might
consider applying the last version even if nobody reviewed it, but I
fear it will break some platforms, hence my hesitations to apply it
without any external tests/reviews.

> 
> > > For the case of a .dts file specifying a more general board which can be 
> > > populated with any flash chip, the property can be left out, and the 
> > > timing mode will then be determined using the ID and ONFi parameter page, 
> > > as applicable.  
> > 
> > I'd like to leave as much as possible in the NAND
> > detection/initialization code, and this includes selecting the best
> > timing mode (based on JEDEC, ONFi, or vendor specific ID parsing).
> > 
> > Also remember that DT is supposed to be represent the HW blocks, not
> > their configuration.  
> 
> Well, in the case of the timing mode, it does represent the external chip 
> that is conected, in terms of information that apparently cannot be 
> probed, in a similar manner that there are properties to specify how a 
> given pin on an audio codec is connected, for instance. One minor tweak 
> would be to have the property specify not the specific timing mode to use, 
> but range of timing modes supported by the chip (i.e. a vector of bits 
> like ONFI_TIMING_MODE_0 etc. However, in practice in a given setup, one 
> would only want to use the fastest mode anyway, so there'd be little point 
> in specifying any other (except mode 0 as it is the default).
> 
> [**] A related question is what values this parameter is supposed to have 
> in the ID table. Is it the numeric timing mode (i.e. 2 for mode 2), or is 
> it a bit vector which is an or of ONFI_TIMING_MODE_0, etc ?

It's supposed to be the highest supported mode, not a bitmap
containing all the supported modes.

> The sunxi 
> driver seems to presume the latter, whereas the entries in nand_ids.c 
> would seem to imply the former, with values such as 2 (for the 
> TC58NVG0S3E) and 4 (for the H27UCG8T2ATR-BC) - surely these chips support 
> more than a single timing mode?

Hm, no it's not. As can be seen here [1], if the NAND is not ONFi, then
we're using the onfi_timing_mode_default value, which is encoding the
highest supported mode. The other case is when the chip is ONFi
compliant, and in this case, the timing_mode field in exposing
supported modes as a bitmap.

One last thing, we recently introduced a generic timing selection/setup
infrastructure [2] to avoid duplicating the code pointed here [1] in all
drivers. It's been merged in 4.9, and that'd would be better to use
this infrastructure in your driver.

[1]http://lxr.free-electrons.com/source/drivers/mtd/nand/sunxi_nand.c#L1723
[2]https://www.spinics.net/lists/arm-kernel/msg532007.html



From lee.jones at linaro.org  Wed Oct 26 06:50:09 2016
From: lee.jones at linaro.org (Lee Jones)
Date: Wed, 26 Oct 2016 14:50:09 +0100
Subject: [PATCH 01/10] mfd: Juniper PTXPMB CPLD Multi-function core driver
In-Reply-To: <1475853451-22121-2-git-send-email-pantelis.antoniou@konsulko.com>
References: <1475853451-22121-1-git-send-email-pantelis.antoniou@konsulko.com>
 <1475853451-22121-2-git-send-email-pantelis.antoniou@konsulko.com>
Message-ID: <20161026135009.GA13127@dell>

On Fri, 07 Oct 2016, Pantelis Antoniou wrote:

> From: Guenter Roeck <groeck at juniper.net>
> 
> Add Juniper's PTXPMB FPGA CPLD driver. Those FPGAs
> are present in Juniper's PTX series of routers.
> 
> There are two variants, the original which is found on the
> PTXPMB_P2020, PTXPMB_P2020_SPMB based on a Freescale P2020 SoC,
> and PTXPMB_P5040 based on a Freescale P5040 SoC.
> 
> The new variant NGPMB is present on a new line of x86 based
> boards (currently only the Gladiator FPC).
> 
> Both variants provide a hardware watchdog, i2c mux and a
> gpio block, with the i2c mux block being different.
> 
> Signed-off-by: Debjit Ghosh <dghosh at juniper.net>
> Signed-off-by: Georgi Vlaev <gvlaev at juniper.net>
> Signed-off-by: Guenter Roeck <groeck at juniper.net>
> Signed-off-by: JawaharBalaji Thirumalaisamy <jawaharb at juniper.net>
> Signed-off-by: Rajat Jain <rajatjain at juniper.net>
> Signed-off-by: Tom Kavanagh <tkavanagh at juniper.net>
> [Ported from Juniper kernel]
> Signed-off-by: Pantelis Antoniou <pantelis.antoniou at konsulko.com>
> ---
>  drivers/mfd/Kconfig             |  15 ++
>  drivers/mfd/Makefile            |   1 +
>  drivers/mfd/ptxpmb-cpld-core.c  | 406 ++++++++++++++++++++++++++++++++++++++++
>  include/linux/mfd/ptxpmb_cpld.h | 140 ++++++++++++++
>  4 files changed, 562 insertions(+)
>  create mode 100644 drivers/mfd/ptxpmb-cpld-core.c
>  create mode 100644 include/linux/mfd/ptxpmb_cpld.h
> 
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 2caf7e9..438666a 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -1340,6 +1340,21 @@ config TWL4030_POWER
>  	  and load scripts controlling which resources are switched off/on
>  	  or reset when a sleep, wakeup or warm reset event occurs.
>  
> +config MFD_JUNIPER_CPLD
> +	tristate "Juniper PTX PMB CPLD"
> +	depends on (PTXPMB_COMMON || JNX_PTX_NGPMB)
> +	default y if (PTXPMB_COMMON || JNX_PTX_NGPMB)

Nit: I'd like to see the default line above 'depends|select'.

> +	select MFD_CORE
> +	select I2C_MUX_PTXPMB
> +	select GPIO_PTXPMB_CPLD
> +	select JNX_PTXPMB_WDT

I don't think these should be selected blindly from here.

> +	help
> +	  Select this to enable the PTX PMB CPLD multi-function kernel driver

What is PTX PMB?

> +	  for the applicable Juniper platforms.

What applicable platforms?  Might wish to consider removing this part.

It would also be nice to mention what functionality this provides and
little more info besides "this enables".

> +	  This driver can be built as a module. If built as a module it will be
> +	  called "ptxpmb-cpld"
> +
>  config MFD_TWL4030_AUDIO
>  	bool "TI TWL4030 Audio"
>  	depends on TWL4030_CORE
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index 2bf6a1a..62decc9 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -148,6 +148,7 @@ obj-$(CONFIG_AB3100_CORE)	+= ab3100-core.o
>  obj-$(CONFIG_AB3100_OTP)	+= ab3100-otp.o
>  obj-$(CONFIG_AB8500_DEBUG)	+= ab8500-debugfs.o
>  obj-$(CONFIG_AB8500_GPADC)	+= ab8500-gpadc.o
> +obj-$(CONFIG_MFD_JUNIPER_CPLD)	+= ptxpmb-cpld-core.o

Is there only ever going to be one Juniper CPLD?

>  obj-$(CONFIG_MFD_DB8500_PRCMU)	+= db8500-prcmu.o
>  # ab8500-core need to come after db8500-prcmu (which provides the channel)
>  obj-$(CONFIG_AB8500_CORE)	+= ab8500-core.o ab8500-sysctrl.o
> diff --git a/drivers/mfd/ptxpmb-cpld-core.c b/drivers/mfd/ptxpmb-cpld-core.c
> new file mode 100644
> index 0000000..18e60a4
> --- /dev/null
> +++ b/drivers/mfd/ptxpmb-cpld-core.c
> @@ -0,0 +1,406 @@
> +/*
> + * Juniper PTX PMB CPLD multi-function core driver

Please expand on what a PTX PMB is.

> + * Copyright (C) 2012 Juniper Networks

This needs updating.

Why is this required now and not in the past 4 years?

> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *

Superfluous line.

> + */
> +
> +#include <linux/delay.h>
> +#include <linux/sched.h>
> +#include <linux/module.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/dmi.h>
> +#include <linux/mfd/core.h>
> +#include <linux/of_device.h>
> +#include <linux/mfd/ptxpmb_cpld.h>
> +#include <linux/jnx/jnx-subsys.h>
> +#include <linux/jnx/board_ids.h>

Alphabetical.

> +struct pmb_cpld_core {
> +	struct device		*dev;
> +	struct pmb_boot_cpld __iomem *cpld;

This isn't how we usually handle IO registers.

> +	spinlock_t		lock;
> +	int			irq;
> +	wait_queue_head_t	wqh;

This is not a very good variable name.

> +};
> +
> +static const struct of_device_id pmb_cpld_of_ids[] = {
> +	{ .compatible = "jnx,ptxpmb-cpld", .data = (void *)CPLD_TYPE_PTXPMB },
> +	{ .compatible = "jnx,ngpmb-bcpld", .data = (void *)CPLD_TYPE_NGPMB },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, pmb_cpld_of_ids);

Place this just before it's about to be used.  Since you're matching
on this, I would expect it be be located just above .probe().

> +static struct dmi_system_id gld_2t_dmi_data[] = {
> +	{
> +		.ident = "Juniper Networks Gladiator 2T FPC",
> +		.matches = {
> +			    DMI_MATCH(DMI_SYS_VENDOR, "Juniper Networks Inc."),
> +			    DMI_MATCH(DMI_PRODUCT_NAME, "0BF9"),
> +			},
> +	},
> +	{},
> +};
> +MODULE_DEVICE_TABLE(dmi, gld_2t_dmi_data);
> +
> +static struct dmi_system_id gld_3t_dmi_data[] = {
> +	{
> +		.ident = "Juniper Networks Gladiator 3T FPC",
> +		.matches = {
> +			    DMI_MATCH(DMI_SYS_VENDOR, "Juniper Networks Inc."),
> +			    DMI_MATCH(DMI_PRODUCT_NAME, "0BFA"),
> +			},
> +	},
> +	{},
> +};
> +MODULE_DEVICE_TABLE(dmi, gld_3t_dmi_data);
> +
> +static int ptxpmb_cpld_get_master(void *data)
> +{
> +	struct pmb_cpld_core *cpld = data;
> +	u8 s1;

s1 is not a good variable name.

> +	s1 = ioread8(&cpld->cpld->i2c_host_sel) & CPLD_I2C_HOST_MSTR_MASK;

Why aren't you using readb()?

> +	if ((s1 & CPLD_I2C_HOST0_MSTR) == CPLD_I2C_HOST0_MSTR)
> +		return 0;

Define this.

> +	if ((s1 & CPLD_I2C_HOST1_MSTR) == CPLD_I2C_HOST1_MSTR)
> +		return 1;

And this.

> +	return -1;

Why aren't you using Linux error numbers.

> +}
> +
> +static int ngpmb_cpld_get_master(void *data)
> +{
> +	struct pmb_cpld_core *cpld = data;
> +
> +	if (ioread8(&cpld->cpld->baseboard_status1) & NGPMB_MASTER_SELECT)
> +		return 1;
> +	else
> +		return 0;
> +}
> +
> +static irqreturn_t pmb_cpld_core_interrupt(int irq, void *dev_data)
> +{
> +	struct pmb_cpld_core *cpld = dev_data;
> +
> +	pr_info("pmb_cpld_core_interrupt %d\n", irq);

This should be dgb at most, but doesn't really have any place in
Mainline code.  Please remove it.

> +	spin_lock(&cpld->wqh.lock);
> +
> +	/* clear interrupt, wake up any handlers */
> +	wake_up_locked(&cpld->wqh);
> +
> +	spin_unlock(&cpld->wqh.lock);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static struct resource pmb_cpld_resources[] = {
> +	{
> +		.start	= 0,
> +		.end	= sizeof(struct pmb_boot_cpld) - 1,

Define these properly.

> +		.flags	= IORESOURCE_MEM,
> +	},
> +};

Use the DEFINE_RES_*() helpers.

> +static struct mfd_cell pmb_cpld_cells[] = {
> +	{
> +		.name = "jnx-ptxpmb-wdt",
> +		.num_resources = ARRAY_SIZE(pmb_cpld_resources),
> +		.resources = pmb_cpld_resources,
> +		.of_compatible = "jnx,ptxpmb-wdt",
> +	},
> +	{
> +		.name = "i2c-mux-ptxpmb-cpld",
> +		.num_resources = ARRAY_SIZE(pmb_cpld_resources),
> +		.resources = pmb_cpld_resources,
> +		.of_compatible = "jnx,i2c-mux-ptxpmb-cpld",
> +	},
> +	{
> +		.name = "gpio-ptxpmb-cpld",
> +		.num_resources = ARRAY_SIZE(pmb_cpld_resources),
> +		.resources = pmb_cpld_resources,
> +		.of_compatible = "jnx,gpio-ptxpmb-cpld",
> +	},
> +};
> +
> +static struct mfd_cell ngpmb_cpld_cells[] = {
> +	{
> +		.name = "jnx-ptxpmb-wdt",
> +		.num_resources = ARRAY_SIZE(pmb_cpld_resources),
> +		.resources = pmb_cpld_resources,
> +		.of_compatible = "jnx,ptxpmb-wdt",
> +	},
> +	{
> +		.name = "i2c-mux-ngpmb-bcpld",
> +		.num_resources = ARRAY_SIZE(pmb_cpld_resources),
> +		.resources = pmb_cpld_resources,
> +		.of_compatible = "jnx,i2c-mux-ngpmb-bcpld",
> +	},
> +	{
> +		.name = "gpio-ptxpmb-cpld",
> +		.num_resources = ARRAY_SIZE(pmb_cpld_resources),
> +		.resources = pmb_cpld_resources,
> +		.of_compatible = "jnx,gpio-ptxpmb-cpld",
> +	},
> +};
> +
> +static void cpld_ngpmb_init(struct pmb_cpld_core *cpld,
> +			    struct jnx_chassis_info *chinfo,
> +			    struct jnx_card_info *cinfo)
> +{
> +	u8 s1, s2, val, chassis;

s1 and s1 are not good variable names.

status1 and status2 would be better.

> +	s1 = ioread8(&cpld->cpld->baseboard_status1);
> +	s2 = ioread8(&cpld->cpld->baseboard_status2);
> +	chassis = (ioread8(&cpld->cpld->board.ngpmb.chassis_type)
> +		   & NGPMB_CHASSIS_TYPE_MASK) >> NGPMB_CHASSIS_TYPE_LSB;
> +
> +	dev_info(cpld->dev, "Revision 0x%02X chassis type %s (0x%02X)\n",
> +		 ioread8(&cpld->cpld->cpld_rev),
> +		 chassis == NGPMB_CHASSIS_TYPE_POLARIS ? "PTX-1000" :
> +		 chassis == NGPMB_CHASSIS_TYPE_HENDRICKS ? "PTX-3000" :
> +		 "Unknown", chassis);
> +
> +	/* Only the Gladiator 2t/3t FPC */
> +	if (dmi_check_system(gld_2t_dmi_data) ||
> +	    dmi_check_system(gld_3t_dmi_data)) {
> +		/* Take SAM FPGA out of reset */
> +		val = ioread8(&cpld->cpld->gpio_2);
> +		iowrite8(val | NGPMB_GPIO2_TO_BASEBRD_LSB, &cpld->cpld->gpio_2);
> +		mdelay(10);
> +	} else {
> +		/*
> +		 * Get the PAM FPGA out of reset,
> +		 * and wait for 100ms as per HW manual
> +		 */
> +		val = ioread8(&cpld->cpld->reset);
> +		iowrite8(val & ~NGPMB_PCIE_OTHER_RESET, &cpld->cpld->reset);
> +		mdelay(100);
> +	}
> +
> +	/* No Card / Chassis info needed in stand alone mode */
> +	if (!(s1 & NGPMB_PMB_STANDALONE) || !(s1 & NGPMB_BASEBRD_STANDALONE))
> +		return;
> +
> +	cinfo->type = JNX_BOARD_TYPE_FPC;
> +	cinfo->slot = (s1 & NGPMB_BASEBRD_SLOT_MASK) >> NGPMB_BASEBRD_SLOT_LSB;
> +
> +	if (((s2 & NGPMB_BASEBRD_TYPE_MASK) >> NGPMB_BASEBRD_TYPE_LSB) !=
> +	    NGPMB_BASEBRD_TYPE_MX) {
> +		if (dmi_check_system(gld_2t_dmi_data))
> +			cinfo->assembly_id = JNX_ID_GLD_2T_FPC;
> +		else if (dmi_check_system(gld_3t_dmi_data))
> +			cinfo->assembly_id = JNX_ID_GLD_3T_FPC;
> +		else
> +			cinfo->assembly_id = JNX_ID_POLARIS_MLC;
> +	}
> +
> +	/*
> +	 * Multi chassis configuration. These bits are not
> +	 * valid for Gladiator.
> +	 */
> +	if (!(dmi_check_system(gld_2t_dmi_data) ||
> +	      dmi_check_system(gld_3t_dmi_data))) {
> +		if (ioread8(&cpld->cpld->board.ngpmb.sys_config) &
> +		    NGPMB_SYS_CONFIG_MULTI_CHASSIS) {
> +			chinfo->multichassis = 1;

"true"?

> +			chinfo->chassis_no =

"no" is ambiguous.

chassis_id?

> +			ioread8(&cpld->cpld->board.ngpmb.chassis_id);
> +		}
> +	}
> +
> +	switch (chassis) {
> +	case NGPMB_CHASSIS_TYPE_POLARIS:
> +		chinfo->platform = JNX_PRODUCT_POLARIS;
> +		break;
> +	case NGPMB_CHASSIS_TYPE_HENDRICKS:
> +		chinfo->platform = JNX_PRODUCT_HENDRICKS;
> +		break;
> +	default:
> +		chinfo->platform = 0;

Define this.

> +		break;
> +	};
> +	chinfo->get_master = ngpmb_cpld_get_master;

Where is get_master() called from?

I think you're probably better off exporting the call, rather than
using call-backs.

> +}
> +
> +static void cpld_ptxpmb_init(struct pmb_cpld_core *cpld,
> +			     struct jnx_chassis_info *chinfo,
> +			     struct jnx_card_info *cinfo)
> +{
> +	u8 s1, s2;
> +
> +	s1 = ioread8(&cpld->cpld->baseboard_status1);
> +	s2 = ioread8(&cpld->cpld->baseboard_status2);
> +
> +	dev_info(cpld->dev, "Revision 0x%02x carrier type 0x%x [%s]\n",
> +		 ioread8(&cpld->cpld->cpld_rev), s2 & 0x1f,
> +		 (s1 & 0X3F) == 0X1F ? "standalone"
> +				     : (s2 & 0x10) ? "FPC" : "SPMB");
> +
> +	if ((s1 & 0x3f) != 0x1f) {	/* not standalone */

Define these, and all the other magic numbers in this driver.

I won't say "define this" again in this review.

> +		cinfo->slot = s1 & 0x0f;
> +		if (s2 & 0x10) {	/* fpc */

Pointless comment.  What is an FPC?

> +			cinfo->type = JNX_BOARD_TYPE_FPC;
> +			switch (s2 & 0x0f) {
> +			case 0x00:	/* Sangria */
> +				cinfo->assembly_id = JNX_ID_SNG_VDV_BASE_P2;
> +				chinfo->platform = JNX_PRODUCT_SANGRIA;
> +				break;
> +			case 0x01:	/* Tiny */
> +				chinfo->platform = JNX_PRODUCT_TINY;
> +				break;
> +			case 0x02:	/* Hercules */
> +				chinfo->platform = JNX_PRODUCT_HERCULES;
> +				break;
> +			case 0x03:      /* Hendricks */
> +				cinfo->assembly_id = JNX_ID_HENDRICKS_FPC_P2;
> +				chinfo->platform = JNX_PRODUCT_HENDRICKS;
> +				break;
> +			default:	/* unknown */
> +				break;
> +			}
> +		} else {		/* spmb */
> +			cinfo->type = JNX_BOARD_TYPE_SPMB;
> +			switch (s2 & 0x0f) {
> +			case 0x00:	/* Sangria */
> +				cinfo->assembly_id = JNX_ID_SNG_PMB;
> +				chinfo->platform = JNX_PRODUCT_SANGRIA;
> +				break;
> +			default:	/* unknown */
> +				break;
> +			}
> +		}
> +	}
> +	chinfo->get_master = ptxpmb_cpld_get_master;
> +}
> +
> +static int pmb_cpld_core_probe(struct platform_device *pdev)
> +{
> +	static struct pmb_cpld_core *cpld;
> +	struct device *dev = &pdev->dev;
> +	struct resource *res;
> +	struct ptxpmb_mux_data *pdata = dev->platform_data;
> +	int i, error, mfd_size;
> +	int cpld_type = CPLD_TYPE_PTXPMB;
> +	const struct of_device_id *match;
> +	struct mfd_cell *mfd_cells;
> +
> +	struct jnx_chassis_info chinfo = {
> +		.chassis_no = 0,
> +		.multichassis = 0,
> +		.master_data = NULL,
> +		.platform = -1,
> +		.get_master = NULL,
> +	};
> +	struct jnx_card_info cinfo = {
> +		.type = JNX_BOARD_TYPE_UNKNOWN,
> +		.slot = -1,
> +		.assembly_id = -1,
> +	};
> +
> +	cpld = devm_kzalloc(dev, sizeof(*cpld), GFP_KERNEL);
> +	if (!cpld)
> +		return -ENOMEM;
> +
> +	cpld->dev = dev;
> +	dev_set_drvdata(dev, cpld);
> +
> +	if (pdata) {
> +		cpld_type = pdata->cpld_type;
> +	} else {
> +		match = of_match_device(pmb_cpld_of_ids, dev);
> +		if (match)
> +			cpld_type = (int)(unsigned long)match->data;
> +	}
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	cpld->cpld = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(cpld->cpld))
> +		return PTR_ERR(cpld->cpld);

cpld->cpld is confusing.  Please rename.

> +	chinfo.master_data = cpld;
> +
> +	cpld->irq = platform_get_irq(pdev, 0);
> +	if (cpld->irq >= 0) {
> +		error = devm_request_threaded_irq(dev, cpld->irq, NULL,
> +						  pmb_cpld_core_interrupt,
> +						  IRQF_TRIGGER_RISING |
> +						  IRQF_ONESHOT,
> +						  dev_name(dev), cpld);
> +		if (error < 0)
> +			return error;
> +	}
> +
> +	spin_lock_init(&cpld->lock);
> +	init_waitqueue_head(&cpld->wqh);
> +
> +	mfd_cells = pmb_cpld_cells;
> +	mfd_size = ARRAY_SIZE(pmb_cpld_cells);
> +
> +	switch (cpld_type) {
> +	case CPLD_TYPE_PTXPMB:
> +		cpld_ptxpmb_init(cpld, &chinfo, &cinfo);
> +		break;
> +	case CPLD_TYPE_NGPMB:
> +		cpld_ngpmb_init(cpld, &chinfo, &cinfo);
> +		mfd_cells = ngpmb_cpld_cells;
> +		mfd_size = ARRAY_SIZE(ngpmb_cpld_cells);
> +		break;

Are other types supported?

> +	}
> +
> +	if (pdata) {
> +		for (i = 0; i < mfd_size; i++) {
> +			mfd_cells[i].platform_data = pdata;
> +			mfd_cells[i].pdata_size = sizeof(*pdata);
> +		}
> +	}
> +
> +	error = mfd_add_devices(dev, pdev->id, mfd_cells,

The use of pdev->id here is unusual.

Are you sure this is what you want?

> +				mfd_size, res, 0, NULL);
> +	if (error < 0)
> +		return error;
> +
> +	jnx_register_chassis(&chinfo);
> +	jnx_register_local_card(&cinfo);
> +
> +	return 0;
> +}
> +
> +static int pmb_cpld_core_remove(struct platform_device *pdev)
> +{
> +	jnx_unregister_local_card();
> +	jnx_unregister_chassis();
> +	mfd_remove_devices(&pdev->dev);

'\n' here.

> +	return 0;
> +}
> +
> +static struct platform_driver pmb_cpld_core_driver = {
> +	.probe		= pmb_cpld_core_probe,
> +	.remove		= pmb_cpld_core_remove,
> +	.driver		= {
> +		.name	= "ptxpmb-cpld",
> +		.of_match_table = pmb_cpld_of_ids,
> +		.owner	= THIS_MODULE,

Remove this line.

> +	}
> +};
> +

Remove this line.

> +module_platform_driver(pmb_cpld_core_driver);
> +
> +MODULE_DESCRIPTION("Juniper PTX PMB CPLD Core Driver");
> +MODULE_AUTHOR("Guenter Roeck <groeck at juniper.net>");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:ptxpmb-cpld");
> diff --git a/include/linux/mfd/ptxpmb_cpld.h b/include/linux/mfd/ptxpmb_cpld.h
> new file mode 100644
> index 0000000..e44afb4
> --- /dev/null
> +++ b/include/linux/mfd/ptxpmb_cpld.h
> @@ -0,0 +1,140 @@
> +/*---------------------------------------------------------------------------
> + *
> + * ptxpmb_cpld_core.h
> + *     Copyright (c) 2012 Juniper Networks
> + *
> + *---------------------------------------------------------------------------
> + */

This it not how we write header comments.

> +#ifndef PTXPMB_CPLD_CORE_H
> +#define PTXPMB_CPLD_CORE_H

__MFD_*

> +struct pmb_boot_cpld {
> +	u8 cpld_rev;		/* 0x00 */
> +	u8 reset;
> +#define CPLD_MAIN_RESET		(1 << 0)

Use BIT() for all these "1 <<"s

> +#define CPLD_PHYCB_RESET	(1 << 1)
> +#define CPLD_PHYSW_RESET	(1 << 2)	/* P2020 only	*/
> +#define NGPMB_PCIE_OTHER_RESET	(1 << 3)	/* PAM reset on MLC */
> +	u8 reset_reason;
> +#define NGPMB_REASON_MON_A_FAIL	(1 << 0)
> +#define NGPMB_REASON_WDT1	(1 << 1)
> +#define NGPMB_REASON_WDT2	(1 << 2)
> +#define NGPMB_REASON_WDT3	(1 << 3)
> +#define NGPMB_REASON_WDT4	(1 << 4)
> +#define NGPMB_REASON_RE_HRST	(1 << 5)
> +#define NGPMB_REASON_PWR_ON	(1 << 6)
> +#define NGPMB_REASON_RE_SRST	(1 << 7)
> +	u8 control;
> +#define CPLD_CONTROL_BOOTED_LED	(1 << 0)
> +#define CPLD_CONTROL_WATCHDOG	(1 << 6)
> +#define CPLD_CONTROL_RTC	(1 << 7)
> +#define NGPMB_FLASH_SELECT	(1 << 4)
> +#define NGPMB_FLASH_SWIZZ_ENA	(1 << 5)
> +	u8 sys_timer_cnt;
> +	u8 watchdog_hbyte;
> +	u8 watchdog_lbyte;
> +	u8 unused1[1];
> +	u8 baseboard_status1;	/* 0x08 */
> +#define NGPMB_PMB_STANDALONE	(1 << 0)
> +#define NGPMB_MASTER_SELECT	(1 << 1)
> +#define NGPMB_BASEBRD_STANDALONE (1 << 2)
> +#define NGPMB_BASEBRD_SLOT_LSB	3
> +#define NGPMB_BASEBRD_SLOT_MASK	0xF8
> +	u8 baseboard_status2;
> +#define NGPMB_BASEBRD_TYPE_LSB	5
> +#define NGPMB_BASEBRD_TYPE_MASK	0xE0
> +#define NGPMB_BASEBRD_TYPE_MX	0
> +	u8 chassis_number;
> +	u8 sys_config;
> +	u8 i2c_group_sel;	/* 0x0c */
> +	u8 i2c_group_en;
> +	u8 unused2[4];
> +	u8 timer_irq_st;	/* 0x12 */
> +	u8 timer_irq_en;
> +	u8 unused3[12];
> +	u8 prog_jtag_control;	/* 0x20 */
> +	u8 gp_reset1;		/* 0x21 */
> +#define CPLD_GP_RST1_PCISW	(1 << 0)
> +#define CPLD_GP_RST1_SAM	(1 << 1)
> +#define CPLD_GP_RST1_BRCM	(1 << 2)
> +	u8 gp_reset2;		/* 0x22 */
> +	u8 phy_control;
> +	u8 gpio_1;
> +	u8 gpio_2;
> +#define NGPMB_GPIO2_TO_BASEBRD_LSB	(1 << 3)
> +#define NGPMB_I2C_GRP_SEL_LSB	0
> +#define NGPMB_I2C_GRP_SEL_MASK	0x03
> +	u8 thermal_status;
> +	u8 i2c_host_sel;
> +#define CPLD_I2C_HOST0_MSTR     0x09
> +#define CPLD_I2C_HOST1_MSTR     0x06
> +#define CPLD_I2C_HOST_MSTR_MASK 0x0f
> +	u8 scratch[3];
> +	u8 misc_status;
> +	u8 i2c_bus_control;	/* 0x2c */
> +	union {
> +		struct {
> +			u8 mezz_present;
> +			u8 unused1[4];
> +			u8 i2c_group_sel_dbg;	/* 0x31 */
> +			u8 i2c_group_en_dbg;	/* 0x32 */
> +			u8 i2c_group_sel_force;	/* 0x33 */
> +			u8 i2c_group_en_force;	/* 0x34 */
> +			u8 unused2[0x4b];
> +		} p2020;
> +		struct {
> +			u8 hdk_minor_version;	/* 0x2d */
> +			u8 hdk_feature_ind;
> +			u8 hdk_pmb_srds_mode;
> +			u8 hdk_pwr_fail_status;
> +			u8 hdk_pmb_pwr_status;
> +			u8 hdk_pmb_mezz_status;
> +			u8 cpld_self_reset;	/* 0x33 */
> +			u8 unused[0x4c];
> +			u8 hdk_bcpld_rcw[80];
> +		} p5020;
> +		struct {
> +			u8 unused[3];
> +			u8 chassis_id;		/* 0x30 */
> +			u8 chassis_type;	/* 0x31 */
> +#define NGPMB_CHASSIS_TYPE_LSB		0
> +#define NGPMB_CHASSIS_TYPE_MASK		0x0F
> +#define NGPMB_CHASSIS_TYPE_POLARIS	0x0B
> +#define NGPMB_CHASSIS_TYPE_HENDRICKS	0x09
> +			u8 sys_config;		/* 0x32 */
> +#define NGPMB_SYS_CONFIG_MULTI_CHASSIS	0x01
> +		} ngpmb;
> +		struct {
> +			u8 nv_win;		/* 0x2d */
> +			u8 nv_addr1;
> +			u8 nv_addr2;
> +			u8 nv_wr_data;
> +			u8 nv_rd_data;
> +			u8 nv_cmd;
> +			u8 nv_done_bit;
> +		} nvram;
> +	} board;
> +};

Please use the standard conventions for detailing registers and bits.

> +#ifdef CONFIG_P2020_PTXPMB
> +#define CPLD_PHY_RESET	(CPLD_PHYCB_RESET | CPLD_PHYSW_RESET)
> +#else
> +#define CPLD_PHY_RESET	CPLD_PHYCB_RESET
> +#endif
> +
> +#define i2c_group_sel_force board.p2020.i2c_group_sel_force
> +#define i2c_group_en_force board.p2020.i2c_group_en_force

I've never seen this before.  Please don't do it.

> +struct ptxpmb_mux_data {
> +	int cpld_type;
> +#define CPLD_TYPE_PTXPMB    0	/* SPMB / Sangria FPC / Hendricks FPC */
> +#define CPLD_TYPE_NGPMB     1	/* MLC / Stout / Gladiator... */
> +	int num_enable;		/* Number of I2C enable pins		*/
> +	int num_channels;	/* Number of I2C channels used in a mux chip */
> +	int parent_bus_num;	/* parent i2c bus number		*/
> +	int base_bus_num;	/* 1st bus number, 0 if undefined	*/
> +	bool use_force;		/* Use i2c force registers if true	*/
> +};

Rename to *_mux_pdata for clarity.

Use kdoc throughout.

> +#endif /* PTXPMB_CPLD_CORE_H */

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog


From Danesh.Daroui at ascom.com  Wed Oct 26 09:07:20 2016
From: Danesh.Daroui at ascom.com (Danesh Daroui)
Date: Wed, 26 Oct 2016 16:07:20 +0000
Subject: OOB Test fails
Message-ID: <39BC08CB3FF4C84CB6397533D4FC79095770D513@SEGOTEXCH02.ascom-Resource.ads>

Hello all,

I have executed MTD tests against an unmounted MTD device which uses UBIFS. All MTD tests except OOB test is passed where the OOB test fails from time to time and from device to device. I have read here:

http://www.linux-mtd.infradead.org/faq/ubi.html#L_why_no_oob

that UBIFS does not use OOB area. Therefore wanted to ask if failing this test does not need that there is any problem in our system (both HW and SW/configuration) and we can safely ignore the results for this test.

Thanks in advance,

Danesh Daroui




From derosier at gmail.com  Wed Oct 26 09:16:42 2016
From: derosier at gmail.com (Steve deRosier)
Date: Wed, 26 Oct 2016 09:16:42 -0700
Subject: OOB Test fails
In-Reply-To: <39BC08CB3FF4C84CB6397533D4FC79095770D513@SEGOTEXCH02.ascom-Resource.ads>
References: <39BC08CB3FF4C84CB6397533D4FC79095770D513@SEGOTEXCH02.ascom-Resource.ads>
Message-ID: <CALupW3CJ_gXS+7BrZEGTF8o0H8pJ_AOw0JcKOftSVaMVSbP1zQ@mail.gmail.com>

Hi Danesh,


On Wed, Oct 26, 2016 at 9:07 AM, Danesh Daroui <Danesh.Daroui at ascom.com> wrote:
> Hello all,
>
> I have executed MTD tests against an unmounted MTD device which uses UBIFS. All MTD tests except OOB test is passed where the OOB test fails from time to time and from device to device. I have read here:
>
> http://www.linux-mtd.infradead.org/faq/ubi.html#L_why_no_oob
>
> that UBIFS does not use OOB area. Therefore wanted to ask if failing this test does not need that there is any problem in our system (both HW and SW/configuration) and we can safely ignore the results for this test.
>

UBIFS doesn't use the OOB area, but your MTD driver most likely does.
We don't want UBI or UBIFS messing with the OOB area because your
flash, NAND controller and the MTD driver will use that. Bad block
markers are set in the OOB area by the manufacturer in most NAND
flashes and your controller and MTD driver will store and use the bits
in the OOB to do error correction.

So, in short - the OOB area does need to function correctly.  As to if
and why the OOB test is or isn't working is a different issue and I
have no input on that.  All that depends on your mix of flash,
controller and driver.

- Steve


From Danesh.Daroui at ascom.com  Wed Oct 26 09:28:43 2016
From: Danesh.Daroui at ascom.com (Danesh Daroui)
Date: Wed, 26 Oct 2016 16:28:43 +0000
Subject: OOB Test fails
In-Reply-To: <CALupW3CJ_gXS+7BrZEGTF8o0H8pJ_AOw0JcKOftSVaMVSbP1zQ@mail.gmail.com>
References: <39BC08CB3FF4C84CB6397533D4FC79095770D513@SEGOTEXCH02.ascom-Resource.ads>
 <CALupW3CJ_gXS+7BrZEGTF8o0H8pJ_AOw0JcKOftSVaMVSbP1zQ@mail.gmail.com>
Message-ID: <39BC08CB3FF4C84CB6397533D4FC79095770D530@SEGOTEXCH02.ascom-Resource.ads>

Hi Steve,

Thank you for your prompt answer. When I run OOB test (mtd_oobtest), for instance, one of devices always return verification failed error on a certain address. This is all we know and all the test reports. We use a quite old kernel i.e. 2.6.39 and this is one of the things that we suspect as a source of the problem that the kernel is outdated. Also, we consider the hardware failure since on some devices no error is shown on OOB test while on others more errors are shown and the address is changed randomly sometimes.

Our main problem is that sometimes UBIFS forces the device into read-only mode due to "bad CRC" error at startup when the device is booted. I am now running tests which are in "mtd_utils" for testing file system. I have started running two tests which are "simple/test_1" and "simple/test_2" which simply write until the drive is full and the read the data back and verify the correctness. During the test, I see lots of:

UBI: scrubbed PEB 585 (LEB 3:770), data moved to PEB 1772
UBI: scrubbed PEB 1045 (LEB 3:1261), data moved to PEB 828
UBI: scrubbed PEB 1493 (LEB 3:664), data moved to PEB 814
UBI: scrubbed PEB 751 (LEB 3:1260), data moved to PEB 1772

In my mind, this is related to problematic hardware that the data is corrupted on many cells that UBIFS tries to move the data when a corruption is detected. My question is, whether this guess can be valid or this is mostly due to old kernel that we are using and upgrading to a new kernel would most likely solve the problems?

Thanks again,

Danesh Daroui


-----Original Message-----
From: Steve deRosier [mailto:derosier at gmail.com] 
Sent: den 26 oktober 2016 18:17
To: Danesh Daroui <Danesh.Daroui at ascom.com>
Cc: linux-mtd at lists.infradead.org
Subject: Re: OOB Test fails

Hi Danesh,


On Wed, Oct 26, 2016 at 9:07 AM, Danesh Daroui <Danesh.Daroui at ascom.com> wrote:
> Hello all,
>
> I have executed MTD tests against an unmounted MTD device which uses UBIFS. All MTD tests except OOB test is passed where the OOB test fails from time to time and from device to device. I have read here:
>
> http://www.linux-mtd.infradead.org/faq/ubi.html#L_why_no_oob
>
> that UBIFS does not use OOB area. Therefore wanted to ask if failing this test does not need that there is any problem in our system (both HW and SW/configuration) and we can safely ignore the results for this test.
>

UBIFS doesn't use the OOB area, but your MTD driver most likely does.
We don't want UBI or UBIFS messing with the OOB area because your flash, NAND controller and the MTD driver will use that. Bad block markers are set in the OOB area by the manufacturer in most NAND flashes and your controller and MTD driver will store and use the bits in the OOB to do error correction.

So, in short - the OOB area does need to function correctly.  As to if and why the OOB test is or isn't working is a different issue and I have no input on that.  All that depends on your mix of flash, controller and driver.

- Steve

From maxime.ripard at free-electrons.com  Tue Oct 25 03:42:09 2016
From: maxime.ripard at free-electrons.com (Maxime Ripard)
Date: Tue, 25 Oct 2016 12:42:09 +0200
Subject: [PATCH 5/8] ARM: gr8: Add missing pwm channel 1 pin
In-Reply-To: <CAGb2v64Ai+8sUPyH9aTnKUw1ROmQNxzCEqUXrT4v8Q-nipqR3Q@mail.gmail.com>
References: <cover.bb1e4a568bc16ada5254cad063f4afbaa1ca5906.1476951078.git-series.maxime.ripard@free-electrons.com>
 <0df42247c3348e7f6aed945e5669cec87f96f7ac.1476951078.git-series.maxime.ripard@free-electrons.com>
 <CAGb2v66w0sTzn_SWH4rrpWKOosSxALV8ot3CBQbGhwLxvX1vxw@mail.gmail.com>
 <20161020170739.lgt2ywm346vm47zd@lukather>
 <CAGb2v64Ai+8sUPyH9aTnKUw1ROmQNxzCEqUXrT4v8Q-nipqR3Q@mail.gmail.com>
Message-ID: <20161025104209.edtqoymu4thc56p4@lukather>

On Tue, Oct 25, 2016 at 12:10:26PM +0800, Chen-Yu Tsai wrote:
> On Fri, Oct 21, 2016 at 1:07 AM, Maxime Ripard
> <maxime.ripard at free-electrons.com> wrote:
> > On Thu, Oct 20, 2016 at 10:10:03PM +0800, Chen-Yu Tsai wrote:
> >> On Thu, Oct 20, 2016 at 4:12 PM, Maxime Ripard
> >> <maxime.ripard at free-electrons.com> wrote:
> >> > The PWM controller has two different channels, but only the first pin was
> >> > exposed in the DTSI. Add the other one.
> >> >
> >> > Signed-off-by: Maxime Ripard <maxime.ripard at free-electrons.com>
> >>
> >> Acked-by: Chen-Yu Tsai <wens at csie.org>
> >>
> >> > ---
> >> >  arch/arm/boot/dts/ntc-gr8.dtsi | 7 +++++++
> >> >  1 file changed, 7 insertions(+), 0 deletions(-)
> >> >
> >> > diff --git a/arch/arm/boot/dts/ntc-gr8.dtsi b/arch/arm/boot/dts/ntc-gr8.dtsi
> >> > index 74aff795e723..fad7381630f3 100644
> >> > --- a/arch/arm/boot/dts/ntc-gr8.dtsi
> >> > +++ b/arch/arm/boot/dts/ntc-gr8.dtsi
> >> > @@ -854,6 +854,13 @@
> >> >                                 allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
> >> >                         };
> >> >
> >> > +                       pwm1_pins_a: pwm1 at 0 {
> >>
> >> Nit: really don't need "_a" and "@0" here.
> >
> > Fixed and applied.
> 
> Oops, you forgot to fix the label in the chip-pro dts:
> 
>   DTC     arch/arm/boot/dts/ntc-gr8-chip-pro.dtb
> ERROR (phandle_references): Reference to non-existent node or label
> "pwm1_pins_a"
> 
> ERROR: Input tree has errors, aborting (use -f to force output)
> scripts/Makefile.lib:313: recipe for target
> 'arch/arm/boot/dts/ntc-gr8-chip-pro.dtb' failed

Yeah, it was noticed by linux-next too, and I fixed it...

Sorry for that.
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20161025/7c71abee/attachment.sig>

From robh at kernel.org  Wed Oct 26 16:19:12 2016
From: robh at kernel.org (Rob Herring)
Date: Wed, 26 Oct 2016 18:19:12 -0500
Subject: [PATCH v3 2/3] dt-bindings: mtd: add DT binding for s3c2410
 flash controller
In-Reply-To: <1476999766-32526-3-git-send-email-sergio.prado@e-labworks.com>
References: <1476999766-32526-1-git-send-email-sergio.prado@e-labworks.com>
 <1476999766-32526-3-git-send-email-sergio.prado@e-labworks.com>
Message-ID: <20161026231912.z6yez3posjqkqtxu@rob-hp-laptop>

On Thu, Oct 20, 2016 at 07:42:45PM -0200, Sergio Prado wrote:
> Adds the device tree bindings description for Samsung S3C2410 and
> compatible NAND flash controller.
> 
> Signed-off-by: Sergio Prado <sergio.prado at e-labworks.com>
> ---
>  .../devicetree/bindings/mtd/samsung-s3c2410.txt    | 56 ++++++++++++++++++++++
>  1 file changed, 56 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt

Acked-by: Rob Herring <robh at kernel.org>


From sergio.prado at e-labworks.com  Wed Oct 26 16:59:52 2016
From: sergio.prado at e-labworks.com (Sergio Prado)
Date: Wed, 26 Oct 2016 21:59:52 -0200
Subject: [PATCH v4 0/3] mtd: s3c2410: add device tree support
Message-ID: <1477526395-13103-1-git-send-email-sergio.prado@e-labworks.com>

This series adds support for configuring Samsung's s3c2410 and
compatible flash memory controller via devicetree.

Tested on FriendlyARM mini2440, based on s3c2440 SoC.

Patch 3 depends on patch 1.

Changes since v3:
- apply the timings in the end of ->setup_data_interface so the
  timings can be changed at runtime by the MTD core.

Changes since v2:
- conditionally assign chip->setup_data_interface to
  s3c2410_nand_setup_data_interface if booting via device tree

Changes since v1:
- automate timing selection when booting with a device tree
- make s3c24XX_nand_devtype_data structs "static const"
- removing samsung,s3c6400-nand compatible since it is equivalent to
  samsung,s3c2412-nand

Changes since initial version:
- patch converted to a patch series
- read timings from nand_sdr_timings when booting with a device tree
- naming improvements in the device tree binding
  (s/nand/nand-controller/, s/_/-, s/children/child)
- dropped property samsung,ignore_unset_ecc
- remove @0 from nand device node
- checking pdev->dev.of_node instead of using ifdef CONFIG_OF_MTD
- preventing from parsing device tree properties twice
- increment the nand controller child node refcount, since we
  maintain a reference to it and its name field
- using of_device_get_match_data() instead of of_match_device()
  to make the code simpler
- remove CONFIG_MTD_NAND_S3C2410_HWECC compile option so we can
  select ECC mode using nand-ecc-mode property in the device tree

Sergio Prado (3):
  mtd: s3c2410: make ecc mode configurable via platform data
  dt-bindings: mtd: add DT binding for s3c2410 flash controller
  mtd: s3c2410: parse the device configuration from OF node

 .../devicetree/bindings/mtd/samsung-s3c2410.txt    |  56 +++++
 arch/arm/mach-s3c24xx/common-smdk.c                |   1 +
 arch/arm/mach-s3c24xx/mach-anubis.c                |   1 +
 arch/arm/mach-s3c24xx/mach-at2440evb.c             |   1 +
 arch/arm/mach-s3c24xx/mach-bast.c                  |   1 +
 arch/arm/mach-s3c24xx/mach-gta02.c                 |   1 +
 arch/arm/mach-s3c24xx/mach-jive.c                  |   1 +
 arch/arm/mach-s3c24xx/mach-mini2440.c              |   1 +
 arch/arm/mach-s3c24xx/mach-osiris.c                |   1 +
 arch/arm/mach-s3c24xx/mach-qt2410.c                |   1 +
 arch/arm/mach-s3c24xx/mach-rx1950.c                |   1 +
 arch/arm/mach-s3c24xx/mach-rx3715.c                |   1 +
 arch/arm/mach-s3c24xx/mach-vstms.c                 |   1 +
 arch/arm/mach-s3c64xx/mach-hmt.c                   |   1 +
 arch/arm/mach-s3c64xx/mach-mini6410.c              |   1 +
 arch/arm/mach-s3c64xx/mach-real6410.c              |   1 +
 drivers/mtd/nand/Kconfig                           |   9 -
 drivers/mtd/nand/s3c2410.c                         | 277 +++++++++++++++------
 include/linux/platform_data/mtd-nand-s3c2410.h     |   7 +-
 19 files changed, 278 insertions(+), 86 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt

-- 
1.9.1



From sergio.prado at e-labworks.com  Wed Oct 26 16:59:53 2016
From: sergio.prado at e-labworks.com (Sergio Prado)
Date: Wed, 26 Oct 2016 21:59:53 -0200
Subject: [PATCH v4 1/3] mtd: s3c2410: make ecc mode configurable via platform
 data
In-Reply-To: <1477526395-13103-1-git-send-email-sergio.prado@e-labworks.com>
References: <1477526395-13103-1-git-send-email-sergio.prado@e-labworks.com>
Message-ID: <1477526395-13103-2-git-send-email-sergio.prado@e-labworks.com>

Removing CONFIG_MTD_NAND_S3C2410_HWECC option and adding a ecc_mode
field in the drivers's platform data structure so it can be selectable
via platform data.

Also setting this field to NAND_ECC_SOFT in all boards using this
driver since none of them had CONFIG_MTD_NAND_S3C2410_HWECC enabled.

Acked-by: Krzysztof Kozlowski <krzk at kernel.org>
Signed-off-by: Sergio Prado <sergio.prado at e-labworks.com>
---
 arch/arm/mach-s3c24xx/common-smdk.c            |   1 +
 arch/arm/mach-s3c24xx/mach-anubis.c            |   1 +
 arch/arm/mach-s3c24xx/mach-at2440evb.c         |   1 +
 arch/arm/mach-s3c24xx/mach-bast.c              |   1 +
 arch/arm/mach-s3c24xx/mach-gta02.c             |   1 +
 arch/arm/mach-s3c24xx/mach-jive.c              |   1 +
 arch/arm/mach-s3c24xx/mach-mini2440.c          |   1 +
 arch/arm/mach-s3c24xx/mach-osiris.c            |   1 +
 arch/arm/mach-s3c24xx/mach-qt2410.c            |   1 +
 arch/arm/mach-s3c24xx/mach-rx1950.c            |   1 +
 arch/arm/mach-s3c24xx/mach-rx3715.c            |   1 +
 arch/arm/mach-s3c24xx/mach-vstms.c             |   1 +
 arch/arm/mach-s3c64xx/mach-hmt.c               |   1 +
 arch/arm/mach-s3c64xx/mach-mini6410.c          |   1 +
 arch/arm/mach-s3c64xx/mach-real6410.c          |   1 +
 drivers/mtd/nand/Kconfig                       |   9 --
 drivers/mtd/nand/s3c2410.c                     | 119 +++++++++++++------------
 include/linux/platform_data/mtd-nand-s3c2410.h |   6 +-
 18 files changed, 79 insertions(+), 70 deletions(-)

diff --git a/arch/arm/mach-s3c24xx/common-smdk.c b/arch/arm/mach-s3c24xx/common-smdk.c
index e9fbcc91c5c0..9e0bc46e90ec 100644
--- a/arch/arm/mach-s3c24xx/common-smdk.c
+++ b/arch/arm/mach-s3c24xx/common-smdk.c
@@ -171,6 +171,7 @@
 	.twrph1		= 20,
 	.nr_sets	= ARRAY_SIZE(smdk_nand_sets),
 	.sets		= smdk_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* devices we initialise */
diff --git a/arch/arm/mach-s3c24xx/mach-anubis.c b/arch/arm/mach-s3c24xx/mach-anubis.c
index d03df0df01fa..029ef1b58925 100644
--- a/arch/arm/mach-s3c24xx/mach-anubis.c
+++ b/arch/arm/mach-s3c24xx/mach-anubis.c
@@ -223,6 +223,7 @@ static void anubis_nand_select(struct s3c2410_nand_set *set, int slot)
 	.nr_sets	= ARRAY_SIZE(anubis_nand_sets),
 	.sets		= anubis_nand_sets,
 	.select_chip	= anubis_nand_select,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* IDE channels */
diff --git a/arch/arm/mach-s3c24xx/mach-at2440evb.c b/arch/arm/mach-s3c24xx/mach-at2440evb.c
index 9ae170fef2a7..7b28eb623fc1 100644
--- a/arch/arm/mach-s3c24xx/mach-at2440evb.c
+++ b/arch/arm/mach-s3c24xx/mach-at2440evb.c
@@ -114,6 +114,7 @@
 	.twrph1		= 40,
 	.nr_sets	= ARRAY_SIZE(at2440evb_nand_sets),
 	.sets		= at2440evb_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* DM9000AEP 10/100 ethernet controller */
diff --git a/arch/arm/mach-s3c24xx/mach-bast.c b/arch/arm/mach-s3c24xx/mach-bast.c
index ed07cf392d4b..5185036765db 100644
--- a/arch/arm/mach-s3c24xx/mach-bast.c
+++ b/arch/arm/mach-s3c24xx/mach-bast.c
@@ -299,6 +299,7 @@ static void bast_nand_select(struct s3c2410_nand_set *set, int slot)
 	.nr_sets	= ARRAY_SIZE(bast_nand_sets),
 	.sets		= bast_nand_sets,
 	.select_chip	= bast_nand_select,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* DM9000 */
diff --git a/arch/arm/mach-s3c24xx/mach-gta02.c b/arch/arm/mach-s3c24xx/mach-gta02.c
index 27ae6877550f..b0ed401da3a3 100644
--- a/arch/arm/mach-s3c24xx/mach-gta02.c
+++ b/arch/arm/mach-s3c24xx/mach-gta02.c
@@ -443,6 +443,7 @@ static void gta02_udc_vbus_draw(unsigned int ma)
 	.twrph1		= 15,
 	.nr_sets	= ARRAY_SIZE(gta02_nand_sets),
 	.sets		= gta02_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 
diff --git a/arch/arm/mach-s3c24xx/mach-jive.c b/arch/arm/mach-s3c24xx/mach-jive.c
index 7d99fe8f6157..895aca225952 100644
--- a/arch/arm/mach-s3c24xx/mach-jive.c
+++ b/arch/arm/mach-s3c24xx/mach-jive.c
@@ -232,6 +232,7 @@
 	.twrph1		= 40,
 	.sets		= jive_nand_sets,
 	.nr_sets	= ARRAY_SIZE(jive_nand_sets),
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 static int __init jive_mtdset(char *options)
diff --git a/arch/arm/mach-s3c24xx/mach-mini2440.c b/arch/arm/mach-s3c24xx/mach-mini2440.c
index ec60bd4a1646..71af8d2fd320 100644
--- a/arch/arm/mach-s3c24xx/mach-mini2440.c
+++ b/arch/arm/mach-s3c24xx/mach-mini2440.c
@@ -287,6 +287,7 @@
 	.nr_sets	= ARRAY_SIZE(mini2440_nand_sets),
 	.sets		= mini2440_nand_sets,
 	.ignore_unset_ecc = 1,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* DM9000AEP 10/100 ethernet controller */
diff --git a/arch/arm/mach-s3c24xx/mach-osiris.c b/arch/arm/mach-s3c24xx/mach-osiris.c
index 2f6fdc326835..70b0eb7d3134 100644
--- a/arch/arm/mach-s3c24xx/mach-osiris.c
+++ b/arch/arm/mach-s3c24xx/mach-osiris.c
@@ -238,6 +238,7 @@ static void osiris_nand_select(struct s3c2410_nand_set *set, int slot)
 	.nr_sets	= ARRAY_SIZE(osiris_nand_sets),
 	.sets		= osiris_nand_sets,
 	.select_chip	= osiris_nand_select,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* PCMCIA control and configuration */
diff --git a/arch/arm/mach-s3c24xx/mach-qt2410.c b/arch/arm/mach-s3c24xx/mach-qt2410.c
index 984516e8307a..868c82087403 100644
--- a/arch/arm/mach-s3c24xx/mach-qt2410.c
+++ b/arch/arm/mach-s3c24xx/mach-qt2410.c
@@ -284,6 +284,7 @@
 	.twrph1		= 20,
 	.nr_sets	= ARRAY_SIZE(qt2410_nand_sets),
 	.sets		= qt2410_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* UDC */
diff --git a/arch/arm/mach-s3c24xx/mach-rx1950.c b/arch/arm/mach-s3c24xx/mach-rx1950.c
index 25a139bb9826..e86ad6a68a0b 100644
--- a/arch/arm/mach-s3c24xx/mach-rx1950.c
+++ b/arch/arm/mach-s3c24xx/mach-rx1950.c
@@ -611,6 +611,7 @@ static void rx1950_set_mmc_power(unsigned char power_mode, unsigned short vdd)
 	.twrph1 = 15,
 	.nr_sets = ARRAY_SIZE(rx1950_nand_sets),
 	.sets = rx1950_nand_sets,
+	.ecc_mode = NAND_ECC_SOFT,
 };
 
 static struct s3c2410_udc_mach_info rx1950_udc_cfg __initdata = {
diff --git a/arch/arm/mach-s3c24xx/mach-rx3715.c b/arch/arm/mach-s3c24xx/mach-rx3715.c
index cf55196f89ca..a39fb9780dd3 100644
--- a/arch/arm/mach-s3c24xx/mach-rx3715.c
+++ b/arch/arm/mach-s3c24xx/mach-rx3715.c
@@ -164,6 +164,7 @@
 	.twrph1		= 15,
 	.nr_sets	= ARRAY_SIZE(rx3715_nand_sets),
 	.sets		= rx3715_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 static struct platform_device *rx3715_devices[] __initdata = {
diff --git a/arch/arm/mach-s3c24xx/mach-vstms.c b/arch/arm/mach-s3c24xx/mach-vstms.c
index b4460d5f7011..f5e6322145fa 100644
--- a/arch/arm/mach-s3c24xx/mach-vstms.c
+++ b/arch/arm/mach-s3c24xx/mach-vstms.c
@@ -117,6 +117,7 @@
 	.twrph1		= 20,
 	.nr_sets	= ARRAY_SIZE(vstms_nand_sets),
 	.sets		= vstms_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 static struct platform_device *vstms_devices[] __initdata = {
diff --git a/arch/arm/mach-s3c64xx/mach-hmt.c b/arch/arm/mach-s3c64xx/mach-hmt.c
index bc7dc1fcbf7d..59b5531f1987 100644
--- a/arch/arm/mach-s3c64xx/mach-hmt.c
+++ b/arch/arm/mach-s3c64xx/mach-hmt.c
@@ -204,6 +204,7 @@ static void hmt_bl_exit(struct device *dev)
 	.twrph1		= 40,
 	.nr_sets	= ARRAY_SIZE(hmt_nand_sets),
 	.sets		= hmt_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 static struct gpio_led hmt_leds[] = {
diff --git a/arch/arm/mach-s3c64xx/mach-mini6410.c b/arch/arm/mach-s3c64xx/mach-mini6410.c
index ae999fb3fe6d..a3e3e25728b4 100644
--- a/arch/arm/mach-s3c64xx/mach-mini6410.c
+++ b/arch/arm/mach-s3c64xx/mach-mini6410.c
@@ -142,6 +142,7 @@
 	.twrph1		= 40,
 	.nr_sets	= ARRAY_SIZE(mini6410_nand_sets),
 	.sets		= mini6410_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 static struct s3c_fb_pd_win mini6410_lcd_type0_fb_win = {
diff --git a/arch/arm/mach-s3c64xx/mach-real6410.c b/arch/arm/mach-s3c64xx/mach-real6410.c
index 4e240ffa7ac7..d6b3ffd7704b 100644
--- a/arch/arm/mach-s3c64xx/mach-real6410.c
+++ b/arch/arm/mach-s3c64xx/mach-real6410.c
@@ -194,6 +194,7 @@
 	.twrph1		= 40,
 	.nr_sets	= ARRAY_SIZE(real6410_nand_sets),
 	.sets		= real6410_nand_sets,
+	.ecc_mode       = NAND_ECC_SOFT,
 };
 
 static struct platform_device *real6410_devices[] __initdata = {
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 7b7a887b4709..9748f3580d4b 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -179,15 +179,6 @@ config MTD_NAND_S3C2410_DEBUG
 	help
 	  Enable debugging of the S3C NAND driver
 
-config MTD_NAND_S3C2410_HWECC
-	bool "Samsung S3C NAND Hardware ECC"
-	depends on MTD_NAND_S3C2410
-	help
-	  Enable the use of the controller's internal ECC generator when
-	  using NAND. Early versions of the chips have had problems with
-	  incorrect ECC generation, and if using these, the default of
-	  software ECC is preferable.
-
 config MTD_NAND_NDFC
 	tristate "NDFC NanD Flash Controller"
 	depends on 4xx
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index d459c19d78de..371db0d48135 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -497,7 +497,6 @@ static int s3c2412_nand_devready(struct mtd_info *mtd)
 
 /* ECC handling functions */
 
-#ifdef CONFIG_MTD_NAND_S3C2410_HWECC
 static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
 				     u_char *read_ecc, u_char *calc_ecc)
 {
@@ -649,7 +648,6 @@ static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
 
 	return 0;
 }
-#endif
 
 /* over-ride the standard functions for a little more speed. We can
  * use read/write block to move the data buffers to/from the controller
@@ -858,50 +856,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
 	nmtd->info	   = info;
 	nmtd->set	   = set;
 
-#ifdef CONFIG_MTD_NAND_S3C2410_HWECC
-	chip->ecc.calculate = s3c2410_nand_calculate_ecc;
-	chip->ecc.correct   = s3c2410_nand_correct_data;
-	chip->ecc.mode	    = NAND_ECC_HW;
-	chip->ecc.strength  = 1;
-
-	switch (info->cpu_type) {
-	case TYPE_S3C2410:
-		chip->ecc.hwctl	    = s3c2410_nand_enable_hwecc;
-		chip->ecc.calculate = s3c2410_nand_calculate_ecc;
-		break;
-
-	case TYPE_S3C2412:
-		chip->ecc.hwctl     = s3c2412_nand_enable_hwecc;
-		chip->ecc.calculate = s3c2412_nand_calculate_ecc;
-		break;
-
-	case TYPE_S3C2440:
-		chip->ecc.hwctl     = s3c2440_nand_enable_hwecc;
-		chip->ecc.calculate = s3c2440_nand_calculate_ecc;
-		break;
-	}
-#else
-	chip->ecc.mode	    = NAND_ECC_SOFT;
-	chip->ecc.algo	= NAND_ECC_HAMMING;
-#endif
-
-	if (set->disable_ecc)
-		chip->ecc.mode	= NAND_ECC_NONE;
-
-	switch (chip->ecc.mode) {
-	case NAND_ECC_NONE:
-		dev_info(info->device, "NAND ECC disabled\n");
-		break;
-	case NAND_ECC_SOFT:
-		dev_info(info->device, "NAND soft ECC\n");
-		break;
-	case NAND_ECC_HW:
-		dev_info(info->device, "NAND hardware ECC\n");
-		break;
-	default:
-		dev_info(info->device, "NAND ECC UNKNOWN\n");
-		break;
-	}
+	chip->ecc.mode = info->platform->ecc_mode;
 
 	/* If you use u-boot BBT creation code, specifying this flag will
 	 * let the kernel fish out the BBT from the NAND, and also skip the
@@ -923,28 +878,72 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
  *
  * The internal state is currently limited to the ECC state information.
 */
-static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
+static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
 				     struct s3c2410_nand_mtd *nmtd)
 {
 	struct nand_chip *chip = &nmtd->chip;
 
-	dev_dbg(info->device, "chip %p => page shift %d\n",
-		chip, chip->page_shift);
+	switch (chip->ecc.mode) {
 
-	if (chip->ecc.mode != NAND_ECC_HW)
-		return;
+	case NAND_ECC_NONE:
+		dev_info(info->device, "ECC disabled\n");
+		break;
+
+	case NAND_ECC_SOFT:
+		/*
+		 * This driver expects Hamming based ECC when ecc_mode is set
+		 * to NAND_ECC_SOFT. Force ecc.algo to NAND_ECC_HAMMING to
+		 * avoid adding an extra ecc_algo field to s3c2410_platform_nand.
+		 */
+		chip->ecc.algo = NAND_ECC_HAMMING;
+		dev_info(info->device, "soft ECC\n");
+		break;
+
+	case NAND_ECC_HW:
+		chip->ecc.calculate = s3c2410_nand_calculate_ecc;
+		chip->ecc.correct   = s3c2410_nand_correct_data;
+		chip->ecc.strength  = 1;
+
+		switch (info->cpu_type) {
+		case TYPE_S3C2410:
+			chip->ecc.hwctl	    = s3c2410_nand_enable_hwecc;
+			chip->ecc.calculate = s3c2410_nand_calculate_ecc;
+			break;
+
+		case TYPE_S3C2412:
+			chip->ecc.hwctl     = s3c2412_nand_enable_hwecc;
+			chip->ecc.calculate = s3c2412_nand_calculate_ecc;
+			break;
+
+		case TYPE_S3C2440:
+			chip->ecc.hwctl     = s3c2440_nand_enable_hwecc;
+			chip->ecc.calculate = s3c2440_nand_calculate_ecc;
+			break;
+		}
+
+		dev_dbg(info->device, "chip %p => page shift %d\n",
+			chip, chip->page_shift);
 
 		/* change the behaviour depending on whether we are using
 		 * the large or small page nand device */
+		if (chip->page_shift > 10) {
+			chip->ecc.size	    = 256;
+			chip->ecc.bytes	    = 3;
+		} else {
+			chip->ecc.size	    = 512;
+			chip->ecc.bytes	    = 3;
+			mtd_set_ooblayout(nand_to_mtd(chip), &s3c2410_ooblayout_ops);
+		}
 
-	if (chip->page_shift > 10) {
-		chip->ecc.size	    = 256;
-		chip->ecc.bytes	    = 3;
-	} else {
-		chip->ecc.size	    = 512;
-		chip->ecc.bytes	    = 3;
-		mtd_set_ooblayout(nand_to_mtd(chip), &s3c2410_ooblayout_ops);
+		dev_info(info->device, "hardware ECC\n");
+		break;
+
+	default:
+		dev_err(info->device, "invalid ECC mode!\n");
+		return -EINVAL;
 	}
+
+	return 0;
 }
 
 /* s3c24xx_nand_probe
@@ -1046,7 +1045,9 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 						 NULL);
 
 		if (nmtd->scan_res == 0) {
-			s3c2410_nand_update_chip(info, nmtd);
+			err = s3c2410_nand_update_chip(info, nmtd);
+			if (err < 0)
+				goto exit_error;
 			nand_scan_tail(mtd);
 			s3c2410_nand_add_partition(info, nmtd, sets);
 		}
diff --git a/include/linux/platform_data/mtd-nand-s3c2410.h b/include/linux/platform_data/mtd-nand-s3c2410.h
index c55e42ee57fa..729af13d1773 100644
--- a/include/linux/platform_data/mtd-nand-s3c2410.h
+++ b/include/linux/platform_data/mtd-nand-s3c2410.h
@@ -12,9 +12,10 @@
 #ifndef __MTD_NAND_S3C2410_H
 #define __MTD_NAND_S3C2410_H
 
+#include <linux/mtd/nand.h>
+
 /**
  * struct s3c2410_nand_set - define a set of one or more nand chips
- * @disable_ecc:	Entirely disable ECC - Dangerous
  * @flash_bbt: 		Openmoko u-boot can create a Bad Block Table
  *			Setting this flag will allow the kernel to
  *			look for it at boot time and also skip the NAND
@@ -31,7 +32,6 @@
  * a warning at boot time.
  */
 struct s3c2410_nand_set {
-	unsigned int		disable_ecc:1;
 	unsigned int		flash_bbt:1;
 
 	unsigned int		options;
@@ -51,6 +51,8 @@ struct s3c2410_platform_nand {
 
 	unsigned int	ignore_unset_ecc:1;
 
+	nand_ecc_modes_t	ecc_mode;
+
 	int			nr_sets;
 	struct s3c2410_nand_set *sets;
 
-- 
1.9.1



From sergio.prado at e-labworks.com  Wed Oct 26 16:59:54 2016
From: sergio.prado at e-labworks.com (Sergio Prado)
Date: Wed, 26 Oct 2016 21:59:54 -0200
Subject: [PATCH v4 2/3] dt-bindings: mtd: add DT binding for s3c2410 flash
 controller
In-Reply-To: <1477526395-13103-1-git-send-email-sergio.prado@e-labworks.com>
References: <1477526395-13103-1-git-send-email-sergio.prado@e-labworks.com>
Message-ID: <1477526395-13103-3-git-send-email-sergio.prado@e-labworks.com>

Adds the device tree bindings description for Samsung S3C2410 and
compatible NAND flash controller.

Acked-by: Rob Herring <robh at kernel.org>
Acked-by: Krzysztof Kozlowski <krzk at kernel.org>
Signed-off-by: Sergio Prado <sergio.prado at e-labworks.com>
---
 .../devicetree/bindings/mtd/samsung-s3c2410.txt    | 56 ++++++++++++++++++++++
 1 file changed, 56 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt

diff --git a/Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt b/Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt
new file mode 100644
index 000000000000..0040eb8895e0
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt
@@ -0,0 +1,56 @@
+* Samsung S3C2410 and compatible NAND flash controller
+
+Required properties:
+- compatible : The possible values are:
+	"samsung,s3c2410-nand"
+	"samsung,s3c2412-nand"
+	"samsung,s3c2440-nand"
+- reg : register's location and length.
+- #address-cells, #size-cells : see nand.txt
+- clocks : phandle to the nand controller clock
+- clock-names : must contain "nand"
+
+Optional child nodes:
+Child nodes representing the available nand chips.
+
+Optional child properties:
+- nand-ecc-mode : see nand.txt
+- nand-on-flash-bbt : see nand.txt
+
+Each child device node may optionally contain a 'partitions' sub-node,
+which further contains sub-nodes describing the flash partition mapping.
+See partition.txt for more detail.
+
+Example:
+
+nand-controller at 4e000000 {
+	compatible = "samsung,s3c2440-nand";
+	reg = <0x4e000000 0x40>;
+
+	#address-cells = <1>;
+        #size-cells = <0>;
+
+	clocks = <&clocks HCLK_NAND>;
+	clock-names = "nand";
+
+	nand {
+		nand-ecc-mode = "soft";
+		nand-on-flash-bbt;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition at 0 {
+				label = "u-boot";
+				reg = <0 0x040000>;
+			};
+
+			partition at 40000 {
+				label = "kernel";
+				reg = <0x040000 0x500000>;
+			};
+		};
+	};
+};
-- 
1.9.1



From sergio.prado at e-labworks.com  Wed Oct 26 16:59:55 2016
From: sergio.prado at e-labworks.com (Sergio Prado)
Date: Wed, 26 Oct 2016 21:59:55 -0200
Subject: [PATCH v4 3/3] mtd: s3c2410: parse the device configuration from OF
 node
In-Reply-To: <1477526395-13103-1-git-send-email-sergio.prado@e-labworks.com>
References: <1477526395-13103-1-git-send-email-sergio.prado@e-labworks.com>
Message-ID: <1477526395-13103-4-git-send-email-sergio.prado@e-labworks.com>

Allows configuring Samsung's s3c2410 memory controller using a
devicetree.

Signed-off-by: Sergio Prado <sergio.prado at e-labworks.com>
---
 drivers/mtd/nand/s3c2410.c                     | 158 ++++++++++++++++++++++---
 include/linux/platform_data/mtd-nand-s3c2410.h |   1 +
 2 files changed, 143 insertions(+), 16 deletions(-)

diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index 371db0d48135..b13208c526f8 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -39,6 +39,8 @@
 #include <linux/slab.h>
 #include <linux/clk.h>
 #include <linux/cpufreq.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
@@ -185,6 +187,22 @@ struct s3c2410_nand_info {
 #endif
 };
 
+struct s3c24XX_nand_devtype_data {
+	enum s3c_cpu_type type;
+};
+
+static const struct s3c24XX_nand_devtype_data s3c2410_nand_devtype_data = {
+	.type = TYPE_S3C2410,
+};
+
+static const struct s3c24XX_nand_devtype_data s3c2412_nand_devtype_data = {
+	.type = TYPE_S3C2412,
+};
+
+static const struct s3c24XX_nand_devtype_data s3c2440_nand_devtype_data = {
+	.type = TYPE_S3C2440,
+};
+
 /* conversion functions */
 
 static struct s3c2410_nand_mtd *s3c2410_nand_mtd_toours(struct mtd_info *mtd)
@@ -794,6 +812,30 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
 	return -ENODEV;
 }
 
+static int s3c2410_nand_setup_data_interface(struct mtd_info *mtd,
+					     const struct nand_data_interface *conf,
+					     bool check_only)
+{
+	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+	struct s3c2410_platform_nand *pdata = info->platform;
+	const struct nand_sdr_timings *timings;
+	int tacls;
+
+	timings = nand_get_sdr_timings(conf);
+	if (IS_ERR(timings))
+		return -ENOTSUPP;
+
+	tacls = timings->tCLS_min - timings->tWP_min;
+	if (tacls < 0)
+		tacls = 0;
+
+	pdata->tacls  = DIV_ROUND_UP(tacls, 1000);
+	pdata->twrph0 = DIV_ROUND_UP(timings->tWP_min, 1000);
+	pdata->twrph1 = DIV_ROUND_UP(timings->tCLH_min, 1000);
+
+	return s3c2410_nand_setrate(info);
+}
+
 /**
  * s3c2410_nand_init_chip - initialise a single instance of an chip
  * @info: The base NAND controller the chip is on.
@@ -808,9 +850,12 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
 				   struct s3c2410_nand_mtd *nmtd,
 				   struct s3c2410_nand_set *set)
 {
+	struct device_node *np = info->device->of_node;
 	struct nand_chip *chip = &nmtd->chip;
 	void __iomem *regs = info->regs;
 
+	nand_set_flash_node(chip, set->of_node);
+
 	chip->write_buf    = s3c2410_nand_write_buf;
 	chip->read_buf     = s3c2410_nand_read_buf;
 	chip->select_chip  = s3c2410_nand_select_chip;
@@ -819,6 +864,13 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
 	chip->options	   = set->options;
 	chip->controller   = &info->controller;
 
+	/*
+	 * let's keep behavior unchanged for legacy boards booting via pdata and
+	 * auto-detect timings only when booting with a device tree.
+	 */
+	if (np)
+		chip->setup_data_interface = s3c2410_nand_setup_data_interface;
+
 	switch (info->cpu_type) {
 	case TYPE_S3C2410:
 		chip->IO_ADDR_W = regs + S3C2410_NFDATA;
@@ -859,12 +911,9 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
 	chip->ecc.mode = info->platform->ecc_mode;
 
 	/* If you use u-boot BBT creation code, specifying this flag will
-	 * let the kernel fish out the BBT from the NAND, and also skip the
-	 * full NAND scan that can take 1/2s or so. Little things... */
-	if (set->flash_bbt) {
+	 * let the kernel fish out the BBT from the NAND */
+	if (set->flash_bbt)
 		chip->bbt_options |= NAND_BBT_USE_FLASH;
-		chip->options |= NAND_SKIP_BBTSCAN;
-	}
 }
 
 /**
@@ -943,6 +992,77 @@ static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
 		return -EINVAL;
 	}
 
+	if (chip->bbt_options & NAND_BBT_USE_FLASH)
+		chip->options |= NAND_SKIP_BBTSCAN;
+
+	return 0;
+}
+
+static const struct of_device_id s3c24xx_nand_dt_ids[] = {
+	{
+		.compatible = "samsung,s3c2410-nand",
+		.data = &s3c2410_nand_devtype_data,
+	}, {
+		.compatible = "samsung,s3c2412-nand", /* also compatible with s3c6400 */
+		.data = &s3c2412_nand_devtype_data,
+	}, {
+		.compatible = "samsung,s3c2440-nand",
+		.data = &s3c2440_nand_devtype_data,
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, s3c24xx_nand_dt_ids);
+
+static int s3c24xx_nand_probe_dt(struct platform_device *pdev)
+{
+	const struct s3c24XX_nand_devtype_data *devtype_data;
+	struct s3c2410_platform_nand *pdata;
+	struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
+	struct device_node *np = pdev->dev.of_node, *child;
+	struct s3c2410_nand_set *sets;
+
+	devtype_data = of_device_get_match_data(&pdev->dev);
+	if (!devtype_data)
+		return -ENODEV;
+
+	info->cpu_type = devtype_data->type;
+
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	pdev->dev.platform_data = pdata;
+
+	pdata->nr_sets = of_get_child_count(np);
+	if (!pdata->nr_sets)
+		return 0;
+
+	sets = devm_kzalloc(&pdev->dev, sizeof(*sets) * pdata->nr_sets, GFP_KERNEL);
+	if (!sets)
+		return -ENOMEM;
+
+	pdata->sets = sets;
+
+	for_each_available_child_of_node(np, child) {
+
+		sets->name = (char *)child->name;
+		sets->of_node = child;
+		sets->nr_chips = 1;
+
+		of_node_get(child);
+
+		sets++;
+	}
+
+	return 0;
+}
+
+static int s3c24xx_nand_probe_pdata(struct platform_device *pdev)
+{
+	struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
+
+	info->cpu_type = platform_get_device_id(pdev)->driver_data;
+
 	return 0;
 }
 
@@ -955,8 +1075,7 @@ static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
 */
 static int s3c24xx_nand_probe(struct platform_device *pdev)
 {
-	struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
-	enum s3c_cpu_type cpu_type;
+	struct s3c2410_platform_nand *plat;
 	struct s3c2410_nand_info *info;
 	struct s3c2410_nand_mtd *nmtd;
 	struct s3c2410_nand_set *sets;
@@ -966,8 +1085,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 	int nr_sets;
 	int setno;
 
-	cpu_type = platform_get_device_id(pdev)->driver_data;
-
 	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
 	if (info == NULL) {
 		err = -ENOMEM;
@@ -989,6 +1106,16 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 
 	s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
 
+	if (pdev->dev.of_node)
+		err = s3c24xx_nand_probe_dt(pdev);
+	else
+		err = s3c24xx_nand_probe_pdata(pdev);
+
+	if (err)
+		goto exit_error;
+
+	plat = to_nand_plat(pdev);
+
 	/* allocate and map the resource */
 
 	/* currently we assume we have the one resource */
@@ -997,7 +1124,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 
 	info->device	= &pdev->dev;
 	info->platform	= plat;
-	info->cpu_type	= cpu_type;
 
 	info->regs = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(info->regs)) {
@@ -1007,12 +1133,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 
 	dev_dbg(&pdev->dev, "mapped registers at %p\n", info->regs);
 
-	/* initialise the hardware */
-
-	err = s3c2410_nand_inithw(info);
-	if (err != 0)
-		goto exit_error;
-
 	sets = (plat != NULL) ? plat->sets : NULL;
 	nr_sets = (plat != NULL) ? plat->nr_sets : 1;
 
@@ -1056,6 +1176,11 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 			sets++;
 	}
 
+	/* initialise the hardware */
+	err = s3c2410_nand_inithw(info);
+	if (err != 0)
+		goto exit_error;
+
 	err = s3c2410_nand_cpufreq_register(info);
 	if (err < 0) {
 		dev_err(&pdev->dev, "failed to init cpufreq support\n");
@@ -1156,6 +1281,7 @@ static int s3c24xx_nand_resume(struct platform_device *dev)
 	.id_table	= s3c24xx_driver_ids,
 	.driver		= {
 		.name	= "s3c24xx-nand",
+		.of_match_table = s3c24xx_nand_dt_ids,
 	},
 };
 
diff --git a/include/linux/platform_data/mtd-nand-s3c2410.h b/include/linux/platform_data/mtd-nand-s3c2410.h
index 729af13d1773..f01659026b26 100644
--- a/include/linux/platform_data/mtd-nand-s3c2410.h
+++ b/include/linux/platform_data/mtd-nand-s3c2410.h
@@ -40,6 +40,7 @@ struct s3c2410_nand_set {
 	char			*name;
 	int			*nr_map;
 	struct mtd_partition	*partitions;
+	struct device_node	*of_node;
 };
 
 struct s3c2410_platform_nand {
-- 
1.9.1



From boris.brezillon at free-electrons.com  Thu Oct 27 00:34:07 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Thu, 27 Oct 2016 09:34:07 +0200
Subject: OOB Test fails
In-Reply-To: <CALupW3CJ_gXS+7BrZEGTF8o0H8pJ_AOw0JcKOftSVaMVSbP1zQ@mail.gmail.com>
References: <39BC08CB3FF4C84CB6397533D4FC79095770D513@SEGOTEXCH02.ascom-Resource.ads>
 <CALupW3CJ_gXS+7BrZEGTF8o0H8pJ_AOw0JcKOftSVaMVSbP1zQ@mail.gmail.com>
Message-ID: <20161027093407.53a76657@bbrezillon>

Hi Steve,

On Wed, 26 Oct 2016 09:16:42 -0700
Steve deRosier <derosier at gmail.com> wrote:

> Hi Danesh,
> 
> 
> On Wed, Oct 26, 2016 at 9:07 AM, Danesh Daroui <Danesh.Daroui at ascom.com> wrote:
> > Hello all,
> >
> > I have executed MTD tests against an unmounted MTD device which uses UBIFS. All MTD tests except OOB test is passed where the OOB test fails from time to time and from device to device. I have read here:
> >
> > http://www.linux-mtd.infradead.org/faq/ubi.html#L_why_no_oob
> >
> > that UBIFS does not use OOB area. Therefore wanted to ask if failing this test does not need that there is any problem in our system (both HW and SW/configuration) and we can safely ignore the results for this test.
> >  
> 
> UBIFS doesn't use the OOB area, but your MTD driver most likely does.
> We don't want UBI or UBIFS messing with the OOB area because your
> flash, NAND controller and the MTD driver will use that. Bad block
> markers are set in the OOB area by the manufacturer in most NAND
> flashes and your controller and MTD driver will store and use the bits
> in the OOB to do error correction.
> 
> So, in short - the OOB area does need to function correctly.  As to if
> and why the OOB test is or isn't working is a different issue and I
> have no input on that.  All that depends on your mix of flash,
> controller and driver.

UBI/UBIFS are not using the OOB area, but I don't think it's a good
idea to encourage people to partially implement the NAND interface.
What if another layer needs to use the OOB area (JFFS2 does)?

Having your NAND controller driver pass all the MTD tests is a good
practice, let's keep it this way, even if some features are not
strictly required for the UBI/UBIFS use case.

Thanks,

Boris


From boris.brezillon at free-electrons.com  Thu Oct 27 00:38:01 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Thu, 27 Oct 2016 09:38:01 +0200
Subject: OOB Test fails
In-Reply-To: <39BC08CB3FF4C84CB6397533D4FC79095770D530@SEGOTEXCH02.ascom-Resource.ads>
References: <39BC08CB3FF4C84CB6397533D4FC79095770D513@SEGOTEXCH02.ascom-Resource.ads>
 <CALupW3CJ_gXS+7BrZEGTF8o0H8pJ_AOw0JcKOftSVaMVSbP1zQ@mail.gmail.com>
 <39BC08CB3FF4C84CB6397533D4FC79095770D530@SEGOTEXCH02.ascom-Resource.ads>
Message-ID: <20161027093801.7695f05e@bbrezillon>

Hi Danesh,

On Wed, 26 Oct 2016 16:28:43 +0000
Danesh Daroui <Danesh.Daroui at ascom.com> wrote:

> Hi Steve,
> 
> Thank you for your prompt answer. When I run OOB test (mtd_oobtest), for instance, one of devices always return verification failed error on a certain address. This is all we know and all the test reports. We use a quite old kernel i.e. 2.6.39 and this is one of the things that we suspect as a source of the problem that the kernel is outdated. Also, we consider the hardware failure since on some devices no error is shown on OOB test while on others more errors are shown and the address is changed randomly sometimes.

Yes, please, try with a newer kernel: I won't help debugging such an
old thing.

> 
> Our main problem is that sometimes UBIFS forces the device into read-only mode due to "bad CRC" error at startup when the device is booted. I am now running tests which are in "mtd_utils" for testing file system. I have started running two tests which are "simple/test_1" and "simple/test_2" which simply write until the drive is full and the read the data back and verify the correctness. During the test, I see lots of:
> 
> UBI: scrubbed PEB 585 (LEB 3:770), data moved to PEB 1772
> UBI: scrubbed PEB 1045 (LEB 3:1261), data moved to PEB 828
> UBI: scrubbed PEB 1493 (LEB 3:664), data moved to PEB 814
> UBI: scrubbed PEB 751 (LEB 3:1260), data moved to PEB 1772
> 
> In my mind, this is related to problematic hardware that the data is corrupted on many cells that UBIFS tries to move the data when a corruption is detected. My question is, whether this guess can be valid or this is mostly due to old kernel that we are using and upgrading to a new kernel would most likely solve the problems?

Well, I can't tell. It can be caused by a buggy NAND controller driver,
a bug in the UBI layer or maybe your NAND is simply worn.

Try with a newer kernel, and let's see what the MTD tests and MTD utils
tests say.

BTW, which NAND and NAND controller are your testing on?

Regards,

Boris


From Danesh.Daroui at ascom.com  Thu Oct 27 03:51:14 2016
From: Danesh.Daroui at ascom.com (Danesh Daroui)
Date: Thu, 27 Oct 2016 10:51:14 +0000
Subject: OOB Test fails
In-Reply-To: <20161027093801.7695f05e@bbrezillon>
References: <39BC08CB3FF4C84CB6397533D4FC79095770D513@SEGOTEXCH02.ascom-Resource.ads>
 <CALupW3CJ_gXS+7BrZEGTF8o0H8pJ_AOw0JcKOftSVaMVSbP1zQ@mail.gmail.com>
 <39BC08CB3FF4C84CB6397533D4FC79095770D530@SEGOTEXCH02.ascom-Resource.ads>
 <20161027093801.7695f05e@bbrezillon>
Message-ID: <39BC08CB3FF4C84CB6397533D4FC79095770D5E7@SEGOTEXCH02.ascom-Resource.ads>

Hi Boris,

Thanks for your help. We would really like to upgrade the Kernel and that is a wise approach of course, but we would like to be sure that this is due to the outdated Kernel or whether this is a hardware problem since Kernel upgrading is a time consuming and cumbersome task, but definitely necessary as you mentioned. Right now I am trying to run UBIFS tests which are included in "mtd_utils". I hope these tests will give me some hints if there is any problem is UBI/UBIFS layers. I had written my own stress test before which would test the memory on POSIX level (same as UBI/UBIFS layers more or less), and I experienced some crashes but could not identify what is the reason. For instance I could not find out if the crash happens due to a bug in driver or file system, etc. 

The flash memory we are using is a Micron NAND 1GiB 3,3V 8-bit and the driver delivered with Kernel 3.6.39. Have you heard about similar problem before? Or do you want me to give you more info about the hardware and the system we have under test?

Thanks again for your help,

Danesh Daroui


-----Original Message-----
From: Boris Brezillon [mailto:boris.brezillon at free-electrons.com] 
Sent: den 27 oktober 2016 09:38
To: Danesh Daroui <Danesh.Daroui at ascom.com>
Cc: Steve deRosier <derosier at gmail.com>; linux-mtd at lists.infradead.org
Subject: Re: OOB Test fails

Hi Danesh,

On Wed, 26 Oct 2016 16:28:43 +0000
Danesh Daroui <Danesh.Daroui at ascom.com> wrote:

> Hi Steve,
> 
> Thank you for your prompt answer. When I run OOB test (mtd_oobtest), for instance, one of devices always return verification failed error on a certain address. This is all we know and all the test reports. We use a quite old kernel i.e. 2.6.39 and this is one of the things that we suspect as a source of the problem that the kernel is outdated. Also, we consider the hardware failure since on some devices no error is shown on OOB test while on others more errors are shown and the address is changed randomly sometimes.

Yes, please, try with a newer kernel: I won't help debugging such an old thing.

> 
> Our main problem is that sometimes UBIFS forces the device into read-only mode due to "bad CRC" error at startup when the device is booted. I am now running tests which are in "mtd_utils" for testing file system. I have started running two tests which are "simple/test_1" and "simple/test_2" which simply write until the drive is full and the read the data back and verify the correctness. During the test, I see lots of:
> 
> UBI: scrubbed PEB 585 (LEB 3:770), data moved to PEB 1772
> UBI: scrubbed PEB 1045 (LEB 3:1261), data moved to PEB 828
> UBI: scrubbed PEB 1493 (LEB 3:664), data moved to PEB 814
> UBI: scrubbed PEB 751 (LEB 3:1260), data moved to PEB 1772
> 
> In my mind, this is related to problematic hardware that the data is corrupted on many cells that UBIFS tries to move the data when a corruption is detected. My question is, whether this guess can be valid or this is mostly due to old kernel that we are using and upgrading to a new kernel would most likely solve the problems?

Well, I can't tell. It can be caused by a buggy NAND controller driver, a bug in the UBI layer or maybe your NAND is simply worn.

Try with a newer kernel, and let's see what the MTD tests and MTD utils tests say.

BTW, which NAND and NAND controller are your testing on?

Regards,

Boris


From marcin.krzeminski at nokia.com  Thu Oct 27 05:19:31 2016
From: marcin.krzeminski at nokia.com (Krzeminski, Marcin (Nokia - PL/Wroclaw))
Date: Thu, 27 Oct 2016 12:19:31 +0000
Subject: MTD partitions vs erase regions
Message-ID: <AM4PR0701MB21304CE213B5F0B0534AB52FFEAA0@AM4PR0701MB2130.eurprd07.prod.outlook.com>

Hi Marek,

I am sending mtd partition and erase regions conflict that I had.
I admit I have no investigated it, since finally all is different.
This could make some problems with your idea of having erase sizes defined from DT.

Erase regions configuration:

nor->eraseregions[0].erasesize = 4096;
nor->eraseregions[0].numblocks = 8;
nor->eraseregions[0].offset = 0x0;

nor->eraseregions[1].erasesize = 32*1024;
nor->eraseregions[1].numblocks = 1;
nor->eraseregions[1].offset = 32*1024;

nor->eraseregions[2].erasesize = 64*1024;
nor->eraseregions[2].numblocks = div_u64_rem(mtd->size - 64*1024, info->sector_size, &rem);
nor->eraseregions[2].offset = 64*1024;

Device tree (mtd):

partition at 0 {
label = "all";
reg = <0x00000000 0x08000000>;
};

partition at 1 {
label = "small";
reg = <0x00000000 0x00008000>;
};

partition at 2 {
label = "rest"; 
reg = <0x00008000 0x07FF8000>;
};

Logs from startup:

[    1.187722] 0x000000000000-0x000008000000 : "all"
[    1.188498] device: 'mtd0': device_add
[    1.189563] device: 'mtd0ro': device_add
[    1.192359] device: '31:0': device_add
[    1.192810] device: 'mtdblock0': device_add
[    1.194504] 0x000000000000-0x000000008000 : "small"
[    1.195144] device: 'mtd1': device_add
[    1.196667] device: 'mtd1ro': device_add
[    1.198268] device: '31:1': device_add
[    1.199016] device: 'mtdblock1': device_add
[    1.200922] 0x000000008000-0x000008000000 : "rest"
[    1.201222] mtd: partition "rest" doesn't start on an erase block boundary -- force read-only
[    1.201613] device: 'mtd2': device_add
[    1.202541] device: 'mtd2ro': device_add
[    1.204659] device: '31:2': device_add
[    1.206233] device: 'mtdblock2': device_add

Message is from here:
http://lxr.free-electrons.com/source/drivers/mtd/mtdpart.c?v=4.4#L526

Regards,
Marcin



From richard at nod.at  Thu Oct 27 05:51:55 2016
From: richard at nod.at (Richard Weinberger)
Date: Thu, 27 Oct 2016 14:51:55 +0200
Subject: UBIFS LEB properties tree with odd addresses
In-Reply-To: <DA6901612C71B84D91459DE817C418AE26E0069D@XAP-PVEXMBX01.xlnx.xilinx.com>
References: <DA6901612C71B84D91459DE817C418AE26E0016D@XAP-PVEXMBX01.xlnx.xilinx.com>
 <e7f63f72-0dc1-54f4-b94c-2efef3e7af6b@nod.at>
 <DA6901612C71B84D91459DE817C418AE26E0069D@XAP-PVEXMBX01.xlnx.xilinx.com>
Message-ID: <c6e394c9-bbec-1121-7a93-268abcf934bf@nod.at>

Naga Sureshkumar Relli,

On 26.10.2016 14:11, Naga Sureshkumar Relli wrote:
> Hi Richard,
> 
> -----Original Message-----
> From: Richard Weinberger [mailto:richard at nod.at] 
> Sent: Wednesday, October 26, 2016 2:44 AM
> To: Naga Sureshkumar Relli <nagasure at xilinx.com>; Christoph Hellwig <hch at infradead.org>
> Cc: dwmw2 at infradead.org; computersforpeace at gmail.com; dedekind1 at gmail.com; adrian.hunter at intel.com; michal.simek at xilinx.com; Punnaiah Choudary Kalluri <punnaia at xilinx.com>; linux-mtd at lists.infradead.org; linux-kernel at vger.kernel.org; Boris Brezillon <boris.brezillon at free-electrons.com>
> Subject: Re: UBIFS LEB properties tree with odd addresses
> 
> Naga Sureshkumar Relli,
>>     Even bytes i.e. 0, 2, 4,... are transmitted on Lower Data Bus
>>     Odd bytes i.e. 1, 3, 5,.. are transmitted on Upper Data Bus.
> 
>> But these details are hidden from UBI?
> 
> Yes, Our controller driver will take care of these byte striping.
> 
>> So for temporary hack we did the following change In fs/ubifs/lpt.c In 
>> do_calc_lpt_geom(), added the following
>> +       if (c->pnode_sz % 2)
>> +               c->pnode_sz += 1; 
>> +       if (c->ltab_sz % 2)
>> +               c->ltab_sz += 1;
>>
>> Please kindly suggest, I need your inputs, changing the pnode_sz and ltab_sz to even in lpt.c, will it impact on any others?
> 
>> Hmm, the calculations in lpt.c use basic properties of the MTD (number of blocks, etc...).
>> Can you please double check which property causes the failure and also verify whether the MTD driver provides correct properties. i.e. page sizes, block size, number of blocks, ...
> 
> Yes, only pnode_sz and ltab_sz are odd values

Hm, these values depend only on basic MTD prperties AFAICT.

> And MTD info, here are my logs
> In Single Flash mode:
> Mtd->erasesize = 64KiB
> Mtd->size = 64MiB
> Mtd->numeraseregions = 0
> Nor->pagesize = 256
> 
> In Dual parallel mode:
> Mtd->erasesize = 128KiB
> Mtd->size = 128MiB
> Mtd->numeraseregions = 0
> Nor->pagesize = 512

How does UBI report them?
Maybe you miss some bit and set incorrect MTD properties.

A 128MiB MTD with 128KiB erase size is nothing special.

Thanks,
//richard


From boris.brezillon at free-electrons.com  Thu Oct 27 08:45:27 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Thu, 27 Oct 2016 17:45:27 +0200
Subject: OOB Test fails
In-Reply-To: <20161027093407.53a76657@bbrezillon>
References: <39BC08CB3FF4C84CB6397533D4FC79095770D513@SEGOTEXCH02.ascom-Resource.ads>
 <CALupW3CJ_gXS+7BrZEGTF8o0H8pJ_AOw0JcKOftSVaMVSbP1zQ@mail.gmail.com>
 <20161027093407.53a76657@bbrezillon>
Message-ID: <20161027174527.6003fd37@bbrezillon>

On Thu, 27 Oct 2016 09:34:07 +0200
Boris Brezillon <boris.brezillon at free-electrons.com> wrote:

> Hi Steve,
> 
> On Wed, 26 Oct 2016 09:16:42 -0700
> Steve deRosier <derosier at gmail.com> wrote:
> 
> > Hi Danesh,
> > 
> > 
> > On Wed, Oct 26, 2016 at 9:07 AM, Danesh Daroui <Danesh.Daroui at ascom.com> wrote:  
> > > Hello all,
> > >
> > > I have executed MTD tests against an unmounted MTD device which uses UBIFS. All MTD tests except OOB test is passed where the OOB test fails from time to time and from device to device. I have read here:
> > >
> > > http://www.linux-mtd.infradead.org/faq/ubi.html#L_why_no_oob
> > >
> > > that UBIFS does not use OOB area. Therefore wanted to ask if failing this test does not need that there is any problem in our system (both HW and SW/configuration) and we can safely ignore the results for this test.
> > >    
> > 
> > UBIFS doesn't use the OOB area, but your MTD driver most likely does.
> > We don't want UBI or UBIFS messing with the OOB area because your
> > flash, NAND controller and the MTD driver will use that. Bad block
> > markers are set in the OOB area by the manufacturer in most NAND
> > flashes and your controller and MTD driver will store and use the bits
> > in the OOB to do error correction.
> > 
> > So, in short - the OOB area does need to function correctly.  As to if
> > and why the OOB test is or isn't working is a different issue and I
> > have no input on that.  All that depends on your mix of flash,
> > controller and driver.  

My bad, I misread your sentence. I thought you we saying "the OOB area
does *not* need to function correctly".

My apologies for this misunderstanding, it seems we're on the same page.


From boris.brezillon at free-electrons.com  Thu Oct 27 09:12:25 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Thu, 27 Oct 2016 18:12:25 +0200
Subject: [PATCH v4 0/3] mtd: s3c2410: add device tree support
In-Reply-To: <1477526395-13103-1-git-send-email-sergio.prado@e-labworks.com>
References: <1477526395-13103-1-git-send-email-sergio.prado@e-labworks.com>
Message-ID: <20161027181225.3d5a6f04@bbrezillon>

On Wed, 26 Oct 2016 21:59:52 -0200
Sergio Prado <sergio.prado at e-labworks.com> wrote:

> This series adds support for configuring Samsung's s3c2410 and
> compatible flash memory controller via devicetree.
> 
> Tested on FriendlyARM mini2440, based on s3c2440 SoC.
> 
> Patch 3 depends on patch 1.

Applied.

Thanks,

Boris

> 
> Changes since v3:
> - apply the timings in the end of ->setup_data_interface so the
>   timings can be changed at runtime by the MTD core.
> 
> Changes since v2:
> - conditionally assign chip->setup_data_interface to
>   s3c2410_nand_setup_data_interface if booting via device tree
> 
> Changes since v1:
> - automate timing selection when booting with a device tree
> - make s3c24XX_nand_devtype_data structs "static const"
> - removing samsung,s3c6400-nand compatible since it is equivalent to
>   samsung,s3c2412-nand
> 
> Changes since initial version:
> - patch converted to a patch series
> - read timings from nand_sdr_timings when booting with a device tree
> - naming improvements in the device tree binding
>   (s/nand/nand-controller/, s/_/-, s/children/child)
> - dropped property samsung,ignore_unset_ecc
> - remove @0 from nand device node
> - checking pdev->dev.of_node instead of using ifdef CONFIG_OF_MTD
> - preventing from parsing device tree properties twice
> - increment the nand controller child node refcount, since we
>   maintain a reference to it and its name field
> - using of_device_get_match_data() instead of of_match_device()
>   to make the code simpler
> - remove CONFIG_MTD_NAND_S3C2410_HWECC compile option so we can
>   select ECC mode using nand-ecc-mode property in the device tree
> 
> Sergio Prado (3):
>   mtd: s3c2410: make ecc mode configurable via platform data
>   dt-bindings: mtd: add DT binding for s3c2410 flash controller
>   mtd: s3c2410: parse the device configuration from OF node
> 
>  .../devicetree/bindings/mtd/samsung-s3c2410.txt    |  56 +++++
>  arch/arm/mach-s3c24xx/common-smdk.c                |   1 +
>  arch/arm/mach-s3c24xx/mach-anubis.c                |   1 +
>  arch/arm/mach-s3c24xx/mach-at2440evb.c             |   1 +
>  arch/arm/mach-s3c24xx/mach-bast.c                  |   1 +
>  arch/arm/mach-s3c24xx/mach-gta02.c                 |   1 +
>  arch/arm/mach-s3c24xx/mach-jive.c                  |   1 +
>  arch/arm/mach-s3c24xx/mach-mini2440.c              |   1 +
>  arch/arm/mach-s3c24xx/mach-osiris.c                |   1 +
>  arch/arm/mach-s3c24xx/mach-qt2410.c                |   1 +
>  arch/arm/mach-s3c24xx/mach-rx1950.c                |   1 +
>  arch/arm/mach-s3c24xx/mach-rx3715.c                |   1 +
>  arch/arm/mach-s3c24xx/mach-vstms.c                 |   1 +
>  arch/arm/mach-s3c64xx/mach-hmt.c                   |   1 +
>  arch/arm/mach-s3c64xx/mach-mini6410.c              |   1 +
>  arch/arm/mach-s3c64xx/mach-real6410.c              |   1 +
>  drivers/mtd/nand/Kconfig                           |   9 -
>  drivers/mtd/nand/s3c2410.c                         | 277 +++++++++++++++------
>  include/linux/platform_data/mtd-nand-s3c2410.h     |   7 +-
>  19 files changed, 278 insertions(+), 86 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt
> 



From zach.brown at ni.com  Thu Oct 27 12:14:02 2016
From: zach.brown at ni.com (Zach Brown)
Date: Thu, 27 Oct 2016 14:14:02 -0500
Subject: [RESEND PATCH v2 3/3] mtd: ubi: use 'max_bad_blocks' to compute
 bad_peb_limit if available
In-Reply-To: <1477595642-11454-1-git-send-email-zach.brown@ni.com>
References: <1477595642-11454-1-git-send-email-zach.brown@ni.com>
Message-ID: <1477595642-11454-4-git-send-email-zach.brown@ni.com>

From: Jeff Westfahl <jeff.westfahl at ni.com>

Use the MTD function 'max_bad_blocks' to compute the UBI bad_peb_limit,
if the function is implemented for an MTD and doesn't return an error.

Signed-off-by: Jeff Westfahl <jeff.westfahl at ni.com>
Signed-off-by: Zach Brown <zach.brown at ni.com>
---
 drivers/mtd/ubi/build.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 85d54f3..0648863 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -584,6 +584,15 @@ static int get_bad_peb_limit(const struct ubi_device *ubi, int max_beb_per1024)
 	int limit, device_pebs;
 	uint64_t device_size;
 
+	/* If the MTD provides a max_bad_blocks function, use that value. Fall
+	 * back to max_beb_per1024 if that function returns an error.
+	 */
+	if (ubi->mtd->_max_bad_blocks) {
+		limit = ubi->mtd->_max_bad_blocks(ubi->mtd, 0, ubi->mtd->size);
+		if (limit > 0)
+			return limit;
+	}
+
 	if (!max_beb_per1024)
 		return 0;
 
-- 
2.7.4



From zach.brown at ni.com  Thu Oct 27 12:13:59 2016
From: zach.brown at ni.com (Zach Brown)
Date: Thu, 27 Oct 2016 14:13:59 -0500
Subject: [RESEND PATCH v2 0/3] mtd: use ONFI bad blocks per LUN to calculate
 UBI bad PEB limit
Message-ID: <1477595642-11454-1-git-send-email-zach.brown@ni.com>

For ONFI-compliant NAND devices, the ONFI parameters report the maximum number
of bad blocks per LUN that will be encountered over the lifetime of the device,
so we can use that information to get a more accurate (and smaller) value for
the UBI bad PEB limit.

The ONFI parameter "maxiumum number of bad blocks per LUN" is the max number of
bad blocks that each individual LUN will ever ecounter. It is not the number of
bad blocks to reserve for the nand device per LUN in the device.

This means that in the worst case a UBI device spanning X LUNs will encounter
"maximum number of bad blocks per LUN" * X bad blocks. The implementation in
this patch assumes this worst case and allocates bad block accordingly.

These patches are ordered in terms of their dependencies, but ideally, all 3
would need to be applied for this to work as intended.

v1:
 * Changed commit message to address concerns from v1[1] about this patch set
   making best case assumptions.

[1]
http://lkml.iu.edu/hypermail/linux/kernel/1505.1/04822.html

Jeff Westfahl (3):
  mtd: introduce function max_bad_blocks
  mtd: nand: implement 'max_bad_blocks' mtd function
  mtd: ubi: use 'max_bad_blocks' to compute bad_peb_limit if available

 drivers/mtd/mtdpart.c        | 12 ++++++++++++
 drivers/mtd/nand/nand_base.c | 34 ++++++++++++++++++++++++++++++++++
 drivers/mtd/ubi/build.c      |  9 +++++++++
 include/linux/mtd/mtd.h      |  1 +
 4 files changed, 56 insertions(+)

-- 
2.7.4



From zach.brown at ni.com  Thu Oct 27 12:14:00 2016
From: zach.brown at ni.com (Zach Brown)
Date: Thu, 27 Oct 2016 14:14:00 -0500
Subject: [RESEND PATCH v2 1/3] mtd: introduce function max_bad_blocks
In-Reply-To: <1477595642-11454-1-git-send-email-zach.brown@ni.com>
References: <1477595642-11454-1-git-send-email-zach.brown@ni.com>
Message-ID: <1477595642-11454-2-git-send-email-zach.brown@ni.com>

From: Jeff Westfahl <jeff.westfahl at ni.com>

If implemented, 'max_bad_blocks' returns the maximum number of bad
blocks to reserve for an MTD. An implementation for NAND is coming soon.

Signed-off-by: Jeff Westfahl <jeff.westfahl at ni.com>
Signed-off-by: Zach Brown <zach.brown at ni.com>
---
 drivers/mtd/mtdpart.c   | 12 ++++++++++++
 include/linux/mtd/mtd.h |  1 +
 2 files changed, 13 insertions(+)

diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index fccdd49..565f0dd 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -349,6 +349,16 @@ static const struct mtd_ooblayout_ops part_ooblayout_ops = {
 	.free = part_ooblayout_free,
 };
 
+static int part_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+	struct mtd_part *part = mtd_to_part(mtd);
+
+	if ((len + ofs) > mtd->size)
+		return -EINVAL;
+	return part->master->_max_bad_blocks(part->master,
+					     ofs + part->offset, len);
+}
+
 static inline void free_partition(struct mtd_part *p)
 {
 	kfree(p->mtd.name);
@@ -481,6 +491,8 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
 	if (master->_put_device)
 		slave->mtd._put_device = part_put_device;
 
+	if (master->_max_bad_blocks)
+		slave->mtd._max_bad_blocks = part_max_bad_blocks;
 	slave->mtd._erase = part_erase;
 	slave->master = master;
 	slave->offset = part->offset;
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 13f8052..bd277eb 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -322,6 +322,7 @@ struct mtd_info {
 	int (*_block_isreserved) (struct mtd_info *mtd, loff_t ofs);
 	int (*_block_isbad) (struct mtd_info *mtd, loff_t ofs);
 	int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs);
+	int (*_max_bad_blocks) (struct mtd_info *mtd, loff_t ofs, size_t len);
 	int (*_suspend) (struct mtd_info *mtd);
 	void (*_resume) (struct mtd_info *mtd);
 	void (*_reboot) (struct mtd_info *mtd);
-- 
2.7.4



From zach.brown at ni.com  Thu Oct 27 12:14:01 2016
From: zach.brown at ni.com (Zach Brown)
Date: Thu, 27 Oct 2016 14:14:01 -0500
Subject: [RESEND PATCH v2 2/3] mtd: nand: implement 'max_bad_blocks' mtd
 function
In-Reply-To: <1477595642-11454-1-git-send-email-zach.brown@ni.com>
References: <1477595642-11454-1-git-send-email-zach.brown@ni.com>
Message-ID: <1477595642-11454-3-git-send-email-zach.brown@ni.com>

From: Jeff Westfahl <jeff.westfahl at ni.com>

Implement the new mtd function 'max_bad_blocks'. Use the ONFI parameter
page to find the maximum bad blocks to reserve for an MTD, taking into
account how many LUNs the MTD spans.

Signed-off-by: Jeff Westfahl <jeff.westfahl at ni.com>
Signed-off-by: Zach Brown <zach.brown at ni.com>
---
 drivers/mtd/nand/nand_base.c | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index e5718e5..ac08224 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -3226,6 +3226,39 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
 }
 
 /**
+ * nand_max_bad_blocks - [MTD Interface] Max number of bad blocks for an mtd
+ * @mtd: MTD device structure
+ * @ofs: offset relative to mtd start
+ * @len: length of mtd
+ */
+static int nand_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	uint32_t part_start_block;
+	uint32_t part_end_block;
+	uint32_t part_start_lun;
+	uint32_t part_end_lun;
+
+	/* ONFI is used to determine the maximum bad block count. */
+	if (!chip->onfi_version)
+		return -ENOTSUPP;
+
+	/* Get the start and end of the partition in erase blocks. */
+	part_start_block = mtd_div_by_eb(ofs, mtd);
+	part_end_block = mtd_div_by_eb(len, mtd) + part_start_block - 1;
+
+	/* Get the start and end LUNs of the partition. */
+	part_start_lun = part_start_block / chip->onfi_params.blocks_per_lun;
+	part_end_lun = part_end_block / chip->onfi_params.blocks_per_lun;
+
+	/* Look up the bad blocks per unit and multiply by the number of units
+	 * that the partition spans.
+	 */
+	return chip->onfi_params.bb_per_lun *
+		(part_end_lun - part_start_lun + 1);
+}
+
+/**
  * nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand
  * @mtd: MTD device structure
  * @chip: nand chip info structure
@@ -4743,6 +4776,7 @@ int nand_scan_tail(struct mtd_info *mtd)
 	mtd->_block_isreserved = nand_block_isreserved;
 	mtd->_block_isbad = nand_block_isbad;
 	mtd->_block_markbad = nand_block_markbad;
+	mtd->_max_bad_blocks = nand_max_bad_blocks;
 	mtd->writebufsize = mtd->writesize;
 
 	/*
-- 
2.7.4



From boris.brezillon at free-electrons.com  Thu Oct 27 12:56:53 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Thu, 27 Oct 2016 21:56:53 +0200
Subject: [RESEND PATCH v2 0/3] mtd: use ONFI bad blocks per LUN to
 calculate UBI bad PEB limit
In-Reply-To: <1477595642-11454-1-git-send-email-zach.brown@ni.com>
References: <1477595642-11454-1-git-send-email-zach.brown@ni.com>
Message-ID: <20161027215653.6f97858d@bbrezillon>

Hi Zach,

Please do not resend after only one week. Reviewing this series was on
my TODO list ;).

On Thu, 27 Oct 2016 14:13:59 -0500
Zach Brown <zach.brown at ni.com> wrote:

> For ONFI-compliant NAND devices, the ONFI parameters report the maximum number
> of bad blocks per LUN that will be encountered over the lifetime of the device,
> so we can use that information to get a more accurate (and smaller) value for
> the UBI bad PEB limit.
> 
> The ONFI parameter "maxiumum number of bad blocks per LUN" is the max number of
> bad blocks that each individual LUN will ever ecounter. It is not the number of
> bad blocks to reserve for the nand device per LUN in the device.
> 
> This means that in the worst case a UBI device spanning X LUNs will encounter
> "maximum number of bad blocks per LUN" * X bad blocks. The implementation in
> this patch assumes this worst case and allocates bad block accordingly.

That's a discussion I had with Richard a few months ago, and I didn't
know someone had already proposed a patch for that. So that's all good
news.
Indeed, I really think we should use information retrieved at flash
detection time rather than asking the user to explicitly tweak the
bad_peb_limit value for its chip.

> 
> These patches are ordered in terms of their dependencies, but ideally, all 3
> would need to be applied for this to work as intended.
> 
> v1:
>  * Changed commit message to address concerns from v1[1] about this patch set
>    making best case assumptions.
> 
> [1]
> http://lkml.iu.edu/hypermail/linux/kernel/1505.1/04822.html
> 
> Jeff Westfahl (3):
>   mtd: introduce function max_bad_blocks
>   mtd: nand: implement 'max_bad_blocks' mtd function
>   mtd: ubi: use 'max_bad_blocks' to compute bad_peb_limit if available
> 
>  drivers/mtd/mtdpart.c        | 12 ++++++++++++
>  drivers/mtd/nand/nand_base.c | 34 ++++++++++++++++++++++++++++++++++
>  drivers/mtd/ubi/build.c      |  9 +++++++++
>  include/linux/mtd/mtd.h      |  1 +
>  4 files changed, 56 insertions(+)
> 



From boris.brezillon at free-electrons.com  Thu Oct 27 13:01:47 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Thu, 27 Oct 2016 22:01:47 +0200
Subject: [RESEND PATCH v2 1/3] mtd: introduce function max_bad_blocks
In-Reply-To: <1477595642-11454-2-git-send-email-zach.brown@ni.com>
References: <1477595642-11454-1-git-send-email-zach.brown@ni.com>
 <1477595642-11454-2-git-send-email-zach.brown@ni.com>
Message-ID: <20161027220147.4ac902c6@bbrezillon>

On Thu, 27 Oct 2016 14:14:00 -0500
Zach Brown <zach.brown at ni.com> wrote:

> From: Jeff Westfahl <jeff.westfahl at ni.com>
> 
> If implemented, 'max_bad_blocks' returns the maximum number of bad
> blocks to reserve for an MTD. An implementation for NAND is coming soon.
> 
> Signed-off-by: Jeff Westfahl <jeff.westfahl at ni.com>
> Signed-off-by: Zach Brown <zach.brown at ni.com>
> ---
>  drivers/mtd/mtdpart.c   | 12 ++++++++++++
>  include/linux/mtd/mtd.h |  1 +
>  2 files changed, 13 insertions(+)
> 
> diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
> index fccdd49..565f0dd 100644
> --- a/drivers/mtd/mtdpart.c
> +++ b/drivers/mtd/mtdpart.c
> @@ -349,6 +349,16 @@ static const struct mtd_ooblayout_ops part_ooblayout_ops = {
>  	.free = part_ooblayout_free,
>  };
>  
> +static int part_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len)
> +{
> +	struct mtd_part *part = mtd_to_part(mtd);
> +
> +	if ((len + ofs) > mtd->size)
> +		return -EINVAL;
> +	return part->master->_max_bad_blocks(part->master,
> +					     ofs + part->offset, len);
> +}
> +
>  static inline void free_partition(struct mtd_part *p)
>  {
>  	kfree(p->mtd.name);
> @@ -481,6 +491,8 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
>  	if (master->_put_device)
>  		slave->mtd._put_device = part_put_device;
>  
> +	if (master->_max_bad_blocks)
> +		slave->mtd._max_bad_blocks = part_max_bad_blocks;
>  	slave->mtd._erase = part_erase;
>  	slave->master = master;
>  	slave->offset = part->offset;
> diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
> index 13f8052..bd277eb 100644
> --- a/include/linux/mtd/mtd.h
> +++ b/include/linux/mtd/mtd.h
> @@ -322,6 +322,7 @@ struct mtd_info {
>  	int (*_block_isreserved) (struct mtd_info *mtd, loff_t ofs);
>  	int (*_block_isbad) (struct mtd_info *mtd, loff_t ofs);
>  	int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs);
> +	int (*_max_bad_blocks) (struct mtd_info *mtd, loff_t ofs, size_t len);

Please provide an helper function around this hook, so that you can
call the helper in patch 3 and won't have to test the ->_max_bad_blocks
field directly.

This helper should return -ENOTSUPP if ->_max_bad_blocks is not
implemented.

>  	int (*_suspend) (struct mtd_info *mtd);
>  	void (*_resume) (struct mtd_info *mtd);
>  	void (*_reboot) (struct mtd_info *mtd);



From boris.brezillon at free-electrons.com  Thu Oct 27 13:04:21 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Thu, 27 Oct 2016 22:04:21 +0200
Subject: [RESEND PATCH v2 2/3] mtd: nand: implement 'max_bad_blocks' mtd
 function
In-Reply-To: <1477595642-11454-3-git-send-email-zach.brown@ni.com>
References: <1477595642-11454-1-git-send-email-zach.brown@ni.com>
 <1477595642-11454-3-git-send-email-zach.brown@ni.com>
Message-ID: <20161027220421.7a1471be@bbrezillon>

On Thu, 27 Oct 2016 14:14:01 -0500
Zach Brown <zach.brown at ni.com> wrote:

> From: Jeff Westfahl <jeff.westfahl at ni.com>
> 
> Implement the new mtd function 'max_bad_blocks'. Use the ONFI parameter
> page to find the maximum bad blocks to reserve for an MTD, taking into
> account how many LUNs the MTD spans.
> 
> Signed-off-by: Jeff Westfahl <jeff.westfahl at ni.com>
> Signed-off-by: Zach Brown <zach.brown at ni.com>
> ---
>  drivers/mtd/nand/nand_base.c | 34 ++++++++++++++++++++++++++++++++++
>  1 file changed, 34 insertions(+)
> 
> diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
> index e5718e5..ac08224 100644
> --- a/drivers/mtd/nand/nand_base.c
> +++ b/drivers/mtd/nand/nand_base.c
> @@ -3226,6 +3226,39 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
>  }
>  
>  /**
> + * nand_max_bad_blocks - [MTD Interface] Max number of bad blocks for an mtd
> + * @mtd: MTD device structure
> + * @ofs: offset relative to mtd start
> + * @len: length of mtd
> + */
> +static int nand_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len)
> +{
> +	struct nand_chip *chip = mtd_to_nand(mtd);
> +	uint32_t part_start_block;
> +	uint32_t part_end_block;
> +	uint32_t part_start_lun;
> +	uint32_t part_end_lun;
> +
> +	/* ONFI is used to determine the maximum bad block count. */
> +	if (!chip->onfi_version)
> +		return -ENOTSUPP;
> +
> +	/* Get the start and end of the partition in erase blocks. */
> +	part_start_block = mtd_div_by_eb(ofs, mtd);
> +	part_end_block = mtd_div_by_eb(len, mtd) + part_start_block - 1;
> +
> +	/* Get the start and end LUNs of the partition. */
> +	part_start_lun = part_start_block / chip->onfi_params.blocks_per_lun;
> +	part_end_lun = part_end_block / chip->onfi_params.blocks_per_lun;
> +
> +	/* Look up the bad blocks per unit and multiply by the number of units
> +	 * that the partition spans.
> +	 */
> +	return chip->onfi_params.bb_per_lun *
> +		(part_end_lun - part_start_lun + 1);

Well, it's a good start, but I'd like to have something that works even
for non-ONFI chips. How about adding a field in nand_chip and filling
this field when the ONFI param page is retrieved/parsed. This way we
can easily extend the implementation for full-id entries in the
nand_ids table or for JEDEC compliant chips (assuming the JEDEC
standard provides such information).

> +}
> +
> +/**
>   * nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand
>   * @mtd: MTD device structure
>   * @chip: nand chip info structure
> @@ -4743,6 +4776,7 @@ int nand_scan_tail(struct mtd_info *mtd)
>  	mtd->_block_isreserved = nand_block_isreserved;
>  	mtd->_block_isbad = nand_block_isbad;
>  	mtd->_block_markbad = nand_block_markbad;
> +	mtd->_max_bad_blocks = nand_max_bad_blocks;
>  	mtd->writebufsize = mtd->writesize;
>  
>  	/*



From boris.brezillon at free-electrons.com  Thu Oct 27 13:05:24 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Thu, 27 Oct 2016 22:05:24 +0200
Subject: [RESEND PATCH v2 3/3] mtd: ubi: use 'max_bad_blocks' to compute
 bad_peb_limit if available
In-Reply-To: <1477595642-11454-4-git-send-email-zach.brown@ni.com>
References: <1477595642-11454-1-git-send-email-zach.brown@ni.com>
 <1477595642-11454-4-git-send-email-zach.brown@ni.com>
Message-ID: <20161027220524.61560d14@bbrezillon>

On Thu, 27 Oct 2016 14:14:02 -0500
Zach Brown <zach.brown at ni.com> wrote:

> From: Jeff Westfahl <jeff.westfahl at ni.com>
> 
> Use the MTD function 'max_bad_blocks' to compute the UBI bad_peb_limit,
> if the function is implemented for an MTD and doesn't return an error.
> 
> Signed-off-by: Jeff Westfahl <jeff.westfahl at ni.com>
> Signed-off-by: Zach Brown <zach.brown at ni.com>
> ---
>  drivers/mtd/ubi/build.c | 9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
> index 85d54f3..0648863 100644
> --- a/drivers/mtd/ubi/build.c
> +++ b/drivers/mtd/ubi/build.c
> @@ -584,6 +584,15 @@ static int get_bad_peb_limit(const struct ubi_device *ubi, int max_beb_per1024)
>  	int limit, device_pebs;
>  	uint64_t device_size;
>  
> +	/* If the MTD provides a max_bad_blocks function, use that value. Fall
> +	 * back to max_beb_per1024 if that function returns an error.
> +	 */
> +	if (ubi->mtd->_max_bad_blocks) {
> +		limit = ubi->mtd->_max_bad_blocks(ubi->mtd, 0, ubi->mtd->size);
> +		if (limit > 0)
> +			return limit;
> +	}

Please use the helper I was suggesting in patch 1.

> +
>  	if (!max_beb_per1024)
>  		return 0;
>  



From computersforpeace at gmail.com  Thu Oct 27 13:19:30 2016
From: computersforpeace at gmail.com (Brian Norris)
Date: Thu, 27 Oct 2016 13:19:30 -0700
Subject: [PATCH v2 1/1] MAINTAINERS: add a maintainer for the SPI NOR
 subsystem
In-Reply-To: <CAD6G_RRm0ttasw8DAQvE2fOpXd61tTsbNwyy_vJ_quAO0y3swA@mail.gmail.com>
References: <aad52b708dcf6754edab87d2e0afe4f0ee6831f9.1476891131.git.cyrille.pitchen@atmel.com>
 <d92f8ef8-be78-0386-fa84-117c3cae6459@denx.de>
 <CAD6G_RRm0ttasw8DAQvE2fOpXd61tTsbNwyy_vJ_quAO0y3swA@mail.gmail.com>
Message-ID: <20161027201930.GA1582@localhost>

Hi,

On Fri, Oct 21, 2016 at 11:28:00PM +0530, Jagan Teki wrote:
> On Thu, Oct 20, 2016 at 7:12 PM, Marek Vasut <marex at denx.de> wrote:
> > On 10/19/2016 05:34 PM, Cyrille Pitchen wrote:
> >> I would like to volunteer as a maintainer for the SPI NOR part of the MTD
> >> subsystem.

Thanks! I'll be happy to have the help.

[...]

> >> Also both Marek Vasut and Richard Weinberger have volunteered as well as
> >> maintainers for the SPI NOR subsystem.

Snipped all mention of Richard, since he did not volunteer :)

> >> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
> >> Acked-by: Boris Brezillon <boris.brezillon at free-electrons.com>
> >
> > Acked-by: Marek Vasut <marek.vasut at gmail.com>
> 
> Acked-by: Jagan Teki <jteki at openedev.com>
> 
> >
> > btw I think I'll need higher privileges in patchwork to fiddle with patches.

I expect you'll be mailing Jeremy soon then.

> >> ---
> >> ChangeLog:
> >>
> >> v1 -> v2:
> >> - add Marek and Richard as maintainers.
> >> - add Acked-by from Boris Brezillon.
> >>
> >>
> >>  MAINTAINERS | 12 ++++++++++++
> >>  1 file changed, 12 insertions(+)
> >>
> >> diff --git a/MAINTAINERS b/MAINTAINERS
> >> index 757f9c4b388d..7e63b2015072 100644
> >> --- a/MAINTAINERS
> >> +++ b/MAINTAINERS
> >> @@ -11390,6 +11390,18 @@ W:   http://www.st.com/spear
> >>  S:   Maintained
> >>  F:   drivers/clk/spear/
> >>
> >> +SPI NOR SUBSYSTEM
> >> +M:   Cyrille Pitchen <cyrille.pitchen at atmel.com>
> >> +M:   Marek Vasut <marek.vasut at gmail.com>
> >> +M:   Richard Weinberger <richard at nod.at>

Snipped the above line, and pushed to linux-mtd.git.

> 
> May be I was little late, but if there is any space for one more or so
> I would also like to co-maintain? Currently I am maintaining
> SPI/SPI-FLASH for u-boot and working for generic MTD (with u-boot
> driver model) + SPI-NOR addition on u-boot which eventually similar
> conceptual theory what Linux follows.

I'd be happy to add more if the others think that it's warranted. If
not, I'm sure all involved would still be happy with extra review, and
that could serve nearly the same purpose, as long as the committers
don't fall asleep like I admittedly have too often.

Regards,
Brian


From marex at denx.de  Thu Oct 27 13:21:47 2016
From: marex at denx.de (Marek Vasut)
Date: Thu, 27 Oct 2016 22:21:47 +0200
Subject: [PATCH v2 1/1] MAINTAINERS: add a maintainer for the SPI NOR
 subsystem
In-Reply-To: <20161027201930.GA1582@localhost>
References: <aad52b708dcf6754edab87d2e0afe4f0ee6831f9.1476891131.git.cyrille.pitchen@atmel.com>
 <d92f8ef8-be78-0386-fa84-117c3cae6459@denx.de>
 <CAD6G_RRm0ttasw8DAQvE2fOpXd61tTsbNwyy_vJ_quAO0y3swA@mail.gmail.com>
 <20161027201930.GA1582@localhost>
Message-ID: <f3e4c12e-fda1-9ff3-e875-03d1a5e08341@denx.de>

On 10/27/2016 10:19 PM, Brian Norris wrote:
> Hi,
> 
> On Fri, Oct 21, 2016 at 11:28:00PM +0530, Jagan Teki wrote:
>> On Thu, Oct 20, 2016 at 7:12 PM, Marek Vasut <marex at denx.de> wrote:
>>> On 10/19/2016 05:34 PM, Cyrille Pitchen wrote:
>>>> I would like to volunteer as a maintainer for the SPI NOR part of the MTD
>>>> subsystem.
> 
> Thanks! I'll be happy to have the help.
> 
> [...]
> 
>>>> Also both Marek Vasut and Richard Weinberger have volunteered as well as
>>>> maintainers for the SPI NOR subsystem.
> 
> Snipped all mention of Richard, since he did not volunteer :)
> 
>>>> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
>>>> Acked-by: Boris Brezillon <boris.brezillon at free-electrons.com>
>>>
>>> Acked-by: Marek Vasut <marek.vasut at gmail.com>
>>
>> Acked-by: Jagan Teki <jteki at openedev.com>
>>
>>>
>>> btw I think I'll need higher privileges in patchwork to fiddle with patches.
> 
> I expect you'll be mailing Jeremy soon then.
> 
Done


-- 
Best regards,
Marek Vasut


From computersforpeace at gmail.com  Thu Oct 27 13:57:32 2016
From: computersforpeace at gmail.com (Brian Norris)
Date: Thu, 27 Oct 2016 13:57:32 -0700
Subject: [PATCH] MAINTAINERS: add more people to the MTD maintainer team
In-Reply-To: <1477312526-7563-1-git-send-email-boris.brezillon@free-electrons.com>
References: <1477312526-7563-1-git-send-email-boris.brezillon@free-electrons.com>
Message-ID: <20161027205732.GB1582@localhost>

On Mon, Oct 24, 2016 at 02:35:26PM +0200, Boris Brezillon wrote:
> Brian has been maintaining the MTD subsystem alone for several years
> now, and maintaining such a subsystem can really be time consuming.
> 
> Create a maintainer team formed of the most active MTD contributors
> to help Brian with this task, which will hopefully improve the
> subsystem reactivity.
> 
> Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>

Thanks to all the volunteers! Applied to linux-mtd.git. Will send to
Linus once we can collect other outstanding fixes.

> ---
> Hi all,
> 
> I'm just trying to summarize what I understood the process would be,
> don't hesitate to correct me if I'm wrong.
> 
> For each release we will assign a specific MTD maintainer which will be
> responsible for taking MTD core patches and pulling spi-nor and nand PRs
> into the MTD tree and eventually send one or several PRs to Linus.

I had imagined that the "release owner" role wouldn't necessarily imply
exclusive commit rights, but that they'd just the primary one
responsible. I don't see a problem with other maintainer(s) applying
patches as long as they've gotten the proper review. Or would that be
too confusing?

But that's something not discussed here so far: review requirements. I
expect we need a minimum of 1 reviewer (where reviewer may be the one
applying it) that isn't the author. And for bigger things (i.e., not
trivial and not just a leaf driver) maybe 2. Hopefully in the form of
explicit Reviewed-by or Acked-by. And that means that for NAND or
SPI-NOR PRs, that may require preempting the "release owner" (e.g., if
Boris is supposed to be the "owner" for a release, he'll have to find
someone else to review his NAND PR -- I'm still happy to do so for now,
but others are welcome).

And for PRs to Linus: if y'all don't mind, I'd still like to have a
last look at things from the brand new maintainers, at least for now.
(Boris and Richard would probably also be good candidates for the last
review / PR, as they've proven to maintain things well already.) I'm
sure that can be relaxed after a release or so (say, after 4.10?).

Thoughts?

Also, everyone should make their attempts to get their PGP keys into the
web-of-trust. And we need David to get people infradead.org permissions.

One other point of order: if it isn't clear, I've been using
l2-mtd.git/master as the -next "branch" and linux-mtd.git/master as the
-current-release "branch." We should work extra hard to avoid rebasing
in either of those trees now. In fact, I'll go disable non-ff pushes
now...

I also currently have a server-side post-receive git hook installed in
l2-mtd.git that tries to update patchwork. It's not 100% accurate
because it matches contents (which might be the same across multiple
revisions of a series). I should probably remove or modify that before
others start pushing there.

> For fixes that are submitted after -rc1, I usually ask Brian to apply
> them directly into the MTD tree (I don't think there's a real need to
> prepare spi-nor and nand PRs for fixes), so we can proceed the same
> way: ask the maintainer assigned to this release to also take care of
> applying fixes and sending PRs to Linus before each -rc.

I'm flexible on this. If the "release owner" is attentive enough,
applying them to the MTD tree works just fine. But if a PR helps (as
Boris is planning to do right now for 4.9-rc) I don't see a problem with
that either.

> If you have other ideas, or would like to proceed differently, don't
> hesitate propose them.

Good luck, and happy MTD hacking :)

Brian

> Thanks,
> 
> Boris
> ---
>  MAINTAINERS | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 1cd38a7e0064..cbf9583fdbe7 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -7912,6 +7912,10 @@ F:	mm/
>  MEMORY TECHNOLOGY DEVICES (MTD)
>  M:	David Woodhouse <dwmw2 at infradead.org>
>  M:	Brian Norris <computersforpeace at gmail.com>
> +M:	Boris Brezillon <boris.brezillon at free-electrons.com>
> +M:	Marek Vasut <marek.vasut at gmail.com>
> +M:	Richard Weinberger <richard at nod.at>
> +M:	Cyrille Pitchen <cyrille.pitchen at atmel.com>
>  L:	linux-mtd at lists.infradead.org
>  W:	http://www.linux-mtd.infradead.org/
>  Q:	http://patchwork.ozlabs.org/project/linux-mtd/list/
> -- 
> 2.7.4
> 


From hkallweit1 at gmail.com  Thu Oct 27 14:23:58 2016
From: hkallweit1 at gmail.com (Heiner Kallweit)
Date: Thu, 27 Oct 2016 23:23:58 +0200
Subject: [PATCH RESEND] mtd: m25p80: consider max message size in m25p80_read
In-Reply-To: <a5aad691-fb3b-39a5-943e-43068df74c44@gmail.com>
References: <6c95366c-7fcc-ef4c-033a-f9f6e152a669@gmail.com>
 <20160816164204.GV9347@sirena.org.uk>
 <b65240ff-7e28-5ecb-0670-abfca871246b@gmail.com>
 <a5aad691-fb3b-39a5-943e-43068df74c44@gmail.com>
Message-ID: <e2e4ecfe-b888-f335-57f6-634f5c818252@gmail.com>

Consider a message size limit when calculating the maximum amount
of data that can be read.

Signed-off-by: Heiner Kallweit <hkallweit1 at gmail.com>
---
v2:
- use the new function spi_max_message_size

This patch was part of a series and is needed to correctly support
reads > 64k on fsl-espi (as first user of spi_max_message_size).
See commit 02a595d5d6e4 ("spi: fsl-espi: eliminate spi nor flash
read loop")
---
 drivers/mtd/devices/m25p80.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 9cf7fcd..16a7df2 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -172,7 +172,8 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
 
 	t[1].rx_buf = buf;
 	t[1].rx_nbits = m25p80_rx_nbits(nor);
-	t[1].len = min(len, spi_max_transfer_size(spi));
+	t[1].len = min3(len, spi_max_transfer_size(spi),
+			spi_max_message_size(spi) - t[0].len);
 	spi_message_add_tail(&t[1], &m);
 
 	ret = spi_sync(spi, &m);
-- 
2.9.2





From hkallweit1 at gmail.com  Thu Oct 27 14:13:26 2016
From: hkallweit1 at gmail.com (Heiner Kallweit)
Date: Thu, 27 Oct 2016 23:13:26 +0200
Subject: [PATCH RESEND v3] mtd: spi-nor: fix flags for s25fl128s
In-Reply-To: <808bf727-f562-79d4-a60f-5e437cc15da6@gmail.com>
References: <4d3db993-d030-3659-2f62-94c373f57038@gmail.com>
 <808bf727-f562-79d4-a60f-5e437cc15da6@gmail.com>
Message-ID: <514b12c9-447b-1688-29d3-aac839de08ac@gmail.com>

The Spansion S25FL128S also supports dual read mode.
In addition remove flag SECT_4K. 4K erases are supported,
but not uniformly.

Signed-off-by: Heiner Kallweit <hkallweit1 at gmail.com>
Reviewed-by: Jagan Teki <jteki at openedev.com>
---
v2:
- In addition remove SECT_4K flag. 4K erases are supported,
  but not uniformly.
v3:
- mention removal of SECT_4K also in actual commit message
---
 drivers/mtd/spi-nor/spi-nor.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index d0fc165..4f8e488 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -905,7 +905,7 @@ static const struct flash_info spi_nor_ids[] = {
 	{ "s70fl01gs",  INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
 	{ "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024,  64, 0) },
 	{ "s25sl12801", INFO(0x012018, 0x0301,  64 * 1024, 256, 0) },
-	{ "s25fl128s",	INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) },
+	{ "s25fl128s",	INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 	{ "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024,  64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 	{ "s25fl129p1", INFO(0x012018, 0x4d01,  64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 	{ "s25sl004a",  INFO(0x010212,      0,  64 * 1024,   8, 0) },
-- 
2.9.2





From marex at denx.de  Thu Oct 27 17:14:58 2016
From: marex at denx.de (Marek Vasut)
Date: Fri, 28 Oct 2016 02:14:58 +0200
Subject: MTD partitions vs erase regions
In-Reply-To: <AM4PR0701MB21304CE213B5F0B0534AB52FFEAA0@AM4PR0701MB2130.eurprd07.prod.outlook.com>
References: <AM4PR0701MB21304CE213B5F0B0534AB52FFEAA0@AM4PR0701MB2130.eurprd07.prod.outlook.com>
Message-ID: <35c63aa4-d686-e06a-a12f-408c25895a22@denx.de>

On 10/27/2016 02:19 PM, Krzeminski, Marcin (Nokia - PL/Wroclaw) wrote:
> Hi Marek,

Hi,

> I am sending mtd partition and erase regions conflict that I had.
> I admit I have no investigated it, since finally all is different.
> This could make some problems with your idea of having erase sizes defined from DT.

Which flash is that ?

> Erase regions configuration:
> 
> nor->eraseregions[0].erasesize = 4096;
> nor->eraseregions[0].numblocks = 8;
> nor->eraseregions[0].offset = 0x0;
> 
> nor->eraseregions[1].erasesize = 32*1024;
> nor->eraseregions[1].numblocks = 1;
> nor->eraseregions[1].offset = 32*1024;
> 
> nor->eraseregions[2].erasesize = 64*1024;
> nor->eraseregions[2].numblocks = div_u64_rem(mtd->size - 64*1024, info->sector_size, &rem);
> nor->eraseregions[2].offset = 64*1024;
> 
> Device tree (mtd):
> 
> partition at 0 {
> label = "all";
> reg = <0x00000000 0x08000000>;
> };
> 
> partition at 1 {
> label = "small";
> reg = <0x00000000 0x00008000>;
> };
> 
> partition at 2 {
> label = "rest"; 
> reg = <0x00008000 0x07FF8000>;
> };
> 
> Logs from startup:
> 
> [    1.187722] 0x000000000000-0x000008000000 : "all"
> [    1.188498] device: 'mtd0': device_add
> [    1.189563] device: 'mtd0ro': device_add
> [    1.192359] device: '31:0': device_add
> [    1.192810] device: 'mtdblock0': device_add
> [    1.194504] 0x000000000000-0x000000008000 : "small"
> [    1.195144] device: 'mtd1': device_add
> [    1.196667] device: 'mtd1ro': device_add
> [    1.198268] device: '31:1': device_add
> [    1.199016] device: 'mtdblock1': device_add
> [    1.200922] 0x000000008000-0x000008000000 : "rest"
> [    1.201222] mtd: partition "rest" doesn't start on an erase block boundary -- force read-only
> [    1.201613] device: 'mtd2': device_add
> [    1.202541] device: 'mtd2ro': device_add
> [    1.204659] device: '31:2': device_add
> [    1.206233] device: 'mtdblock2': device_add
> 
> Message is from here:
> http://lxr.free-electrons.com/source/drivers/mtd/mtdpart.c?v=4.4#L526
> 
> Regards,
> Marcin
> 


-- 
Best regards,
Marek Vasut


From marcin.krzeminski at nokia.com  Thu Oct 27 21:50:16 2016
From: marcin.krzeminski at nokia.com (Krzeminski, Marcin (Nokia - PL/Wroclaw))
Date: Fri, 28 Oct 2016 04:50:16 +0000
Subject: MTD partitions vs erase regions
In-Reply-To: <35c63aa4-d686-e06a-a12f-408c25895a22@denx.de>
References: <AM4PR0701MB21304CE213B5F0B0534AB52FFEAA0@AM4PR0701MB2130.eurprd07.prod.outlook.com>
 <35c63aa4-d686-e06a-a12f-408c25895a22@denx.de>
Message-ID: <AM4PR0701MB2130B3903E47ACF2A5D9A3F5FEAD0@AM4PR0701MB2130.eurprd07.prod.outlook.com>

Marek,

> -----Original Message-----
> From: Marek Vasut [mailto:marex at denx.de]
> Sent: Friday, October 28, 2016 2:15 AM
> To: Krzeminski, Marcin (Nokia - PL/Wroclaw)
> <marcin.krzeminski at nokia.com>
> Cc: linux-mtd at lists.infradead.org
> Subject: Re: MTD partitions vs erase regions
> 
> On 10/27/2016 02:19 PM, Krzeminski, Marcin (Nokia - PL/Wroclaw) wrote:
> > Hi Marek,
> 
> Hi,
> 
> > I am sending mtd partition and erase regions conflict that I had.
> > I admit I have no investigated it, since finally all is different.
> > This could make some problems with your idea of having erase sizes
> defined from DT.
> 
> Which flash is that ?

Sorry - forgot to mention: MT25Q00 (64KiB erase size).
CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is disabled.

Regards,
Marcin
> 
> > Erase regions configuration:
> >
> > nor->eraseregions[0].erasesize = 4096; eraseregions[0].numblocks = 8;
> > nor->eraseregions[0].offset = 0x0;
> >
> > nor->eraseregions[1].erasesize = 32*1024; eraseregions[1].numblocks =
> > nor->1; eraseregions[1].offset = 32*1024;
> >
> > nor->eraseregions[2].erasesize = 64*1024; eraseregions[2].numblocks =
> > nor->div_u64_rem(mtd->size - 64*1024, info->sector_size, &rem);
> > nor->eraseregions[2].offset = 64*1024;
> >
> > Device tree (mtd):
> >
> > partition at 0 {
> > label = "all";
> > reg = <0x00000000 0x08000000>;
> > };
> >
> > partition at 1 {
> > label = "small";
> > reg = <0x00000000 0x00008000>;
> > };
> >
> > partition at 2 {
> > label = "rest";
> > reg = <0x00008000 0x07FF8000>;
> > };
> >
> > Logs from startup:
> >
> > [    1.187722] 0x000000000000-0x000008000000 : "all"
> > [    1.188498] device: 'mtd0': device_add
> > [    1.189563] device: 'mtd0ro': device_add
> > [    1.192359] device: '31:0': device_add
> > [    1.192810] device: 'mtdblock0': device_add
> > [    1.194504] 0x000000000000-0x000000008000 : "small"
> > [    1.195144] device: 'mtd1': device_add
> > [    1.196667] device: 'mtd1ro': device_add
> > [    1.198268] device: '31:1': device_add
> > [    1.199016] device: 'mtdblock1': device_add
> > [    1.200922] 0x000000008000-0x000008000000 : "rest"
> > [    1.201222] mtd: partition "rest" doesn't start on an erase block boundary
> -- force read-only
> > [    1.201613] device: 'mtd2': device_add
> > [    1.202541] device: 'mtd2ro': device_add
> > [    1.204659] device: '31:2': device_add
> > [    1.206233] device: 'mtdblock2': device_add
> >
> > Message is from here:
> > http://lxr.free-electrons.com/source/drivers/mtd/mtdpart.c?v=4.4#L526
> >
> > Regards,
> > Marcin
> >
> 
> 
> --
> Best regards,
> Marek Vasut


From marex at denx.de  Thu Oct 27 22:08:08 2016
From: marex at denx.de (Marek Vasut)
Date: Fri, 28 Oct 2016 07:08:08 +0200
Subject: MTD partitions vs erase regions
In-Reply-To: <AM4PR0701MB2130B3903E47ACF2A5D9A3F5FEAD0@AM4PR0701MB2130.eurprd07.prod.outlook.com>
References: <AM4PR0701MB21304CE213B5F0B0534AB52FFEAA0@AM4PR0701MB2130.eurprd07.prod.outlook.com>
 <35c63aa4-d686-e06a-a12f-408c25895a22@denx.de>
 <AM4PR0701MB2130B3903E47ACF2A5D9A3F5FEAD0@AM4PR0701MB2130.eurprd07.prod.outlook.com>
Message-ID: <c821516b-cda3-d6e1-2aad-1fe3c11cab77@denx.de>

On 10/28/2016 06:50 AM, Krzeminski, Marcin (Nokia - PL/Wroclaw) wrote:
> Marek,
> 
>> -----Original Message-----
>> From: Marek Vasut [mailto:marex at denx.de]
>> Sent: Friday, October 28, 2016 2:15 AM
>> To: Krzeminski, Marcin (Nokia - PL/Wroclaw)
>> <marcin.krzeminski at nokia.com>
>> Cc: linux-mtd at lists.infradead.org
>> Subject: Re: MTD partitions vs erase regions
>>
>> On 10/27/2016 02:19 PM, Krzeminski, Marcin (Nokia - PL/Wroclaw) wrote:
>>> Hi Marek,
>>
>> Hi,
>>
>>> I am sending mtd partition and erase regions conflict that I had.
>>> I admit I have no investigated it, since finally all is different.
>>> This could make some problems with your idea of having erase sizes
>> defined from DT.
>>
>> Which flash is that ?
> 
> Sorry - forgot to mention: MT25Q00 (64KiB erase size).
> CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is disabled.

I think this is expected then, the subsystem is not ready for device
with variable eraseblock length.

-- 
Best regards,
Marek Vasut


From hkallweit1 at gmail.com  Thu Oct 27 22:48:29 2016
From: hkallweit1 at gmail.com (Heiner Kallweit)
Date: Fri, 28 Oct 2016 07:48:29 +0200
Subject: [PATCH RESEND] mtd: m25p80: consider max message size in
 m25p80_read
In-Reply-To: <e2e4ecfe-b888-f335-57f6-634f5c818252@gmail.com>
References: <6c95366c-7fcc-ef4c-033a-f9f6e152a669@gmail.com>
 <20160816164204.GV9347@sirena.org.uk>
 <b65240ff-7e28-5ecb-0670-abfca871246b@gmail.com>
 <a5aad691-fb3b-39a5-943e-43068df74c44@gmail.com>
 <e2e4ecfe-b888-f335-57f6-634f5c818252@gmail.com>
Message-ID: <4ad13cef-96b5-20d6-db1b-18f04807845e@gmail.com>

Am 27.10.2016 um 23:23 schrieb Heiner Kallweit:
> Consider a message size limit when calculating the maximum amount
> of data that can be read.
> 
> Signed-off-by: Heiner Kallweit <hkallweit1 at gmail.com>
> ---
> v2:
> - use the new function spi_max_message_size
> 
> This patch was part of a series and is needed to correctly support
> reads > 64k on fsl-espi (as first user of spi_max_message_size).
> See commit 02a595d5d6e4 ("spi: fsl-espi: eliminate spi nor flash
> read loop")
> ---
>  drivers/mtd/devices/m25p80.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
> index 9cf7fcd..16a7df2 100644
> --- a/drivers/mtd/devices/m25p80.c
> +++ b/drivers/mtd/devices/m25p80.c
> @@ -172,7 +172,8 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
>  
>  	t[1].rx_buf = buf;
>  	t[1].rx_nbits = m25p80_rx_nbits(nor);
> -	t[1].len = min(len, spi_max_transfer_size(spi));
> +	t[1].len = min3(len, spi_max_transfer_size(spi),
> +			spi_max_message_size(spi) - t[0].len);
>  	spi_message_add_tail(&t[1], &m);
>  
>  	ret = spi_sync(spi, &m);
> 
Sorry, forgot that this needs to go to stable as well. Will send a v2.


From hkallweit1 at gmail.com  Thu Oct 27 22:58:46 2016
From: hkallweit1 at gmail.com (Heiner Kallweit)
Date: Fri, 28 Oct 2016 07:58:46 +0200
Subject: [PATCH v2] mtd: m25p80: consider max message size in m25p80_read
In-Reply-To: <e2e4ecfe-b888-f335-57f6-634f5c818252@gmail.com>
References: <6c95366c-7fcc-ef4c-033a-f9f6e152a669@gmail.com>
 <20160816164204.GV9347@sirena.org.uk>
 <b65240ff-7e28-5ecb-0670-abfca871246b@gmail.com>
 <a5aad691-fb3b-39a5-943e-43068df74c44@gmail.com>
 <e2e4ecfe-b888-f335-57f6-634f5c818252@gmail.com>
Message-ID: <0e38d1ed-af5c-160f-e02a-f1433c507d23@gmail.com>

Consider a message size limit when calculating the maximum amount
of data that can be read.

The message size limit has been introduced with 4.9, so cc it
to stable.

Signed-off-by: Heiner Kallweit <hkallweit1 at gmail.com>
Cc: <stable at vger.kernel.org> # 4.9.x
---
v2:
- This patch was part of a series and the other patches of the
  series went into 4.9. It's needed to correctly support
  reads > 64k on fsl-espi as first user of spi_max_message_size.
  See commit 02a595d5d6e4 ("spi: fsl-espi: eliminate spi nor
  flash read loop"). CC it to stable.  
---
 drivers/mtd/devices/m25p80.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 9cf7fcd..16a7df2 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -172,7 +172,8 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
 
 	t[1].rx_buf = buf;
 	t[1].rx_nbits = m25p80_rx_nbits(nor);
-	t[1].len = min(len, spi_max_transfer_size(spi));
+	t[1].len = min3(len, spi_max_transfer_size(spi),
+			spi_max_message_size(spi) - t[0].len);
 	spi_message_add_tail(&t[1], &m);
 
 	ret = spi_sync(spi, &m);
-- 
2.9.2




From boris.brezillon at free-electrons.com  Fri Oct 28 00:56:02 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Fri, 28 Oct 2016 09:56:02 +0200
Subject: [PATCH] mtd: nand: davinci: Fix unaligned 16-bit NAND read
In-Reply-To: <20161021092605.GA14609@gmail.com>
References: <20161021092605.GA14609@gmail.com>
Message-ID: <20161028095602.7a02f404@bbrezillon>

Hi Michael,

On Fri, 21 Oct 2016 10:26:05 +0100
Ville Michael Baillie <ville.michael.baillie at gmail.com> wrote:

> This patch fixes a rare bug when reading from 16-bit NAND flashes, by
> not allowing 8-bit read accesses within nand_davinci_read_buf().
> 
> In certain situations, an non 16-bit aligned buffer is passed to
> nand_davinci_read_buf(), which causes 8-bit accesses to be performed.
> However, the NAND will be returning 16-bit words, and half of these will
> be discarded.
> 
> This was observed when running mtd_stresstest.ko, which would report ECC
> errors when reading from a non 16-bit aligned offset into a page, and
> reading at least one subsequent page in the same read.
> 
> Signed-off-by: Ville Michael Baillie <ville.michael.baillie at gmail.com>
> ---
>  drivers/mtd/nand/davinci_nand.c | 14 +++++++++++++-
>  1 file changed, 13 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c
> index 27fa8b8..ed9cd0d 100644
> --- a/drivers/mtd/nand/davinci_nand.c
> +++ b/drivers/mtd/nand/davinci_nand.c
> @@ -442,12 +442,24 @@ static int nand_davinci_correct_4bit(struct mtd_info *mtd,
>  static void nand_davinci_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
>  {
>  	struct nand_chip *chip = mtd_to_nand(mtd);
> +	u16 tmp;
>  
>  	if ((0x03 & ((unsigned)buf)) == 0 && (0x03 & len) == 0)
>  		ioread32_rep(chip->IO_ADDR_R, buf, len >> 2);
>  	else if ((0x01 & ((unsigned)buf)) == 0 && (0x01 & len) == 0)
>  		ioread16_rep(chip->IO_ADDR_R, buf, len >> 1);
> -	else
> +	else if (chip->options & NAND_BUSWIDTH_16) {
> +		/*
> +		 * if NAND buswidth is 16 then 8 bit accesses
> +		 * will silently discard half the data
> +		 */
> +		len /= 2;
> +		while (len--) {
> +			tmp = ioread16(chip->IO_ADDR_R);
> +			memcpy(buf, &tmp, sizeof(u16));
> +			buf += sizeof(u16);
> +		}

Hm, you're not checking the len alignment here. Not sure this
is safe to assume len will always be a multiple of 2 bytes.

How about doing the following instead:

		/* Use ioread16_rep for aligned accesses. */
		if (IS_ALIGNED(addr, sizeof(u16))) {
			ioread16_rep(chip->IO_ADDR_R, buf, len >> 1);
			buf += len & ~0x1;
			len &= 0x1;
		}

		/*
		 * Now handle unaligned accesses.
		 * Warning: in case of unaligned len, we are consuming
		 * one extra byte, which is then discarded. It's fine
		 * as long as the caller does not call ->read_buf()
		 * twice without re-issuing a command in the middle.
		 * Otherwise, this means we lost one byte.
		 */
		for (; len > 0; len -= sizeof(u16)) {
			u16 tmp;

			tmp = ioread16(chip->IO_ADDR_R);
			memcpy(buf, &tmp,
			       len < sizeof(u16) ? len : sizeof(u16));
			buf += sizeof(u16);
		}

> +	} else
>  		ioread8_rep(chip->IO_ADDR_R, buf, len);

	} else {
		ioread8_rep(chip->IO_ADDR_R, buf, len);
	}

>  }
>  



From boris.brezillon at free-electrons.com  Fri Oct 28 01:04:19 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Fri, 28 Oct 2016 10:04:19 +0200
Subject: [PATCH] mtd: nand: pxa3xx_nand: write exactly one message on
 probe failure
In-Reply-To: <1474276878-1021-1-git-send-email-u.kleine-koenig@pengutronix.de>
References: <1474276878-1021-1-git-send-email-u.kleine-koenig@pengutronix.de>
Message-ID: <20161028100419.1ba04968@bbrezillon>

On Mon, 19 Sep 2016 11:21:18 +0200
Uwe Kleine-K?nig <u.kleine-koenig at pengutronix.de> wrote:

> For some error paths alloc_nand_resource() emitted an error message, for
> others it didn't. Make it consistently print a message including the
> error code where it's not constant and drop the hardly helpful
> additional message printed by the caller of alloc_nand_resource.
> 
> Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig at pengutronix.de>

It looks good to me. Ezequiel, Robert, any objection to this patch? If
not, can I have your Acked/Reviewed-by ?

> ---
>  drivers/mtd/nand/pxa3xx_nand.c | 17 ++++++++++-------
>  1 file changed, 10 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> index 436dd6dc11f4..052e9725cf12 100644
> --- a/drivers/mtd/nand/pxa3xx_nand.c
> +++ b/drivers/mtd/nand/pxa3xx_nand.c
> @@ -1774,8 +1774,11 @@ static int alloc_nand_resource(struct platform_device *pdev)
>  	int ret, irq, cs;
>  
>  	pdata = dev_get_platdata(&pdev->dev);
> -	if (pdata->num_cs <= 0)
> +	if (pdata->num_cs <= 0) {
> +		dev_err(&pdev->dev, "broken number of chip selects\n");
>  		return -ENODEV;
> +	}
> +
>  	info = devm_kzalloc(&pdev->dev,
>  			    sizeof(*info) + sizeof(*host) * pdata->num_cs,
>  			    GFP_KERNEL);
> @@ -1814,8 +1817,9 @@ static int alloc_nand_resource(struct platform_device *pdev)
>  	init_waitqueue_head(&chip->controller->wq);
>  	info->clk = devm_clk_get(&pdev->dev, NULL);
>  	if (IS_ERR(info->clk)) {
> -		dev_err(&pdev->dev, "failed to get nand clock\n");
> -		return PTR_ERR(info->clk);
> +		ret = PTR_ERR(info->clk);
> +		dev_err(&pdev->dev, "failed to get nand clock (%d)\n", ret);
> +		return ret;
>  	}
>  	ret = clk_prepare_enable(info->clk);
>  	if (ret < 0)
> @@ -1843,6 +1847,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
>  	info->mmio_base = devm_ioremap_resource(&pdev->dev, r);
>  	if (IS_ERR(info->mmio_base)) {
>  		ret = PTR_ERR(info->mmio_base);
> +		dev_err(&pdev->dev, "failed to map register space (%d)\n", ret);
>  		goto fail_disable_clk;
>  	}
>  	info->mmio_phys = r->start;
> @@ -1862,7 +1867,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
>  				   pxa3xx_nand_irq_thread, IRQF_ONESHOT,
>  				   pdev->name, info);
>  	if (ret < 0) {
> -		dev_err(&pdev->dev, "failed to request IRQ\n");
> +		dev_err(&pdev->dev, "failed to request IRQ (%d)\n", ret);
>  		goto fail_free_buf;
>  	}
>  
> @@ -1961,10 +1966,8 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
>  	}
>  
>  	ret = alloc_nand_resource(pdev);
> -	if (ret) {
> -		dev_err(&pdev->dev, "alloc nand resource failed\n");
> +	if (ret)
>  		return ret;
> -	}
>  
>  	info = platform_get_drvdata(pdev);
>  	probe_success = 0;



From boris.brezillon at free-electrons.com  Fri Oct 28 01:18:59 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Fri, 28 Oct 2016 10:18:59 +0200
Subject: [PULL] mtd: nand: Fixes for 4.9-rc3
Message-ID: <20161028101859.615190bc@bbrezillon>

Hi Brian,

Here is the PR I was mentioning yesterday. I thought I had more fixes
in the queue, but apparently I only have 2.

As usual, let me know if you find something weird in this PR, and I'll
fix it.

Thanks,

Boris

The following changes since commit 07d9a380680d1c0eb51ef87ff2eab5c994949e69:

  Linux 4.9-rc2 (2016-10-23 17:10:14 -0700)

are available in the git repository at:

  git at github.com:linux-nand/linux.git tags/nand/fixes-for-4.9-rc3

for you to fetch changes up to 73f907fd5fa56b0066d199bdd7126bbd04f6cd7b:

  mtd: nand: Fix data interface configuration logic (2016-10-28 09:58:36 +0200)

----------------------------------------------------------------
Two simple fixes:

- the first one is fixing a non-critical bug in the gpmi driver
- the second one is fixing a bug in the 'automatic NAND timings
  selection' feature introduced in 4.9-rc1

----------------------------------------------------------------
Boris Brezillon (1):
      mtd: nand: Fix data interface configuration logic

Fabio Estevam (1):
      mtd: nand: gpmi: disable the clocks on errors

 drivers/mtd/nand/gpmi-nand/gpmi-lib.c |  6 ++++--
 drivers/mtd/nand/nand_base.c          | 60 ++++++++++++++++++++++++++++++++++++++++++------------------
 include/linux/mtd/nand.h              |  2 +-
 3 files changed, 47 insertions(+), 21 deletions(-)
	


From boris.brezillon at free-electrons.com  Fri Oct 28 01:25:26 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Fri, 28 Oct 2016 10:25:26 +0200
Subject: [PULL] mtd: nand: Fixes for 4.9-rc3
In-Reply-To: <20161028101859.615190bc@bbrezillon>
References: <20161028101859.615190bc@bbrezillon>
Message-ID: <20161028102526.3df5d4a4@bbrezillon>

On Fri, 28 Oct 2016 10:18:59 +0200
Boris Brezillon <boris.brezillon at free-electrons.com> wrote:

> Hi Brian,
> 
> Here is the PR I was mentioning yesterday. I thought I had more fixes
> in the queue, but apparently I only have 2.
> 
> As usual, let me know if you find something weird in this PR, and I'll
> fix it.

Please ignore this PR, I found another patch. I'll send a v2.
Sorry for the noise.

> 
> Thanks,
> 
> Boris
> 
> The following changes since commit 07d9a380680d1c0eb51ef87ff2eab5c994949e69:
> 
>   Linux 4.9-rc2 (2016-10-23 17:10:14 -0700)
> 
> are available in the git repository at:
> 
>   git at github.com:linux-nand/linux.git tags/nand/fixes-for-4.9-rc3
> 
> for you to fetch changes up to 73f907fd5fa56b0066d199bdd7126bbd04f6cd7b:
> 
>   mtd: nand: Fix data interface configuration logic (2016-10-28 09:58:36 +0200)
> 
> ----------------------------------------------------------------
> Two simple fixes:
> 
> - the first one is fixing a non-critical bug in the gpmi driver
> - the second one is fixing a bug in the 'automatic NAND timings
>   selection' feature introduced in 4.9-rc1
> 
> ----------------------------------------------------------------
> Boris Brezillon (1):
>       mtd: nand: Fix data interface configuration logic
> 
> Fabio Estevam (1):
>       mtd: nand: gpmi: disable the clocks on errors
> 
>  drivers/mtd/nand/gpmi-nand/gpmi-lib.c |  6 ++++--
>  drivers/mtd/nand/nand_base.c          | 60 ++++++++++++++++++++++++++++++++++++++++++------------------
>  include/linux/mtd/nand.h              |  2 +-
>  3 files changed, 47 insertions(+), 21 deletions(-)
> 	
> 
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/



From boris.brezillon at free-electrons.com  Fri Oct 28 01:26:49 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Fri, 28 Oct 2016 10:26:49 +0200
Subject: [PULL v2] mtd: nand: Fixes for 4.9-rc3
Message-ID: <20161028102649.7b90e308@bbrezillon>

Hi Brian,

Here is the PR I was mentioning yesterday.
As usual, let me know if you find something weird in this PR, and I'll
fix it.

Thanks,

Boris

The following changes since commit 07d9a380680d1c0eb51ef87ff2eab5c994949e69:

  Linux 4.9-rc2 (2016-10-23 17:10:14 -0700)

are available in the git repository at:

  git at github.com:linux-nand/linux.git tags/nand/fixes-for-4.9-rc3

for you to fetch changes up to 8ff0513bdcdd71e84aa561cce216675d43fb41b8:

  mtd: mtk: avoid warning in mtk_ecc_encode (2016-10-28 10:21:23 +0200)

----------------------------------------------------------------
Three simple fixes:

- the first one is fixing a non-critical bug in the gpmi driver
- the second one is fixing a bug in the 'automatic NAND timings
  selection' feature introduced in 4.9-rc1
- the last one is fixing a false positive uninitialized-var warning

----------------------------------------------------------------
Arnd Bergmann (1):
      mtd: mtk: avoid warning in mtk_ecc_encode

Boris Brezillon (1):
      mtd: nand: Fix data interface configuration logic

Fabio Estevam (1):
      mtd: nand: gpmi: disable the clocks on errors

 drivers/mtd/nand/gpmi-nand/gpmi-lib.c |  6 ++++--
 drivers/mtd/nand/mtk_ecc.c            | 19 +++++++++----------
 drivers/mtd/nand/nand_base.c          | 60 ++++++++++++++++++++++++++++++++++++++++++------------------
 include/linux/mtd/nand.h              |  2 +-
 4 files changed, 56 insertions(+), 31 deletions(-)


From boris.brezillon at free-electrons.com  Fri Oct 28 01:54:25 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Fri, 28 Oct 2016 10:54:25 +0200
Subject: [PATCH 0/2] mtd: nand: Enforce tCCS wait time after a column
 change
In-Reply-To: <1475310243-32625-1-git-send-email-boris.brezillon@free-electrons.com>
References: <1475310243-32625-1-git-send-email-boris.brezillon@free-electrons.com>
Message-ID: <20161028105425.61868d75@bbrezillon>

On Sat,  1 Oct 2016 10:24:01 +0200
Boris Brezillon <boris.brezillon at free-electrons.com> wrote:

> Hi,
> 
> Marc recently struggled with the RNDIN/RNDOUT commands when trying to
> add support for the Tango NAND controller.
> After some investigation it appeared that nothing in the
> nand_command_lp() code waits tCCS, which is required to make sure the
> NAND chip is ready to receive/send data on the bus after a column
> change.
> 
> This series adds some more timings to the nand_sdr_timings struct
> (including tCCS) and try to extract them from the ONFI parameter table
> (if available).
> 
> It then adds a new flags to ask the core to enforce the tCCS
> constraint.
> As noted in the commit message, this is an opt-in flag to avoid perf
> regressions on existing implementations (adding an ndelay() might be
> useless if the controller IP or driver already takes care of that),
> but it might appear that some implementations are actually broken and
> needs this flag as well.

Applied.

> 
> Regards,
> 
> Boris
> 
> Boris Brezillon (2):
>   mtd: nand: Add a few more timings to nand_sdr_timings
>   mtd: nand: Wait tCCS after a column change
> 
>  drivers/mtd/nand/nand_base.c    | 26 +++++++++++++++++++++++++-
>  drivers/mtd/nand/nand_timings.c | 26 +++++++++++++++++++++++++-
>  include/linux/mtd/nand.h        | 18 ++++++++++++++++++
>  3 files changed, 68 insertions(+), 2 deletions(-)
> 



From boris.brezillon at free-electrons.com  Fri Oct 28 02:08:44 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Fri, 28 Oct 2016 11:08:44 +0200
Subject: [PATCH] UBI: fastmap: Fix add_vol() return value test in
 ubi_attach_fastmap()
Message-ID: <1477645724-17654-1-git-send-email-boris.brezillon@free-electrons.com>

Commit e96a8a3bb671 ("UBI: Fastmap: Do not add vol if it already
exists") introduced a bug by changing the possible error codes returned
by add_vol():
- this functions no longer returns NULL in case of allocation failure
  but return ERR_PTR(-ENOMEM)
- when a duplicate entry in the volume RB tree is found it returns
  ERR_PTR(-EEXIST) instead of ERR_PTR(-EINVAL)

Fix the tests done of add_vol() return value accordingly.

Fixes: e96a8a3bb671 ("UBI: Fastmap: Do not add vol if it already exists")
Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
Acked-by: Sheng Yong <shengyong1 at huawei.com>
---
 drivers/mtd/ubi/fastmap.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c
index d6384d965788..eb39c44726e3 100644
--- a/drivers/mtd/ubi/fastmap.c
+++ b/drivers/mtd/ubi/fastmap.c
@@ -707,11 +707,11 @@ static int ubi_attach_fastmap(struct ubi_device *ubi,
 			     fmvhdr->vol_type,
 			     be32_to_cpu(fmvhdr->last_eb_bytes));
 
-		if (!av)
-			goto fail_bad;
-		if (PTR_ERR(av) == -EINVAL) {
-			ubi_err(ubi, "volume (ID %i) already exists",
-				fmvhdr->vol_id);
+		if (IS_ERR(av)) {
+			if (PTR_ERR(av) == -EEXIST)
+				ubi_err(ubi, "volume (ID %i) already exists",
+					fmvhdr->vol_id);
+
 			goto fail_bad;
 		}
 
-- 
2.7.4



From boris.brezillon at free-electrons.com  Fri Oct 28 02:12:10 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Fri, 28 Oct 2016 11:12:10 +0200
Subject: [PATCH] UBI: fastmap: Fix add_vol() return value test in
 ubi_attach_fastmap()
In-Reply-To: <1477645724-17654-1-git-send-email-boris.brezillon@free-electrons.com>
References: <1477645724-17654-1-git-send-email-boris.brezillon@free-electrons.com>
Message-ID: <20161028111210.4515249a@bbrezillon>

On Fri, 28 Oct 2016 11:08:44 +0200
Boris Brezillon <boris.brezillon at free-electrons.com> wrote:

> Commit e96a8a3bb671 ("UBI: Fastmap: Do not add vol if it already
> exists") introduced a bug by changing the possible error codes returned
> by add_vol():
> - this functions no longer returns NULL in case of allocation failure

	 ^ function

>   but return ERR_PTR(-ENOMEM)
> - when a duplicate entry in the volume RB tree is found it returns
>   ERR_PTR(-EEXIST) instead of ERR_PTR(-EINVAL)
> 
> Fix the tests done of add_vol() return value accordingly.

"Fix the tests done on add_vol() return val to match this new behavior."

Do you want me to send a new version fixing the commit message?

> 
> Fixes: e96a8a3bb671 ("UBI: Fastmap: Do not add vol if it already exists")
> Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
> Acked-by: Sheng Yong <shengyong1 at huawei.com>
> ---
>  drivers/mtd/ubi/fastmap.c | 10 +++++-----
>  1 file changed, 5 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c
> index d6384d965788..eb39c44726e3 100644
> --- a/drivers/mtd/ubi/fastmap.c
> +++ b/drivers/mtd/ubi/fastmap.c
> @@ -707,11 +707,11 @@ static int ubi_attach_fastmap(struct ubi_device *ubi,
>  			     fmvhdr->vol_type,
>  			     be32_to_cpu(fmvhdr->last_eb_bytes));
>  
> -		if (!av)
> -			goto fail_bad;
> -		if (PTR_ERR(av) == -EINVAL) {
> -			ubi_err(ubi, "volume (ID %i) already exists",
> -				fmvhdr->vol_id);
> +		if (IS_ERR(av)) {
> +			if (PTR_ERR(av) == -EEXIST)
> +				ubi_err(ubi, "volume (ID %i) already exists",
> +					fmvhdr->vol_id);
> +
>  			goto fail_bad;
>  		}
>  



From richard at nod.at  Fri Oct 28 02:14:19 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 28 Oct 2016 11:14:19 +0200
Subject: [PATCH] UBI: fastmap: Fix add_vol() return value test in
 ubi_attach_fastmap()
In-Reply-To: <20161028111210.4515249a@bbrezillon>
References: <1477645724-17654-1-git-send-email-boris.brezillon@free-electrons.com>
 <20161028111210.4515249a@bbrezillon>
Message-ID: <2bcac0ef-2937-f3c9-0f22-4a3b727bf150@nod.at>

On 28.10.2016 11:12, Boris Brezillon wrote:
> On Fri, 28 Oct 2016 11:08:44 +0200
> Boris Brezillon <boris.brezillon at free-electrons.com> wrote:
> 
>> Commit e96a8a3bb671 ("UBI: Fastmap: Do not add vol if it already
>> exists") introduced a bug by changing the possible error codes returned
>> by add_vol():
>> - this functions no longer returns NULL in case of allocation failure
> 
> 	 ^ function
> 
>>   but return ERR_PTR(-ENOMEM)
>> - when a duplicate entry in the volume RB tree is found it returns
>>   ERR_PTR(-EEXIST) instead of ERR_PTR(-EINVAL)
>>
>> Fix the tests done of add_vol() return value accordingly.
> 
> "Fix the tests done on add_vol() return val to match this new behavior."
> 
> Do you want me to send a new version fixing the commit message?

Nope, I can fixup it myself. :-)

Thanks,
//richard


From boris.brezillon at free-electrons.com  Fri Oct 28 02:23:52 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Fri, 28 Oct 2016 11:23:52 +0200
Subject: [PATCH] MAINTAINERS: add more people to the MTD maintainer team
In-Reply-To: <20161027205732.GB1582@localhost>
References: <1477312526-7563-1-git-send-email-boris.brezillon@free-electrons.com>
 <20161027205732.GB1582@localhost>
Message-ID: <20161028112352.772abae8@bbrezillon>

Hi Brian,

On Thu, 27 Oct 2016 13:57:32 -0700
Brian Norris <computersforpeace at gmail.com> wrote:

> On Mon, Oct 24, 2016 at 02:35:26PM +0200, Boris Brezillon wrote:
> > Brian has been maintaining the MTD subsystem alone for several years
> > now, and maintaining such a subsystem can really be time consuming.
> > 
> > Create a maintainer team formed of the most active MTD contributors
> > to help Brian with this task, which will hopefully improve the
> > subsystem reactivity.
> > 
> > Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>  
> 
> Thanks to all the volunteers! Applied to linux-mtd.git. Will send to
> Linus once we can collect other outstanding fixes.
> 
> > ---
> > Hi all,
> > 
> > I'm just trying to summarize what I understood the process would be,
> > don't hesitate to correct me if I'm wrong.
> > 
> > For each release we will assign a specific MTD maintainer which will be
> > responsible for taking MTD core patches and pulling spi-nor and nand PRs
> > into the MTD tree and eventually send one or several PRs to Linus.  
> 
> I had imagined that the "release owner" role wouldn't necessarily imply
> exclusive commit rights, but that they'd just the primary one
> responsible. I don't see a problem with other maintainer(s) applying
> patches as long as they've gotten the proper review. Or would that be
> too confusing?

Nope, I'm fine with both solutions.

> 
> But that's something not discussed here so far: review requirements. I
> expect we need a minimum of 1 reviewer (where reviewer may be the one
> applying it) that isn't the author. And for bigger things (i.e., not
> trivial and not just a leaf driver) maybe 2. Hopefully in the form of
> explicit Reviewed-by or Acked-by.

Agreed.

> And that means that for NAND or
> SPI-NOR PRs, that may require preempting the "release owner" (e.g., if
> Boris is supposed to be the "owner" for a release, he'll have to find
> someone else to review his NAND PR -- I'm still happy to do so for now,
> but others are welcome).

Cool.

> 
> And for PRs to Linus: if y'all don't mind, I'd still like to have a
> last look at things from the brand new maintainers, at least for now.
> (Boris and Richard would probably also be good candidates for the last
> review / PR, as they've proven to maintain things well already.) I'm
> sure that can be relaxed after a release or so (say, after 4.10?).

I'm perfectly fine with that.

> 
> Thoughts?
> 
> Also, everyone should make their attempts to get their PGP keys into the
> web-of-trust. And we need David to get people infradead.org permissions.
> 
> One other point of order: if it isn't clear, I've been using
> l2-mtd.git/master as the -next "branch" and linux-mtd.git/master as the
> -current-release "branch." We should work extra hard to avoid rebasing
> in either of those trees now. In fact, I'll go disable non-ff pushes
> now...
> 
> I also currently have a server-side post-receive git hook installed in
> l2-mtd.git that tries to update patchwork. It's not 100% accurate
> because it matches contents (which might be the same across multiple
> revisions of a series). I should probably remove or modify that before
> others start pushing there.

I use git notes to do that: each time I apply a patch using pwclient,
it adds a note containing the patchwork id, then, I have a pre-push
hook that scan all the commits that are being pushed on my nand/next
branch and mark the new ones as Accepted in patchwork.

I can provide those scripts if you want, but this means it has to be
done on the client side, because notes are discarded when you push
things to a remote.

> 
> > For fixes that are submitted after -rc1, I usually ask Brian to apply
> > them directly into the MTD tree (I don't think there's a real need to
> > prepare spi-nor and nand PRs for fixes), so we can proceed the same
> > way: ask the maintainer assigned to this release to also take care of
> > applying fixes and sending PRs to Linus before each -rc.  
> 
> I'm flexible on this. If the "release owner" is attentive enough,
> applying them to the MTD tree works just fine. But if a PR helps (as
> Boris is planning to do right now for 4.9-rc) I don't see a problem with
> that either.

Well, it all depends on the number of fixes we have. But if we all have
permissions to push to the mtd tree, then we can just create a fixes
branch where the sub-subsystem maintainers can easily push their fixes
and the release owner will then send a PR to Linus before the next -rc.

> 
> > If you have other ideas, or would like to proceed differently, don't
> > hesitate propose them.  
> 
> Good luck, and happy MTD hacking :)

Thanks.



From ralph.sennhauser at gmail.com  Fri Oct 28 02:37:08 2016
From: ralph.sennhauser at gmail.com (Ralph Sennhauser)
Date: Fri, 28 Oct 2016 11:37:08 +0200
Subject: [REGRESSION 4.9-rc2] "c83ed4c - ubifs: Abort readdir upon error"
 breaks mount
Message-ID: <20161028113708.4d5535ba@gmail.com>

Dear Richard, dear list

When testing 4.9-rc2 the device wouldn't boot, as it turns out commit
c83ed4c9dbb358b9e7707486e167e940d48bfeed prevent's me mounting root.


The relevant portion of init in the initramfs:

  modprobe ubi mtd=$(get_mtd_from_root_arg) block=0,0 || rescue_shell "ubi"
  modprobe ubifs || rescue_shell "ubifs"
  sleep 1

  mount -o ro -t squashfs /dev/ubiblock0_0 /rom || rescue_shell "mount rootfs"
  mount -o rw,noatime -t ubifs /dev/ubi0_1 /overlay || rescue_shell "mount rootfs_data"

  mkdir -p /overlay/upper || rescue_shell "mkdir upper"
  mkdir -p /overlay/work || rescue_shell "mkdir work"

  mount -o rw,noatime,lowerdir=/rom,upperdir=/overlay/upper,workdir=/overlay/work \
        -t overlay overlay /newroot || rescue_shell "mount overlay"


The corresponding output:

  [    1.396152] ubi0: attaching mtd5
  [    1.407127] random: fast init done
  [    1.471770] ubi0: scanning is finished
  [    1.491499] ubi0: volume 1 ("rootfs_data") re-sized from 9 to 111 LEBs
  [    1.498325] ubi0: attached mtd5 (name "rootfs1", size 34 MiB)
  [    1.504106] ubi0: PEB size: 131072 bytes (128 KiB), LEB size: 126976 bytes
  [    1.511007] ubi0: min./max. I/O unit sizes: 2048/2048, sub-page size 2048
  [    1.517826] ubi0: VID header offset: 2048 (aligned 2048), data offset: 4096
  [    1.524819] ubi0: good PEBs: 272, bad PEBs: 0, corrupted PEBs: 0
  [    1.530848] ubi0: user volume: 2, internal volumes: 1, max. volumes count: 128
  [    1.538102] ubi0: max/mean erase counter: 1/0, WL threshold: 4096, image sequence number: 1823239451
  [    1.547275] ubi0: available PEBs: 0, total reserved PEBs: 272, PEBs reserved for bad PEB handling: 20
  [    1.556613] ubi0: background thread "ubi_bgt0d" started, PID 575
  [    1.562933] block ubiblock0_0: created from ubi0:0(rootfs)
  [    2.588027] UBIFS (ubi0:1): default file-system created
  [    2.593689] UBIFS (ubi0:1): background thread "ubifs_bgt0_1" started, PID 586
  [    2.626943] UBIFS (ubi0:1): UBIFS: mounted UBI device 0, volume 1, name "rootfs_data"
  [    2.634816] UBIFS (ubi0:1): LEB size: 126976 bytes (124 KiB), min./max. I/O unit sizes: 2048 bytes/2048 bytes
  [    2.644781] UBIFS (ubi0:1): FS size: 12824576 bytes (12 MiB, 101 LEBs), journal size 1015809 bytes (0 MiB, 6 LEBs)
  [    2.655175] UBIFS (ubi0:1): reserved for root: 605735 bytes (591 KiB)
  [    2.661646] UBIFS (ubi0:1): media format: w4/r0 (latest is w4/r0), UUID FC75053C-E958-4BBC-BD2B-CFCD72BD47F6, small LPT model
  mount: mounting overlay on /newroot failed: No such file or directory
  Error in /init: mount overlay
  -install: applet not found


  BusyBox v1.25.1 () built-in shell (ash)

  sh: can't access tty; job control turned off
  #


The device is a Linksys WRT1900ACS (Shelby), for a basically identical device
see ./arch/arm/boot/dts/armada-385-linksys-cobra.dts


Regards
Ralph


From richard at nod.at  Fri Oct 28 02:38:55 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 28 Oct 2016 11:38:55 +0200
Subject: [REGRESSION 4.9-rc2] "c83ed4c - ubifs: Abort readdir upon error"
 breaks mount
In-Reply-To: <20161028113708.4d5535ba@gmail.com>
References: <20161028113708.4d5535ba@gmail.com>
Message-ID: <dbd2bff6-fdb9-2022-7acc-fcd1cac4c88c@nod.at>

Ralph,

On 28.10.2016 11:37, Ralph Sennhauser wrote:
> Dear Richard, dear list
> 
> When testing 4.9-rc2 the device wouldn't boot, as it turns out commit
> c83ed4c9dbb358b9e7707486e167e940d48bfeed prevent's me mounting root.
> 

A fix for this is already heading upstream:
http://lists.infradead.org/pipermail/linux-mtd/2016-October/070023.html

Thanks,
//richard


From richard at nod.at  Fri Oct 28 02:53:52 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 28 Oct 2016 11:53:52 +0200
Subject: [PATCH] ubifs: Fix regression in ubifs_readdir()
Message-ID: <1477648432-9543-1-git-send-email-richard@nod.at>

Commit c83ed4c9dbb35 ("ubifs: Abort readdir upon error") broke
overlayfs support because the fix exposed an internal error
code to VFS.

Reported-by: Peter Rosin <peda at axentia.se>
Tested-by: Peter Rosin <peda at axentia.se>
Reported-by: Ralph Sennhauser <ralph.sennhauser at gmail.com>
Fixes: c83ed4c9dbb35 ("ubifs: Abort readdir upon error")
Cc: stable at vger.kernel.org
Signed-off-by: Richard Weinberger <richard at nod.at>
---
 fs/ubifs/dir.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index bd4a5e8ce441..ca16c5d7bab1 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -543,6 +543,14 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
 
 	if (err != -ENOENT)
 		ubifs_err(c, "cannot find next direntry, error %d", err);
+	else
+		/*
+		 * -ENOENT is a non-fatal error in this context, the TNC uses
+		 * it to indicate that the cursor moved past the current directory
+		 * and readdir() has to stop.
+		 */
+		err = 0;
+
 
 	/* 2 is a special value indicating that there are no more direntries */
 	ctx->pos = 2;
-- 
2.7.3



From Danesh.Daroui at ascom.com  Fri Oct 28 03:23:47 2016
From: Danesh.Daroui at ascom.com (Danesh Daroui)
Date: Fri, 28 Oct 2016 10:23:47 +0000
Subject: OOB Test fails
In-Reply-To: <20161027174527.6003fd37@bbrezillon>
References: <39BC08CB3FF4C84CB6397533D4FC79095770D513@SEGOTEXCH02.ascom-Resource.ads>
 <CALupW3CJ_gXS+7BrZEGTF8o0H8pJ_AOw0JcKOftSVaMVSbP1zQ@mail.gmail.com>
 <20161027093407.53a76657@bbrezillon> <20161027174527.6003fd37@bbrezillon>
Message-ID: <39BC08CB3FF4C84CB6397533D4FC79095770D803@SEGOTEXCH02.ascom-Resource.ads>

Hi Boris,

I have one question and would appreciate if you can assist me with that. As I wrote we are using a Micron NAND 1GiB 3,3V 8-bit flash memory with UBIFS where we experience some problems. I am wondering whether there are specific drivers provided by vendor in this case or there are generic drivers with respect to the hardware architecture given to the Kernel that can be used as we probably did in this case? I have downloaded a driver package from Micron which is apparently written for our NAND flash memory but the driver uses lots of read/write functions which are platform dependent and not implemented in the driver which makes sense though.

Would you please advise and let us know if we are on the right track e.g. using the driver with the kernel or we need to find more specific driver so the problem that we face now can be related to incorrect driver?

Regards,

Danesh Daroui


-----Original Message-----
From: Boris Brezillon [mailto:boris.brezillon at free-electrons.com] 
Sent: den 27 oktober 2016 17:45
To: Steve deRosier <derosier at gmail.com>
Cc: Danesh Daroui <Danesh.Daroui at ascom.com>; linux-mtd at lists.infradead.org
Subject: Re: OOB Test fails

On Thu, 27 Oct 2016 09:34:07 +0200
Boris Brezillon <boris.brezillon at free-electrons.com> wrote:

> Hi Steve,
> 
> On Wed, 26 Oct 2016 09:16:42 -0700
> Steve deRosier <derosier at gmail.com> wrote:
> 
> > Hi Danesh,
> > 
> > 
> > On Wed, Oct 26, 2016 at 9:07 AM, Danesh Daroui <Danesh.Daroui at ascom.com> wrote:  
> > > Hello all,
> > >
> > > I have executed MTD tests against an unmounted MTD device which uses UBIFS. All MTD tests except OOB test is passed where the OOB test fails from time to time and from device to device. I have read here:
> > >
> > > http://www.linux-mtd.infradead.org/faq/ubi.html#L_why_no_oob
> > >
> > > that UBIFS does not use OOB area. Therefore wanted to ask if failing this test does not need that there is any problem in our system (both HW and SW/configuration) and we can safely ignore the results for this test.
> > >    
> > 
> > UBIFS doesn't use the OOB area, but your MTD driver most likely does.
> > We don't want UBI or UBIFS messing with the OOB area because your 
> > flash, NAND controller and the MTD driver will use that. Bad block 
> > markers are set in the OOB area by the manufacturer in most NAND 
> > flashes and your controller and MTD driver will store and use the 
> > bits in the OOB to do error correction.
> > 
> > So, in short - the OOB area does need to function correctly.  As to 
> > if and why the OOB test is or isn't working is a different issue and 
> > I have no input on that.  All that depends on your mix of flash, 
> > controller and driver.

My bad, I misread your sentence. I thought you we saying "the OOB area does *not* need to function correctly".

My apologies for this misunderstanding, it seems we're on the same page.


From ralph.sennhauser at gmail.com  Fri Oct 28 04:15:52 2016
From: ralph.sennhauser at gmail.com (Ralph Sennhauser)
Date: Fri, 28 Oct 2016 13:15:52 +0200
Subject: [REGRESSION 4.9-rc2] "c83ed4c - ubifs: Abort readdir upon
 error" breaks mount
In-Reply-To: <dbd2bff6-fdb9-2022-7acc-fcd1cac4c88c@nod.at>
References: <20161028113708.4d5535ba@gmail.com>
 <dbd2bff6-fdb9-2022-7acc-fcd1cac4c88c@nod.at>
Message-ID: <20161028131552.16c20658@gmail.com>

Richard

On Fri, 28 Oct 2016 11:38:55 +0200
Richard Weinberger <richard at nod.at> wrote:

> Ralph,
> 
> On 28.10.2016 11:37, Ralph Sennhauser wrote:
> > Dear Richard, dear list
> > 
> > When testing 4.9-rc2 the device wouldn't boot, as it turns out
> > commit c83ed4c9dbb358b9e7707486e167e940d48bfeed prevent's me
> > mounting root. 
> 
> A fix for this is already heading upstream:
> http://lists.infradead.org/pipermail/linux-mtd/2016-October/070023.html
> 

Coming back from lunch and having a working solution in the mail, just
beautiful. If you still need it:

Tested-by: Ralph Sennhauser <ralph.sennhauser at gmail.com>

Much appreciated
Ralph


> Thanks,
> //richard



From ricard.wanderlof at axis.com  Fri Oct 28 07:35:20 2016
From: ricard.wanderlof at axis.com (Ricard Wanderlof)
Date: Fri, 28 Oct 2016 16:35:20 +0200
Subject: [PATCH 1/4] of: Add device tree bindings for Evatronix
In-Reply-To: <20161026150557.587a7387@bbrezillon>
References: <alpine.DEB.2.02.1606020946500.19416@lnxricardw1.se.axis.com>
 <20160603162207.0688c9e6@bbrezillon>
 <alpine.DEB.2.02.1606060757180.23377@lnxricardw1.se.axis.com>
 <20160608175018.16c88207@bbrezillon>
 <alpine.DEB.2.02.1606101641050.30757@lnxricardw1.se.axis.com>
 <20160610175454.327f51a2@bbrezillon>
 <alpine.DEB.2.02.1610261152170.9986@lnxricardw1.se.axis.com>
 <20161026135241.63653c4f@bbrezillon>
 <alpine.DEB.2.02.1610261359290.9986@lnxricardw1.se.axis.com>
 <20161026150557.587a7387@bbrezillon>
Message-ID: <alpine.DEB.2.02.1610280900260.9986@lnxricardw1.se.axis.com>


Hi Boris,

On Wed, 26 Oct 2016, Boris Brezillon wrote:

> > However, mildly accelerated chip timing (i.e. ONFi mode 2) I wouldn't call 
> > an advanced feature, and it seems to be supported by all of the chips in 
> > the 1..4 Gb range that we've seen, although I wouldn't be so bold and go 
> > so far as to say that I know all available flash chips (at least in this 
> > size range) support that mode. That's why I'm reluctant to suggest 
> > changing the entries for these flashes in the table in nand_ids.c, which 
> > would be another alternative. And if we did make that change, it might 
> > cause problems in systems which currently use onfi_timing_mode_default if 
> > the timing suddenly becomes faster after a kernel update. Although, at 
> > least looking at the 4.8 tree I'm using for development, it's only the 
> > sunxi NAND driver which uses it, so I guess it would be alright to change 
> > as it is not in widespread use yet?
> 
> I would definitely prefer this approach.

I don't mind making a patch for nand_ids.c which sets a more aggressive 
timing mode for at least flashes in the 1..4 Gb range. As I mentioned 
though I'm not entirely confident saying that that is in fact the case for 
_all_ flashes of that size, but perhaps it's good enough for now making 
that assumption given the flashes I've actually looked at? (I could refer 
to a number of chips in the commit message for reference).

> > The sunxi driver seems to presume the latter, whereas the entries in 
> > nand_ids.c would seem to imply the former, with values such as 2 (for 
> > the TC58NVG0S3E) and 4 (for the H27UCG8T2ATR-BC) - surely these chips 
> > support more than a single timing mode?
> >
> Hm, no it's not. As can be seen here [1], if the NAND is not ONFi, then
> we're using the onfi_timing_mode_default value, which is encoding the
> highest supported mode. The other case is when the chip is ONFi
> compliant, and in this case, the timing_mode field in exposing
> supported modes as a bitmap.
> [1]http://lxr.free-electrons.com/source/drivers/mtd/nand/sunxi_nand.c#L1723

Yes, you're right of course, I was thrown by the fact that the mode 
variable in the sunxi_nand_chip_init_timings() function is used to 
both represent the bit vector and the actual timing mode.

> One last thing, we recently introduced a generic timing selection/setup
> infrastructure [2] to avoid duplicating the code pointed here [1] in all
> drivers. It's been merged in 4.9, and that'd would be better to use
> this infrastructure in your driver.
>
> [2]https://www.spinics.net/lists/arm-kernel/msg532007.html

One thing I would have liked to have is to have the actual timing mode 
number in the nand_data_interface struct, for controllers like in my case 
where it's problematic to take the numeric timing values and map them to 
register values, and the timing register values need to be pre-computed. 
There might be other reasons where the driver might want to know the mode 
number. Sure, once a mode has been agreed on it is set in 
chip->onfi_timing_mode_default, but that won't help 
nand_init_data_interface() when it calls 
chip->setup_data_interface(..., true) to determine if a given mode is in 
fact supported by the controller.


A minor related issue which I been pondering over is that the fact that 
the supported timing modes of an ONFi flash are expressed as a bit vector 
rather than just a single 'highest possible mode' value, which indicates 
that the idea is that a flash may support a certain mode but not 
necessarily all the ones below, e.g. supporting modes 3, 2 and 0. A 
cursory look at the timing mode definition gives the impression that lower 
speeds are subcases of the higher speed ones, but it's hard to say if 
there are relationships between certain parameters that mean this is not 
necessarily so,

However, when we take the highest supported mode from the ID table, we 
convert it into a continguous bit vector using GENMASK() in 
nand_base.c:nand_init_data_interface(), thus assuming that the flash will 
in fact support all slower modes as well.

Perhaps there are no flashes which support a non-contiguous range of 
timing modes (I don't have enough experience with ONFi flashes to say 
one way or the other), it just seemed to me an odd discrepency and 
limitation for non-ONFi flashes.

/Ricard
-- 
Ricard Wolf Wanderl?f                           ricardw(at)axis.com
Axis Communications AB, Lund, Sweden            www.axis.com
Phone +46 46 272 2016                           Fax +46 46 13 61 30


From ricard.wanderlof at axis.com  Fri Oct 28 07:40:44 2016
From: ricard.wanderlof at axis.com (Ricard Wanderlof)
Date: Fri, 28 Oct 2016 16:40:44 +0200
Subject: OOB Test fails
In-Reply-To: <39BC08CB3FF4C84CB6397533D4FC79095770D803@SEGOTEXCH02.ascom-Resource.ads>
References: <39BC08CB3FF4C84CB6397533D4FC79095770D513@SEGOTEXCH02.ascom-Resource.ads>
 <CALupW3CJ_gXS+7BrZEGTF8o0H8pJ_AOw0JcKOftSVaMVSbP1zQ@mail.gmail.com>
 <20161027093407.53a76657@bbrezillon> <20161027174527.6003fd37@bbrezillon>
 <39BC08CB3FF4C84CB6397533D4FC79095770D803@SEGOTEXCH02.ascom-Resource.ads>
Message-ID: <alpine.DEB.2.02.1610281639120.9986@lnxricardw1.se.axis.com>


On Fri, 28 Oct 2016, Danesh Daroui wrote:

> I have one question and would appreciate if you can assist me with that. 
> As I wrote we are using a Micron NAND 1GiB 3,3V 8-bit flash memory with 
> UBIFS where we experience some problems.

For what its worth, we've been using precisely this flash in many of our 
products for quite a while without any special drivers and with no OOB 
problems.

/Ricard
-- 
Ricard Wolf Wanderl?f                           ricardw(at)axis.com
Axis Communications AB, Lund, Sweden            www.axis.com
Phone +46 46 272 2016                           Fax +46 46 13 61 30


From boris.brezillon at free-electrons.com  Fri Oct 28 07:44:40 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Fri, 28 Oct 2016 16:44:40 +0200
Subject: [PATCH 1/4] of: Add device tree bindings for Evatronix
In-Reply-To: <alpine.DEB.2.02.1610280900260.9986@lnxricardw1.se.axis.com>
References: <alpine.DEB.2.02.1606020946500.19416@lnxricardw1.se.axis.com>
 <20160603162207.0688c9e6@bbrezillon>
 <alpine.DEB.2.02.1606060757180.23377@lnxricardw1.se.axis.com>
 <20160608175018.16c88207@bbrezillon>
 <alpine.DEB.2.02.1606101641050.30757@lnxricardw1.se.axis.com>
 <20160610175454.327f51a2@bbrezillon>
 <alpine.DEB.2.02.1610261152170.9986@lnxricardw1.se.axis.com>
 <20161026135241.63653c4f@bbrezillon>
 <alpine.DEB.2.02.1610261359290.9986@lnxricardw1.se.axis.com>
 <20161026150557.587a7387@bbrezillon>
 <alpine.DEB.2.02.1610280900260.9986@lnxricardw1.se.axis.com>
Message-ID: <20161028164440.253b0c96@bbrezillon>

On Fri, 28 Oct 2016 16:35:20 +0200
Ricard Wanderlof <ricard.wanderlof at axis.com> wrote:

> Hi Boris,
> 
> On Wed, 26 Oct 2016, Boris Brezillon wrote:
> 
> > > However, mildly accelerated chip timing (i.e. ONFi mode 2) I wouldn't call 
> > > an advanced feature, and it seems to be supported by all of the chips in 
> > > the 1..4 Gb range that we've seen, although I wouldn't be so bold and go 
> > > so far as to say that I know all available flash chips (at least in this 
> > > size range) support that mode. That's why I'm reluctant to suggest 
> > > changing the entries for these flashes in the table in nand_ids.c, which 
> > > would be another alternative. And if we did make that change, it might 
> > > cause problems in systems which currently use onfi_timing_mode_default if 
> > > the timing suddenly becomes faster after a kernel update. Although, at 
> > > least looking at the 4.8 tree I'm using for development, it's only the 
> > > sunxi NAND driver which uses it, so I guess it would be alright to change 
> > > as it is not in widespread use yet?  
> > 
> > I would definitely prefer this approach.  
> 
> I don't mind making a patch for nand_ids.c which sets a more aggressive 
> timing mode for at least flashes in the 1..4 Gb range. As I mentioned 
> though I'm not entirely confident saying that that is in fact the case for 
> _all_ flashes of that size, but perhaps it's good enough for now making 
> that assumption given the flashes I've actually looked at? (I could refer 
> to a number of chips in the commit message for reference).
> 
> > > The sunxi driver seems to presume the latter, whereas the entries in 
> > > nand_ids.c would seem to imply the former, with values such as 2 (for 
> > > the TC58NVG0S3E) and 4 (for the H27UCG8T2ATR-BC) - surely these chips 
> > > support more than a single timing mode?
> > >  
> > Hm, no it's not. As can be seen here [1], if the NAND is not ONFi, then
> > we're using the onfi_timing_mode_default value, which is encoding the
> > highest supported mode. The other case is when the chip is ONFi
> > compliant, and in this case, the timing_mode field in exposing
> > supported modes as a bitmap.
> > [1]http://lxr.free-electrons.com/source/drivers/mtd/nand/sunxi_nand.c#L1723  
> 
> Yes, you're right of course, I was thrown by the fact that the mode 
> variable in the sunxi_nand_chip_init_timings() function is used to 
> both represent the bit vector and the actual timing mode.
> 
> > One last thing, we recently introduced a generic timing selection/setup
> > infrastructure [2] to avoid duplicating the code pointed here [1] in all
> > drivers. It's been merged in 4.9, and that'd would be better to use
> > this infrastructure in your driver.
> >
> > [2]https://www.spinics.net/lists/arm-kernel/msg532007.html  
> 
> One thing I would have liked to have is to have the actual timing mode 
> number in the nand_data_interface struct, for controllers like in my case 
> where it's problematic to take the numeric timing values and map them to 
> register values, and the timing register values need to be pre-computed. 

What do you mean by pre-computed? If you're able to pre-compute the
timings, why can't you do that at runtime?

> There might be other reasons where the driver might want to know the mode 
> number.

Do you have real examples?

> Sure, once a mode has been agreed on it is set in 
> chip->onfi_timing_mode_default, but that won't help 
> nand_init_data_interface() when it calls 
> chip->setup_data_interface(..., true) to determine if a given mode is in 
> fact supported by the controller.

We could pass the ONFI timing mode here, but some timings are not
defined using this mode (like tCCS), and I'm not sure we have the same
mapping between ONFI and JEDEC modes. The other thing is that I wanted
to leave the door open for vendor specific timing definitions which do
not exactly match one of the timing mode defined in the ONFI spec.

That's why I didn't bother exposing the ONFI timing mode to the NAND
controller ->setup_data_interface() implementation.

> 
> 
> A minor related issue which I been pondering over is that the fact that 
> the supported timing modes of an ONFi flash are expressed as a bit vector 
> rather than just a single 'highest possible mode' value, which indicates 
> that the idea is that a flash may support a certain mode but not 
> necessarily all the ones below, e.g. supporting modes 3, 2 and 0. A 
> cursory look at the timing mode definition gives the impression that lower 
> speeds are subcases of the higher speed ones, but it's hard to say if 
> there are relationships between certain parameters that mean this is not 
> necessarily so,
> 
> However, when we take the highest supported mode from the ID table, we 
> convert it into a continguous bit vector using GENMASK() in 
> nand_base.c:nand_init_data_interface(), thus assuming that the flash will 
> in fact support all slower modes as well.
> 
> Perhaps there are no flashes which support a non-contiguous range of 
> timing modes (I don't have enough experience with ONFi flashes to say 
> one way or the other), it just seemed to me an odd discrepency and 
> limitation for non-ONFi flashes.

That was a deliberate choice. Honestly, I've never seen a NAND that is
capable of supporting higher modes without supporting the lower ones.
If that ever happens, we'll switch back to a bitmap, but that's rather
unlikely.



From ricard.wanderlof at axis.com  Fri Oct 28 09:01:44 2016
From: ricard.wanderlof at axis.com (Ricard Wanderlof)
Date: Fri, 28 Oct 2016 18:01:44 +0200
Subject: [PATCH 1/4] of: Add device tree bindings for Evatronix
In-Reply-To: <20161028164440.253b0c96@bbrezillon>
References: <alpine.DEB.2.02.1606020946500.19416@lnxricardw1.se.axis.com>
 <20160603162207.0688c9e6@bbrezillon>
 <alpine.DEB.2.02.1606060757180.23377@lnxricardw1.se.axis.com>
 <20160608175018.16c88207@bbrezillon>
 <alpine.DEB.2.02.1606101641050.30757@lnxricardw1.se.axis.com>
 <20160610175454.327f51a2@bbrezillon>
 <alpine.DEB.2.02.1610261152170.9986@lnxricardw1.se.axis.com>
 <20161026135241.63653c4f@bbrezillon>
 <alpine.DEB.2.02.1610261359290.9986@lnxricardw1.se.axis.com>
 <20161026150557.587a7387@bbrezillon>
 <alpine.DEB.2.02.1610280900260.9986@lnxricardw1.se.axis.com>
 <20161028164440.253b0c96@bbrezillon>
Message-ID: <alpine.DEB.2.02.1610281725060.9986@lnxricardw1.se.axis.com>


On Fri, 28 Oct 2016, Boris Brezillon wrote:

> > One thing I would have liked to have is to have the actual timing mode 
> > number in the nand_data_interface struct, for controllers like in my case 
> > where it's problematic to take the numeric timing values and map them to 
> > register values, and the timing register values need to be pre-computed. 
> 
> What do you mean by pre-computed? If you're able to pre-compute the
> timings, why can't you do that at runtime?

The short answer in this case is because the timing values were delivered 
by our ASIC integration vendor, partly after running simulations to verify 
the exact timing using the actual silicon layout. That is why I originally 
wanted to put those timing register values directly in the DT, becuase 
they are in practice part of the specifications for the actual ASIC. In 
essence, we looked at the flash chips we wanted to use with the ASIC, and 
realized they all conformed to ONFi mode 2. Our vendor then provided us 
with mode 2 timing values that they guaranteed would work with the chip. 
(In addition, mode 0 is used during initial boot so minimize the 
likeleyhood that something would go wrong, given that the boot loader is 
in a ROM.) Especially given that there was no mtd timing setup 
infrastructure at the time, we had no interest in how the values were 
derived, or to support more modes.

Another issue is how to model the internal delays within the ASIC between 
the NAND controller IP and the pads, which are also part of the equation.

I don't know if our case is unique, but at least it is an example of a 
situation in which runtime calculation of the timing register values is 
problematic.

> > There might be other reasons where the driver might want to know the mode 
> > number.
> 
> Do you have real examples?

No, it just seemed like a reasonable concept, given that 
nand_init_data_interface() actually does this mapping anyway, so it might 
as well inform chip->setup_data_interface() about it, since the 
information is right there anyway.

> We could pass the ONFI timing mode here, but some timings are not
> defined using this mode (like tCCS), and I'm not sure we have the same
> mapping between ONFI and JEDEC modes. The other thing is that I wanted
> to leave the door open for vendor specific timing definitions which do
> not exactly match one of the timing mode defined in the ONFI spec.
> 
> That's why I didn't bother exposing the ONFI timing mode to the NAND
> controller ->setup_data_interface() implementation.

Ok, so the reason is really future expansion, where ONFi modes 0..5 may 
not be the only modes to be configured. Fair enough.

> > A minor related issue which I been pondering over is that the fact that 
> > the supported timing modes of an ONFi flash are expressed as a bit vector 
> > rather than just a single 'highest possible mode' value, which indicates 
> > that the idea is that a flash may support a certain mode but not 
> > necessarily all the ones below, e.g. supporting modes 3, 2 and 0.
> 
> That was a deliberate choice. Honestly, I've never seen a NAND that is
> capable of supporting higher modes without supporting the lower ones.
> If that ever happens, we'll switch back to a bitmap, but that's rather
> unlikely.

I agree, I would find that hard to believe too. I just don't have the 
experience to back that up. And the fact that ONFi chips actually do 
report this as a bitmap indicates that someone at some time considered 
this a distinct possibility. Or it could just be part of making the 
specification as general as possible without actually having any practical 
case for it.

/Ricard
-- 
Ricard Wolf Wanderl?f                           ricardw(at)axis.com
Axis Communications AB, Lund, Sweden            www.axis.com
Phone +46 46 272 2016                           Fax +46 46 13 61 30


From joerg.krause at embedded.rocks  Fri Oct 28 09:19:04 2016
From: joerg.krause at embedded.rocks (=?ISO-8859-1?Q?J=F6rg?= Krause)
Date: Fri, 28 Oct 2016 18:19:04 +0200
Subject: [PATCH] ubifs: Fix regression in ubifs_readdir()
In-Reply-To: <1477648432-9543-1-git-send-email-richard@nod.at>
References: <1477648432-9543-1-git-send-email-richard@nod.at>
Message-ID: <1477671544.8927.1.camel@embedded.rocks>

Hi,

On Fri, 2016-10-28 at 11:53 +0200, Richard Weinberger wrote:
> Commit c83ed4c9dbb35 ("ubifs: Abort readdir upon error") broke
> overlayfs support because the fix exposed an internal error
> code to VFS.
> 
> Reported-by: Peter Rosin <peda at axentia.se>
> Tested-by: Peter Rosin <peda at axentia.se>
> Reported-by: Ralph Sennhauser <ralph.sennhauser at gmail.com>
> Fixes: c83ed4c9dbb35 ("ubifs: Abort readdir upon error")
> Cc: stable at vger.kernel.org
> Signed-off-by: Richard Weinberger <richard at nod.at>
> ---
> ?fs/ubifs/dir.c | 8 ++++++++
> ?1 file changed, 8 insertions(+)
> 
> diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
> index bd4a5e8ce441..ca16c5d7bab1 100644
> --- a/fs/ubifs/dir.c
> +++ b/fs/ubifs/dir.c
> @@ -543,6 +543,14 @@ static int ubifs_readdir(struct file *file,
> struct dir_context *ctx)
> ?
> ?	if (err != -ENOENT)
> ?		ubifs_err(c, "cannot find next direntry, error %d",
> err);
> +	else
> +		/*
> +		?* -ENOENT is a non-fatal error in this context, the
> TNC uses
> +		?* it to indicate that the cursor moved past the
> current directory
> +		?* and readdir() has to stop.
> +		?*/
> +		err = 0;
> +
> ?
> ?	/* 2 is a special value indicating that there are no more
> direntries */
> ?	ctx->pos = 2;

I'm not sure if it's related to the issue reported by Peter Rosin and
Ralph Sennhauser, but I am still getting a kernel panic using UBIFS
with OverlayFS on Linux v4.9.0-rc2 with this patch applied:


"""
[????2.709197] ubi0: default fastmap pool size: 15
[????2.713806] ubi0: default fastmap WL pool size: 7
[????2.718776] ubi0: attaching mtd5
[????3.690342] ubi0: scanning is finished
[????3.726232] ubi0 warning: ubi_eba_init: cannot reserve enough PEBs
for bad PEB handling, reserved 18, need 20
[????3.756003] ubi0: attached mtd5 (name "ubi-0", size 44 MiB)
[????3.761658] ubi0: PEB size: 131072 bytes (128 KiB), LEB size: 126976
bytes
[????3.768857] ubi0: min./max. I/O unit sizes: 2048/2048, sub-page size
2048
[????3.775860] ubi0: VID header offset: 2048 (aligned 2048), data
offset: 4096
[????3.782886] ubi0: good PEBs: 352, bad PEBs: 0, corrupted PEBs: 0
[????3.789080] ubi0: user volume: 1, internal volumes: 1, max. volumes
count: 128
[????3.796501] ubi0: max/mean erase counter: 1/0, WL threshold: 4096,
image sequence number: 955660178
[????3.805742] ubi0: available PEBs: 0, total reserved PEBs: 352, PEBs
reserved for bad PEB handling: 18
[????3.815502] ubi0: background thread "ubi_bgt0d" started, PID 40
[????3.822173] ubi1: default fastmap pool size: 10
[????3.827213] ubi1: default fastmap WL pool size: 5
[????3.832016] ubi1: attaching mtd7
[????4.278806] ubi1: scanning is finished
[????4.376526] ubi1: volume 0 ("user") re-sized from 13 to 162 LEBs
[????4.391959] ubi1: attached mtd7 (name "data", size 36 MiB)
[????4.397813] ubi1: PEB size: 131072 bytes (128 KiB), LEB size: 126976
bytes
[????4.404761] ubi1: min./max. I/O unit sizes: 2048/2048, sub-page size
2048
[????4.411752] ubi1: VID header offset: 2048 (aligned 2048), data
offset: 4096
[????4.418909] ubi1: good PEBs: 288, bad PEBs: 0, corrupted PEBs: 0
[????4.425107] ubi1: user volume: 2, internal volumes: 1, max. volumes
count: 128
[????4.432399] ubi1: max/mean erase counter: 1/0, WL threshold: 4096,
image sequence number: 1961582752
[????4.441714] ubi1: available PEBs: 0, total reserved PEBs: 288, PEBs
reserved for bad PEB handling: 20
[????4.451267] ubi1: background thread "ubi_bgt1d" started, PID 41
[????4.469335] input: gpio-keys as /devices/soc0/gpio-keys/input/input0
[????4.492732] stmp3xxx-rtc 80056000.rtc: setting system clock to 1970-
01-01 00:01:07 UTC (67)
[????4.506810] ALSA device list:
[????4.509854]???#0: mxs_wm8524
[????4.523140] uart-pl011 80074000.serial: no DMA platform data
[????4.909981] UBIFS (ubi0:1): UBIFS: mounted UBI device 0, volume 1,
name "rootfs", R/O mode
[????4.919428] UBIFS (ubi0:1): LEB size: 126976 bytes (124 KiB),
min./max. I/O unit sizes: 2048 bytes/2048 bytes
[????4.933097] UBIFS (ubi0:1): FS size: 40378368 bytes (38 MiB, 318
LEBs), journal size 5586944 bytes (5 MiB, 44 LEBs)
[????4.944659] UBIFS (ubi0:1): reserved for root: 0 bytes (0 KiB)
[????4.954275] UBIFS (ubi0:1): media format: w4/r0 (latest is w4/r0),
UUID 3F29D9B8-363D-4A54-8CE4-BF6969BB9687, small LPT model
[????4.993543] VFS: Mounted root (ubifs filesystem) readonly on device
0:13.
[????5.023313] devtmpfs: mounted
[????5.036855] Freeing unused kernel memory: 144K (c0506000 - c052a000)
[????5.043278] This architecture does not have kernel memory
protection.
[????5.869112] UBIFS (ubi1:0): background thread "ubifs_bgt1_0"
started, PID 43
[????6.056630] UBIFS (ubi1:0): start fixing up free space
[????6.162648] UBIFS (ubi1:0): free space fixup complete
[????6.263554] UBIFS (ubi1:0): UBIFS: mounted UBI device 1, volume 0,
name "user"
[????6.271600] UBIFS (ubi1:0): LEB size: 126976 bytes (124 KiB),
min./max. I/O unit sizes: 2048 bytes/2048 bytes
[????6.285552] UBIFS (ubi1:0): FS size: 19300352 bytes (18 MiB, 152
LEBs), journal size 3047424 bytes (2 MiB, 24 LEBs)
[????6.296731] UBIFS (ubi1:0): reserved for root: 0 bytes (0 KiB)
[????6.306432] UBIFS (ubi1:0): media format: w4/r0 (latest is w4/r0),
UUID A5813F13-6645-4096-B663-A08D87959541, small LPT model
[????6.542487] random: crng init done
mount: mounting overlay on /mnt/overlay failed: No such file or
directory
mount: mounting /dev on /mnt/overlay/dev failed: No such file or
directory
mount: mounting /mnt/user on /mnt/overlay/mnt/user failed: No such file
or directory
chroot: can't execute '/sbin/init': No such file or directory
[????6.670206] Kernel panic - not syncing: Attempted to kill init!
exitcode=0x00007f00
[????6.670206]?
[????6.679426] CPU: 0 PID: 1 Comm: chroot Not tainted 4.9.0-rc2-LINTECH 
#1
[????6.686075] Hardware name: Freescale MXS (Device Tree)
[????6.691320] [<c000f150>] (unwind_backtrace) from [<c000d318>]
(show_stack+0x10/0x14)
[????6.699143] [<c000d318>] (show_stack) from [<c0092338>]
(panic+0xb4/0x23c)
[????6.706098] [<c0092338>] (panic) from [<c00183dc>]
(do_exit+0x450/0x84c)
[????6.712866] [<c00183dc>] (do_exit) from [<c0019ecc>]
(do_group_exit+0xb8/0xbc)
[????6.720150] [<c0019ecc>] (do_group_exit) from [<c0019ee0>]
(SyS_exit_group+0x10/0x14)
[????6.728037] [<c0019ee0>] (SyS_exit_group) from [<c000a160>]
(ret_fast_syscall+0x0/0x1c)
[????6.736155] ---[ end Kernel panic - not syncing: Attempted to kill
init! exitcode=0x00007f00
"""

This is my preinit script:

"""
#!/bin/sh

mount -t ubifs /dev/ubi1_0 /mnt/user

mkdir -p /mnt/user/overlay
mkdir -p /mnt/user/work

# Overlay read-only rootfs and read-write user filesystem.
mount -t overlay overlay -o
lowerdir=/,upperdir=/mnt/user/overlay,workdir=/mnt/user/work,noatime
/mnt/overlay

# Move necessary mount points
mount -n --move /dev /mnt/overlay/dev
mount -n --move /mnt/user /mnt/overlay/mnt/user

exec chroot /mnt/overlay /sbin/init
"""

Note, this is working on Linux 4.7.

Best regards
J?rg Krause


From boris.brezillon at free-electrons.com  Fri Oct 28 09:20:22 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Fri, 28 Oct 2016 18:20:22 +0200
Subject: [PATCH 1/4] of: Add device tree bindings for Evatronix
In-Reply-To: <alpine.DEB.2.02.1610281725060.9986@lnxricardw1.se.axis.com>
References: <alpine.DEB.2.02.1606020946500.19416@lnxricardw1.se.axis.com>
 <20160603162207.0688c9e6@bbrezillon>
 <alpine.DEB.2.02.1606060757180.23377@lnxricardw1.se.axis.com>
 <20160608175018.16c88207@bbrezillon>
 <alpine.DEB.2.02.1606101641050.30757@lnxricardw1.se.axis.com>
 <20160610175454.327f51a2@bbrezillon>
 <alpine.DEB.2.02.1610261152170.9986@lnxricardw1.se.axis.com>
 <20161026135241.63653c4f@bbrezillon>
 <alpine.DEB.2.02.1610261359290.9986@lnxricardw1.se.axis.com>
 <20161026150557.587a7387@bbrezillon>
 <alpine.DEB.2.02.1610280900260.9986@lnxricardw1.se.axis.com>
 <20161028164440.253b0c96@bbrezillon>
 <alpine.DEB.2.02.1610281725060.9986@lnxricardw1.se.axis.com>
Message-ID: <20161028182022.7643c4ea@bbrezillon>

On Fri, 28 Oct 2016 18:01:44 +0200
Ricard Wanderlof <ricard.wanderlof at axis.com> wrote:

> On Fri, 28 Oct 2016, Boris Brezillon wrote:
> 
> > > One thing I would have liked to have is to have the actual timing mode 
> > > number in the nand_data_interface struct, for controllers like in my case 
> > > where it's problematic to take the numeric timing values and map them to 
> > > register values, and the timing register values need to be pre-computed.   
> > 
> > What do you mean by pre-computed? If you're able to pre-compute the
> > timings, why can't you do that at runtime?  
> 
> The short answer in this case is because the timing values were delivered 
> by our ASIC integration vendor, partly after running simulations to verify 
> the exact timing using the actual silicon layout. That is why I originally 
> wanted to put those timing register values directly in the DT, becuase 
> they are in practice part of the specifications for the actual ASIC. In 
> essence, we looked at the flash chips we wanted to use with the ASIC, and 
> realized they all conformed to ONFi mode 2. Our vendor then provided us 
> with mode 2 timing values that they guaranteed would work with the chip. 
> (In addition, mode 0 is used during initial boot so minimize the 
> likeleyhood that something would go wrong, given that the boot loader is 
> in a ROM.) Especially given that there was no mtd timing setup 
> infrastructure at the time, we had no interest in how the values were 
> derived, or to support more modes.
> 
> Another issue is how to model the internal delays within the ASIC between 
> the NAND controller IP and the pads, which are also part of the equation.
> 
> I don't know if our case is unique, but at least it is an example of a 
> situation in which runtime calculation of the timing register values is 
> problematic.

Okay. I guess we could add the associated ONFI timing mode to the
nand_data_interface struct (it would represent the closest one if the
NAND is not ONFI and some vendor specific implementation decided to
tweak the timing values).

> 
> > > There might be other reasons where the driver might want to know the mode 
> > > number.  
> > 
> > Do you have real examples?  
> 
> No, it just seemed like a reasonable concept, given that 
> nand_init_data_interface() actually does this mapping anyway, so it might 
> as well inform chip->setup_data_interface() about it, since the 
> information is right there anyway.
> 
> > We could pass the ONFI timing mode here, but some timings are not
> > defined using this mode (like tCCS), and I'm not sure we have the same
> > mapping between ONFI and JEDEC modes. The other thing is that I wanted
> > to leave the door open for vendor specific timing definitions which do
> > not exactly match one of the timing mode defined in the ONFI spec.
> > 
> > That's why I didn't bother exposing the ONFI timing mode to the NAND
> > controller ->setup_data_interface() implementation.  
> 
> Ok, so the reason is really future expansion, where ONFi modes 0..5 may 
> not be the only modes to be configured. Fair enough.

Yep.


From richard at nod.at  Fri Oct 28 10:07:26 2016
From: richard at nod.at (Richard Weinberger)
Date: Fri, 28 Oct 2016 19:07:26 +0200
Subject: [PATCH] ubifs: Fix regression in ubifs_readdir()
In-Reply-To: <1477671544.8927.1.camel@embedded.rocks>
References: <1477648432-9543-1-git-send-email-richard@nod.at>
 <1477671544.8927.1.camel@embedded.rocks>
Message-ID: <c542e099-0404-be8e-ebeb-d4265d3204d6@nod.at>

J?rg,

On 28.10.2016 18:19, J?rg Krause wrote:
> Hi,
> 
> On Fri, 2016-10-28 at 11:53 +0200, Richard Weinberger wrote:
>> Commit c83ed4c9dbb35 ("ubifs: Abort readdir upon error") broke
>> overlayfs support because the fix exposed an internal error
>> code to VFS.
>>
>> Reported-by: Peter Rosin <peda at axentia.se>
>> Tested-by: Peter Rosin <peda at axentia.se>
>> Reported-by: Ralph Sennhauser <ralph.sennhauser at gmail.com>
>> Fixes: c83ed4c9dbb35 ("ubifs: Abort readdir upon error")
>> Cc: stable at vger.kernel.org
>> Signed-off-by: Richard Weinberger <richard at nod.at>
>> ---
>>  fs/ubifs/dir.c | 8 ++++++++
>>  1 file changed, 8 insertions(+)
>>
>> diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
>> index bd4a5e8ce441..ca16c5d7bab1 100644
>> --- a/fs/ubifs/dir.c
>> +++ b/fs/ubifs/dir.c
>> @@ -543,6 +543,14 @@ static int ubifs_readdir(struct file *file,
>> struct dir_context *ctx)
>>  
>>  	if (err != -ENOENT)
>>  		ubifs_err(c, "cannot find next direntry, error %d",
>> err);
>> +	else
>> +		/*
>> +		 * -ENOENT is a non-fatal error in this context, the
>> TNC uses
>> +		 * it to indicate that the cursor moved past the
>> current directory
>> +		 * and readdir() has to stop.
>> +		 */
>> +		err = 0;
>> +
>>  
>>  	/* 2 is a special value indicating that there are no more
>> direntries */
>>  	ctx->pos = 2;
> 
> I'm not sure if it's related to the issue reported by Peter Rosin and
> Ralph Sennhauser, but I am still getting a kernel panic using UBIFS
> with OverlayFS on Linux v4.9.0-rc2 with this patch applied:

Does reverting c83ed4c9dbb35 help?
And are you 100% sure you applied the fix?

Does the following WARN_ON() trigger?
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index ca16c5d7bab1..12ffc91f7ef8 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -554,6 +554,9 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)

 	/* 2 is a special value indicating that there are no more direntries */
 	ctx->pos = 2;
+
+	WARN_ON(err);
+
 	return err;
 }


Thanks,
//richard


From colin.king at canonical.com  Fri Oct 28 11:25:59 2016
From: colin.king at canonical.com (Colin King)
Date: Fri, 28 Oct 2016 19:25:59 +0100
Subject: [PATCH] mtd: mtdswap: fix spelling mistake "erassure" -> "erasure"
Message-ID: <20161028182559.7887-1-colin.king@canonical.com>

From: Colin Ian King <colin.king at canonical.com>

Trivial fix to spelling mistake in dev_err message

Signed-off-by: Colin Ian King <colin.king at canonical.com>
---
 drivers/mtd/mtdswap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c
index cb06bdd..d0402df 100644
--- a/drivers/mtd/mtdswap.c
+++ b/drivers/mtd/mtdswap.c
@@ -587,7 +587,7 @@ static int mtdswap_erase_block(struct mtdswap_dev *d, struct swap_eb *eb)
 	ret = wait_event_interruptible(wq, erase.state == MTD_ERASE_DONE ||
 					   erase.state == MTD_ERASE_FAILED);
 	if (ret) {
-		dev_err(d->dev, "Interrupted erase block %#llx erassure on %s",
+		dev_err(d->dev, "Interrupted erase block %#llx erasure on %s",
 			erase.addr, mtd->name);
 		return -EINTR;
 	}
-- 
2.9.3



From colin.king at canonical.com  Fri Oct 28 11:35:23 2016
From: colin.king at canonical.com (Colin King)
Date: Fri, 28 Oct 2016 19:35:23 +0100
Subject: [PATCH] mtd: mtdswap: fix spelling mistake "erassure" -> "erasure"
Message-ID: <20161028183523.8135-1-colin.king@canonical.com>

From: Colin Ian King <colin.king at canonical.com>

Trivial fix to spelling mistake in dev_err message

Signed-off-by: Colin Ian King <colin.king at canonical.com>
---
 drivers/mtd/mtdswap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c
index cb06bdd..d0402df 100644
--- a/drivers/mtd/mtdswap.c
+++ b/drivers/mtd/mtdswap.c
@@ -587,7 +587,7 @@ static int mtdswap_erase_block(struct mtdswap_dev *d, struct swap_eb *eb)
 	ret = wait_event_interruptible(wq, erase.state == MTD_ERASE_DONE ||
 					   erase.state == MTD_ERASE_FAILED);
 	if (ret) {
-		dev_err(d->dev, "Interrupted erase block %#llx erassure on %s",
+		dev_err(d->dev, "Interrupted erase block %#llx erasure on %s",
 			erase.addr, mtd->name);
 		return -EINTR;
 	}
-- 
2.9.3



From colin.king at canonical.com  Fri Oct 28 11:35:48 2016
From: colin.king at canonical.com (Colin King)
Date: Fri, 28 Oct 2016 19:35:48 +0100
Subject: [PATCH] mfd: si476x-i2c: Fix spelling mistakes "Failet" and "gett"
Message-ID: <20161028183548.8190-1-colin.king@canonical.com>

From: Colin Ian King <colin.king at canonical.com>

Trivial spelling mistake fixes in dev_err message.

Signed-off-by: Colin Ian King <colin.king at canonical.com>
---
 drivers/mfd/si476x-i2c.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mfd/si476x-i2c.c b/drivers/mfd/si476x-i2c.c
index c180b75..e6a3d99 100644
--- a/drivers/mfd/si476x-i2c.c
+++ b/drivers/mfd/si476x-i2c.c
@@ -753,7 +753,7 @@ static int si476x_core_probe(struct i2c_client *client,
 				       ARRAY_SIZE(core->supplies),
 				       core->supplies);
 	if (rval) {
-		dev_err(&client->dev, "Failet to gett all of the regulators\n");
+		dev_err(&client->dev, "Failed to get all of the regulators\n");
 		goto free_gpio;
 	}
 
-- 
2.9.3



From joe at perches.com  Fri Oct 28 11:51:47 2016
From: joe at perches.com (Joe Perches)
Date: Fri, 28 Oct 2016 11:51:47 -0700
Subject: [PATCH] mtd: mtdswap: fix spelling mistake "erassure" -> "erasure"
In-Reply-To: <20161028182559.7887-1-colin.king@canonical.com>
References: <20161028182559.7887-1-colin.king@canonical.com>
Message-ID: <1477680707.7945.13.camel@perches.com>

I'd suggest as well fixing all the dev_<level> uses
to be a consistent form: (this also fixes the typo)
and a few other bits

o Coalesce formats
o Realign arguments
o Add missing newlines
o Convert printk(KERN_<LEVEL> to pr_<level>(
o Add #define pr_fmt, remove MTDSWAP_PREFIX

Reduces object size a little too
---
?drivers/mtd/mtdswap.c | 74 +++++++++++++++++++++++----------------------------
?1 file changed, 34 insertions(+), 40 deletions(-)

diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c
index cb06bdd21a1b..60ca953b3314 100644
--- a/drivers/mtd/mtdswap.c
+++ b/drivers/mtd/mtdswap.c
@@ -24,6 +24,8 @@
? * 02110-1301 USA
? */
?
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
?#include?
?#include?
?#include?
@@ -39,8 +41,6 @@
?#include?
?#include?
?
-#define MTDSWAP_PREFIX "mtdswap"
-
?/*
? * The number of free eraseblocks when GC should stop
? */
@@ -282,8 +282,8 @@ static int mtdswap_handle_badblock(struct mtdswap_dev *d, struct swap_eb *eb)
?	ret = mtd_block_markbad(d->mtd, offset);
?
?	if (ret) {
-		dev_warn(d->dev, "Mark block bad failed for block at %08llx "
-			"error %d\n", offset, ret);
+		dev_warn(d->dev, "Mark block bad failed for block at %08llx error %d\n",
+			?offset, ret);
?		return ret;
?	}
?
@@ -319,14 +319,13 @@ static int mtdswap_read_oob(struct mtdswap_dev *d, loff_t from,
?
?	if (ret) {
?		dev_warn(d->dev, "Read OOB failed %d for block at %08llx\n",
-			ret, from);
+			?ret, from);
?		return ret;
?	}
?
?	if (ops->oobretlen < ops->ooblen) {
-		dev_warn(d->dev, "Read OOB return short read (%zd bytes not "
-			"%zd) for block at %08llx\n",
-			ops->oobretlen, ops->ooblen, from);
+		dev_warn(d->dev, "Read OOB return short read (%zd bytes not %zd) for block at %08llx\n",
+			?ops->oobretlen, ops->ooblen, from);
?		return -EIO;
?	}
?
@@ -406,17 +405,16 @@ static int mtdswap_write_marker(struct mtdswap_dev *d, struct swap_eb *eb,
?	ret = mtd_write_oob(d->mtd, offset, &ops);
?
?	if (ret) {
-		dev_warn(d->dev, "Write OOB failed for block at %08llx "
-			"error %d\n", offset, ret);
+		dev_warn(d->dev, "Write OOB failed for block at %08llx error %d\n",
+			?offset, ret);
?		if (ret == -EIO || mtd_is_eccerr(ret))
?			mtdswap_handle_write_error(d, eb);
?		return ret;
?	}
?
?	if (ops.oobretlen != ops.ooblen) {
-		dev_warn(d->dev, "Short OOB write for block at %08llx: "
-			"%zd not %zd\n",
-			offset, ops.oobretlen, ops.ooblen);
+		dev_warn(d->dev, "Short OOB write for block at %08llx: %zd not %zd\n",
+			?offset, ops.oobretlen, ops.ooblen);
?		return ret;
?	}
?
@@ -571,8 +569,8 @@ static int mtdswap_erase_block(struct mtdswap_dev *d, struct swap_eb *eb)
?	if (ret) {
?		if (retries++ < MTDSWAP_ERASE_RETRIES) {
?			dev_warn(d->dev,
-				"erase of erase block %#llx on %s failed",
-				erase.addr, mtd->name);
+				?"erase of erase block %#llx on %s failed\n",
+				?erase.addr, mtd->name);
?			yield();
?			goto retry;
?		}
@@ -587,7 +585,7 @@ static int mtdswap_erase_block(struct mtdswap_dev *d, struct swap_eb *eb)
?	ret = wait_event_interruptible(wq, erase.state == MTD_ERASE_DONE ||
?					???erase.state == MTD_ERASE_FAILED);
?	if (ret) {
-		dev_err(d->dev, "Interrupted erase block %#llx erassure on %s",
+		dev_err(d->dev, "Interrupted erase block %#llx erasure on %s\n",
?			erase.addr, mtd->name);
?		return -EINTR;
?	}
@@ -595,8 +593,8 @@ static int mtdswap_erase_block(struct mtdswap_dev *d, struct swap_eb *eb)
?	if (erase.state == MTD_ERASE_FAILED) {
?		if (retries++ < MTDSWAP_ERASE_RETRIES) {
?			dev_warn(d->dev,
-				"erase of erase block %#llx on %s failed",
-				erase.addr, mtd->name);
+				?"erase of erase block %#llx on %s failed\n",
+				?erase.addr, mtd->name);
?			yield();
?			goto retry;
?		}
@@ -699,13 +697,13 @@ static int mtdswap_write_block(struct mtdswap_dev *d, char *buf,
?	}
?
?	if (ret < 0) {
-		dev_err(d->dev, "Write to MTD device failed: %d (%zd written)",
+		dev_err(d->dev, "Write to MTD device failed: %d (%zd written)\n",
?			ret, retlen);
?		goto err;
?	}
?
?	if (retlen != PAGE_SIZE) {
-		dev_err(d->dev, "Short write to MTD device: %zd written",
+		dev_err(d->dev, "Short write to MTD device: %zd written\n",
?			retlen);
?		ret = -EIO;
?		goto err;
@@ -742,8 +740,7 @@ static int mtdswap_move_block(struct mtdswap_dev *d, unsigned int oldblock,
?		oldeb = d->eb_data + oldblock / d->pages_per_eblk;
?		oldeb->flags |= EBLOCK_READERR;
?
-		dev_err(d->dev, "Read Error: %d (block %u)\n", ret,
-			oldblock);
+		dev_err(d->dev, "Read Error: %d (block %u)\n", ret, oldblock);
?		retries++;
?		if (retries < MTDSWAP_IO_RETRIES)
?			goto retry;
@@ -752,8 +749,8 @@ static int mtdswap_move_block(struct mtdswap_dev *d, unsigned int oldblock,
?	}
?
?	if (retlen != PAGE_SIZE) {
-		dev_err(d->dev, "Short read: %zd (block %u)\n", retlen,
-		???????oldblock);
+		dev_err(d->dev, "Short read: %zd (block %u)\n",
+			retlen, oldblock);
?		ret = -EIO;
?		goto read_error;
?	}
@@ -1404,7 +1401,7 @@ static int mtdswap_init(struct mtdswap_dev *d, unsigned int eblocks,
?revmap_fail:
?	vfree(d->page_data);
?page_data_fail:
-	printk(KERN_ERR "%s: init failed (%d)\n", MTDSWAP_PREFIX, ret);
+	pr_err("init failed (%d)\n", ret);
?	return ret;
?}
?
@@ -1435,21 +1432,20 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
?		return;
?
?	if (mtd->erasesize < PAGE_SIZE || mtd->erasesize % PAGE_SIZE) {
-		printk(KERN_ERR "%s: Erase size %u not multiple of PAGE_SIZE "
-			"%lu\n", MTDSWAP_PREFIX, mtd->erasesize, PAGE_SIZE);
+		pr_err("Erase size %u not multiple of PAGE_SIZE %lu\n",
+		???????mtd->erasesize, PAGE_SIZE);
?		return;
?	}
?
?	if (PAGE_SIZE % mtd->writesize || mtd->writesize > PAGE_SIZE) {
-		printk(KERN_ERR "%s: PAGE_SIZE %lu not multiple of write size"
-			" %u\n", MTDSWAP_PREFIX, PAGE_SIZE, mtd->writesize);
+		pr_err("PAGE_SIZE %lu not multiple of write size %u\n",
+		???????PAGE_SIZE, mtd->writesize);
?		return;
?	}
?
?	if (!mtd->oobsize || mtd->oobavail < MTDSWAP_OOBSIZE) {
-		printk(KERN_ERR "%s: Not enough free bytes in OOB, "
-			"%d available, %zu needed.\n",
-			MTDSWAP_PREFIX, mtd->oobavail, MTDSWAP_OOBSIZE);
+		pr_err("Not enough free bytes in OOB, %d available, %zu needed\n",
+			mtd->oobavail, MTDSWAP_OOBSIZE);
?		return;
?	}
?
@@ -1460,8 +1456,8 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
?	size_limit = (uint64_t) BLOCK_MAX * PAGE_SIZE;
?
?	if (mtd->size > size_limit) {
-		printk(KERN_WARNING "%s: Device too large. Limiting size to "
-			"%llu bytes\n", MTDSWAP_PREFIX, size_limit);
+		pr_warn("Device too large - limiting size to %llu bytes\n",
+			size_limit);
?		use_size = size_limit;
?	}
?
@@ -1471,9 +1467,8 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
?	eavailable = eblocks - bad_blocks;
?
?	if (eavailable < MIN_ERASE_BLOCKS) {
-		printk(KERN_ERR "%s: Not enough erase blocks. %u available, "
-			"%d needed\n", MTDSWAP_PREFIX, eavailable,
-			MIN_ERASE_BLOCKS);
+		pr_err("Not enough erase blocks. %u available, %d needed\n",
+		???????eavailable, MIN_ERASE_BLOCKS);
?		return;
?	}
?
@@ -1488,9 +1483,8 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
?	swap_size = (uint64_t)(eavailable - spare_cnt) * mtd->erasesize +
?		(header ? PAGE_SIZE : 0);
?
-	printk(KERN_INFO "%s: Enabling MTD swap on device %lu, size %llu KB, "
-		"%u spare, %u bad blocks\n",
-		MTDSWAP_PREFIX, part, swap_size / 1024, spare_cnt, bad_blocks);
+	pr_info("Enabling MTD swap on device %lu, size %llu KB, %u spare, %u bad blocks\n",
+		part, swap_size / 1024, spare_cnt, bad_blocks);
?
?	d = kzalloc(sizeof(struct mtdswap_dev), GFP_KERNEL);
?	if (!d)


From zach.brown at ni.com  Fri Oct 28 13:27:44 2016
From: zach.brown at ni.com (Zach Brown)
Date: Fri, 28 Oct 2016 15:27:44 -0500
Subject: [PATCH v3 5/5] mtd: nand: set bb_per_lun and blocks_per_lun for ONFI
 compliant chips
In-Reply-To: <1477686464-7437-1-git-send-email-zach.brown@ni.com>
References: <1477686464-7437-1-git-send-email-zach.brown@ni.com>
Message-ID: <1477686464-7437-6-git-send-email-zach.brown@ni.com>

ONFI compliant chips contain the values for the bb_per_lun and
blocks_per_lun fields in the parameter page. When the ONFI paged is
retrieved/parsed the chip's fields are set by the corresponding fields
in the param page.

Signed-off-by: Zach Brown <zach.brown at ni.com>
---
 drivers/mtd/nand/nand_base.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index ed8dc89..c4ced91 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -3619,6 +3619,11 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
 	if (p->jedec_id == NAND_MFR_MICRON)
 		nand_onfi_detect_micron(chip, p);
 
+	if (p->bb_per_lun)
+		chip->bb_per_lun = p->bb_per_lun;
+	if (p->blocks_per_lun)
+		chip->blocks_per_lun = p->blocks_per_lun;
+
 	return 1;
 }
 
-- 
2.7.4



From zach.brown at ni.com  Fri Oct 28 13:27:41 2016
From: zach.brown at ni.com (Zach Brown)
Date: Fri, 28 Oct 2016 15:27:41 -0500
Subject: [PATCH v3 2/5] mtd: ubi: use 'max_bad_blocks' to compute
 bad_peb_limit if available
In-Reply-To: <1477686464-7437-1-git-send-email-zach.brown@ni.com>
References: <1477686464-7437-1-git-send-email-zach.brown@ni.com>
Message-ID: <1477686464-7437-3-git-send-email-zach.brown@ni.com>

From: Jeff Westfahl <jeff.westfahl at ni.com>

Use the MTD function 'max_bad_blocks' to compute the UBI bad_peb_limit,
if the function is implemented for an MTD and doesn't return an error.

Signed-off-by: Jeff Westfahl <jeff.westfahl at ni.com>
Signed-off-by: Zach Brown <zach.brown at ni.com>
---
 drivers/mtd/ubi/build.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 85d54f3..e9940a9 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -584,6 +584,10 @@ static int get_bad_peb_limit(const struct ubi_device *ubi, int max_beb_per1024)
 	int limit, device_pebs;
 	uint64_t device_size;
 
+	limit = mtd_max_bad_blocks(ubi->mtd, 0, ubi->mtd->size);
+	if (limit > 0)
+		return limit;
+
 	if (!max_beb_per1024)
 		return 0;
 
-- 
2.7.4



From zach.brown at ni.com  Fri Oct 28 13:27:40 2016
From: zach.brown at ni.com (Zach Brown)
Date: Fri, 28 Oct 2016 15:27:40 -0500
Subject: [PATCH v3 1/5] mtd: introduce function max_bad_blocks
In-Reply-To: <1477686464-7437-1-git-send-email-zach.brown@ni.com>
References: <1477686464-7437-1-git-send-email-zach.brown@ni.com>
Message-ID: <1477686464-7437-2-git-send-email-zach.brown@ni.com>

From: Jeff Westfahl <jeff.westfahl at ni.com>

If implemented, 'max_bad_blocks' returns the maximum number of bad
blocks to reserve for an MTD. An implementation for NAND is coming soon.

Signed-off-by: Jeff Westfahl <jeff.westfahl at ni.com>
Signed-off-by: Zach Brown <zach.brown at ni.com>
---
 drivers/mtd/mtdpart.c   | 13 +++++++++++++
 include/linux/mtd/mtd.h | 11 +++++++++++
 2 files changed, 24 insertions(+)

diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index fccdd49..2106bd5 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -349,6 +349,16 @@ static const struct mtd_ooblayout_ops part_ooblayout_ops = {
 	.free = part_ooblayout_free,
 };
 
+static int part_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+	struct mtd_part *part = mtd_to_part(mtd);
+
+	if ((len + ofs) > mtd->size)
+		return -EINVAL;
+	return part->master->_max_bad_blocks(part->master,
+					     ofs + part->offset, len);
+}
+
 static inline void free_partition(struct mtd_part *p)
 {
 	kfree(p->mtd.name);
@@ -481,6 +491,9 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
 	if (master->_put_device)
 		slave->mtd._put_device = part_put_device;
 
+	if (master->_max_bad_blocks)
+		slave->mtd._max_bad_blocks = part_max_bad_blocks;
+
 	slave->mtd._erase = part_erase;
 	slave->master = master;
 	slave->offset = part->offset;
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 13f8052..c02d3c2 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -322,6 +322,7 @@ struct mtd_info {
 	int (*_block_isreserved) (struct mtd_info *mtd, loff_t ofs);
 	int (*_block_isbad) (struct mtd_info *mtd, loff_t ofs);
 	int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs);
+	int (*_max_bad_blocks) (struct mtd_info *mtd, loff_t ofs, size_t len);
 	int (*_suspend) (struct mtd_info *mtd);
 	void (*_resume) (struct mtd_info *mtd);
 	void (*_reboot) (struct mtd_info *mtd);
@@ -402,6 +403,16 @@ int mtd_wunit_to_pairing_info(struct mtd_info *mtd, int wunit,
 int mtd_pairing_info_to_wunit(struct mtd_info *mtd,
 			      const struct mtd_pairing_info *info);
 int mtd_pairing_groups(struct mtd_info *mtd);
+
+static inline int mtd_max_bad_blocks(struct mtd_info *mtd,
+				     loff_t ofs, size_t len)
+{
+	if (mtd->_max_bad_blocks)
+		return mtd->_max_bad_blocks(mtd, ofs, len);
+
+	return -ENOTSUPP;
+}
+
 int mtd_erase(struct mtd_info *mtd, struct erase_info *instr);
 int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
 	      void **virt, resource_size_t *phys);
-- 
2.7.4



From zach.brown at ni.com  Fri Oct 28 13:27:39 2016
From: zach.brown at ni.com (Zach Brown)
Date: Fri, 28 Oct 2016 15:27:39 -0500
Subject: [PATCH v3 0/5] mtd: use ONFI bad blocks per LUN to calculate UBI bad
 PEB limit
Message-ID: <1477686464-7437-1-git-send-email-zach.brown@ni.com>

For ONFI-compliant NAND devices, the ONFI parameters report the maximum number
of bad blocks per LUN that will be encountered over the lifetime of the device,
so we can use that information to get a more accurate (and smaller) value for
the UBI bad PEB limit.

The ONFI parameter "maxiumum number of bad blocks per LUN" is the max number of
bad blocks that each individual LUN will ever ecounter. It is not the number of
bad blocks to reserve for the nand device per LUN in the device.

This means that in the worst case a UBI device spanning X LUNs will encounter
"maximum number of bad blocks per LUN" * X bad blocks. The implementation in
this patch assumes this worst case and allocates bad block accordingly.

These patches are ordered in terms of their dependencies, but ideally, all 5
would need to be applied for this to work as intended.

v1:
 * Changed commit message to address concerns from v1[1] about this patch set
   making best case assumptions.
v2:
 * Provided helper function for _max_bad_blocks
 * Two new patches
 * First new patch adds bb_per_lun and blocks_per_lun to nand_chip struct
 * Second new patch sets the new fields during nand_flash_detect_onfi
 * Max bad blocks calculation now uses the new nand_chip fields

[1]
http://lkml.iu.edu/hypermail/linux/kernel/1505.1/04822.html

Jeff Westfahl (2):
  mtd: introduce function max_bad_blocks
  mtd: ubi: use 'max_bad_blocks' to compute bad_peb_limit if available

Zach Brown (3):
  mtd: nand: Add bb_per_lun and blocks_per_lun fields to nand_chip
  mtd: nand: implement 'max_bad_blocks' mtd function
  mtd: nand: set bb_per_lun and blocks_per_lun for ONFI compliant chips

 drivers/mtd/mtdpart.c        | 13 +++++++++++++
 drivers/mtd/nand/nand_base.c | 40 ++++++++++++++++++++++++++++++++++++++++
 drivers/mtd/ubi/build.c      |  4 ++++
 include/linux/mtd/mtd.h      | 11 +++++++++++
 include/linux/mtd/nand.h     |  5 +++++
 5 files changed, 73 insertions(+)

-- 
2.7.4



From zach.brown at ni.com  Fri Oct 28 13:27:42 2016
From: zach.brown at ni.com (Zach Brown)
Date: Fri, 28 Oct 2016 15:27:42 -0500
Subject: [PATCH v3 3/5] mtd: nand: Add bb_per_lun and blocks_per_lun fields to
 nand_chip
In-Reply-To: <1477686464-7437-1-git-send-email-zach.brown@ni.com>
References: <1477686464-7437-1-git-send-email-zach.brown@ni.com>
Message-ID: <1477686464-7437-4-git-send-email-zach.brown@ni.com>

The fields bb_per_lun and blocks_per_lun are useful determining the
number of bad blocks a MTD needs to allocate. How they are set will
depend on if the chip is ONFI, JEDEC or a fuill-id entry in the nand_ids
table.

Signed-off-by: Zach Brown <zach.brown at ni.com>
---
 include/linux/mtd/nand.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index c5d3d502..efbe439 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -771,6 +771,9 @@ nand_get_sdr_timings(const struct nand_data_interface *conf)
  *			supported, 0 otherwise.
  * @jedec_params:	[INTERN] holds the JEDEC parameter page when JEDEC is
  *			supported, 0 otherwise.
+ * @bb_per_lun:	[INTERN] the max number of bad blocks each LUN of a
+ *			this nand device will encounter their life times.
+ * @blocks_per_lun:	[INTERN] The number of PEBs in a LUN
  * @read_retries:	[INTERN] the number of read retry modes supported
  * @onfi_set_features:	[REPLACEABLE] set the features for ONFI nand
  * @onfi_get_features:	[REPLACEABLE] get the features for ONFI nand
@@ -853,6 +856,8 @@ struct nand_chip {
 		struct nand_onfi_params	onfi_params;
 		struct nand_jedec_params jedec_params;
 	};
+	__le16 bb_per_lun;
+	__le32 blocks_per_lun;
 
 	struct nand_data_interface *data_interface;
 
-- 
2.7.4



From zach.brown at ni.com  Fri Oct 28 13:27:43 2016
From: zach.brown at ni.com (Zach Brown)
Date: Fri, 28 Oct 2016 15:27:43 -0500
Subject: [PATCH v3 4/5] mtd: nand: implement 'max_bad_blocks' mtd function
In-Reply-To: <1477686464-7437-1-git-send-email-zach.brown@ni.com>
References: <1477686464-7437-1-git-send-email-zach.brown@ni.com>
Message-ID: <1477686464-7437-5-git-send-email-zach.brown@ni.com>

Implement the new mtd function 'max_bad_blocks'. Using the chip's
bb_per_lun and blocks_per_lun fields to determine the maximum bad blocks
to reserve for an MTD.

Signed-off-by: Jeff Westfahl <jeff.westfahl at ni.com>
Signed-off-by: Zach Brown <zach.brown at ni.com>
---
 drivers/mtd/nand/nand_base.c | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index e5718e5..ed8dc89 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -3226,6 +3226,40 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
 }
 
 /**
+ * nand_max_bad_blocks - [MTD Interface] Max number of bad blocks for an mtd
+ * @mtd: MTD device structure
+ * @ofs: offset relative to mtd start
+ * @len: length of mtd
+ */
+static int nand_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	uint32_t part_start_block;
+	uint32_t part_end_block;
+	uint32_t part_start_lun;
+	uint32_t part_end_lun;
+
+	/* bb_per_lun and blocks_per_lun used to determine
+	 * the maximum bad block count.
+	 */
+	if (!chip->bb_per_lun || !chip->blocks_per_lun)
+		return -ENOTSUPP;
+
+	/* Get the start and end of the partition in erase blocks. */
+	part_start_block = mtd_div_by_eb(ofs, mtd);
+	part_end_block = mtd_div_by_eb(len, mtd) + part_start_block - 1;
+
+	/* Get the start and end LUNs of the partition. */
+	part_start_lun = part_start_block / chip->blocks_per_lun;
+	part_end_lun = part_end_block / chip->blocks_per_lun;
+
+	/* Look up the bad blocks per unit and multiply by the number of units
+	 * that the partition spans.
+	 */
+	return chip->bb_per_lun * (part_end_lun - part_start_lun + 1);
+}
+
+/**
  * nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand
  * @mtd: MTD device structure
  * @chip: nand chip info structure
@@ -4743,6 +4777,7 @@ int nand_scan_tail(struct mtd_info *mtd)
 	mtd->_block_isreserved = nand_block_isreserved;
 	mtd->_block_isbad = nand_block_isbad;
 	mtd->_block_markbad = nand_block_markbad;
+	mtd->_max_bad_blocks = nand_max_bad_blocks;
 	mtd->writebufsize = mtd->writesize;
 
 	/*
-- 
2.7.4



From marex at denx.de  Fri Oct 28 13:25:34 2016
From: marex at denx.de (Marek Vasut)
Date: Fri, 28 Oct 2016 22:25:34 +0200
Subject: [PULL v2] mtd: nand: Fixes for 4.9-rc3
In-Reply-To: <20161028102649.7b90e308@bbrezillon>
References: <20161028102649.7b90e308@bbrezillon>
Message-ID: <f88ccae7-58f2-d86d-200a-0cf8cf642cc7@denx.de>

On 10/28/2016 10:26 AM, Boris Brezillon wrote:
> Hi Brian,

Hi,

> Here is the PR I was mentioning yesterday.
> As usual, let me know if you find something weird in this PR, and I'll
> fix it.
> 
> Thanks,
> 
> Boris
> 
> The following changes since commit 07d9a380680d1c0eb51ef87ff2eab5c994949e69:
> 
>   Linux 4.9-rc2 (2016-10-23 17:10:14 -0700)
> 
> are available in the git repository at:
> 
>   git at github.com:linux-nand/linux.git tags/nand/fixes-for-4.9-rc3
> 
> for you to fetch changes up to 8ff0513bdcdd71e84aa561cce216675d43fb41b8:
> 
>   mtd: mtk: avoid warning in mtk_ecc_encode (2016-10-28 10:21:23 +0200)
> 
> ----------------------------------------------------------------
> Three simple fixes:
> 
> - the first one is fixing a non-critical bug in the gpmi driver
> - the second one is fixing a bug in the 'automatic NAND timings
>   selection' feature introduced in 4.9-rc1
> - the last one is fixing a false positive uninitialized-var warning
> 
> ----------------------------------------------------------------
> Arnd Bergmann (1):
>       mtd: mtk: avoid warning in mtk_ecc_encode
> 
> Boris Brezillon (1):
>       mtd: nand: Fix data interface configuration logic
> 
> Fabio Estevam (1):
>       mtd: nand: gpmi: disable the clocks on errors
> 
>  drivers/mtd/nand/gpmi-nand/gpmi-lib.c |  6 ++++--
>  drivers/mtd/nand/mtk_ecc.c            | 19 +++++++++----------
>  drivers/mtd/nand/nand_base.c          | 60 ++++++++++++++++++++++++++++++++++++++++++------------------
>  include/linux/mtd/nand.h              |  2 +-
>  4 files changed, 56 insertions(+), 31 deletions(-)
> 

I saw all those patches, so:

Acked-by: Marek Vasut <marex at denx.de>

-- 
Best regards,
Marek Vasut


From joerg.krause at embedded.rocks  Fri Oct 28 15:23:15 2016
From: joerg.krause at embedded.rocks (=?ISO-8859-1?Q?J=F6rg?= Krause)
Date: Sat, 29 Oct 2016 00:23:15 +0200
Subject: [PATCH] ubifs: Fix regression in ubifs_readdir()
In-Reply-To: <c542e099-0404-be8e-ebeb-d4265d3204d6@nod.at>
References: <1477648432-9543-1-git-send-email-richard@nod.at>
 <1477671544.8927.1.camel@embedded.rocks>
 <c542e099-0404-be8e-ebeb-d4265d3204d6@nod.at>
Message-ID: <1477693395.31471.1.camel@embedded.rocks>

Richard,

On Fri, 2016-10-28 at 19:07 +0200, Richard Weinberger wrote:
> J?rg,
> 
> On 28.10.2016 18:19, J?rg Krause wrote:
> > Hi,
> > 
> > On Fri, 2016-10-28 at 11:53 +0200, Richard Weinberger wrote:
> > > Commit c83ed4c9dbb35 ("ubifs: Abort readdir upon error") broke
> > > overlayfs support because the fix exposed an internal error
> > > code to VFS.
> > > 
> > > Reported-by: Peter Rosin <peda at axentia.se>
> > > Tested-by: Peter Rosin <peda at axentia.se>
> > > Reported-by: Ralph Sennhauser <ralph.sennhauser at gmail.com>
> > > Fixes: c83ed4c9dbb35 ("ubifs: Abort readdir upon error")
> > > Cc: stable at vger.kernel.org
> > > Signed-off-by: Richard Weinberger <richard at nod.at>
> > > ---
> > > ?fs/ubifs/dir.c | 8 ++++++++
> > > ?1 file changed, 8 insertions(+)
> > > 
> > > diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
> > > index bd4a5e8ce441..ca16c5d7bab1 100644
> > > --- a/fs/ubifs/dir.c
> > > +++ b/fs/ubifs/dir.c
> > > @@ -543,6 +543,14 @@ static int ubifs_readdir(struct file *file,
> > > struct dir_context *ctx)
> > > ?
> > > ?	if (err != -ENOENT)
> > > ?		ubifs_err(c, "cannot find next direntry, error
> > > %d",
> > > err);
> > > +	else
> > > +		/*
> > > +		?* -ENOENT is a non-fatal error in this context,
> > > the
> > > TNC uses
> > > +		?* it to indicate that the cursor moved past the
> > > current directory
> > > +		?* and readdir() has to stop.
> > > +		?*/
> > > +		err = 0;
> > > +
> > > ?
> > > ?	/* 2 is a special value indicating that there are no
> > > more
> > > direntries */
> > > ?	ctx->pos = 2;
> > 
> > I'm not sure if it's related to the issue reported by Peter Rosin
> > and
> > Ralph Sennhauser, but I am still getting a kernel panic using UBIFS
> > with OverlayFS on Linux v4.9.0-rc2 with this patch applied:
> 
> Does reverting c83ed4c9dbb35 help?
> And are you 100% sure you applied the fix?

I double double checked. The fix was applied on the git tree, but the
compiler cache (I am using Buildroot with this option enabled) fooled
me by using an old copy. After disabling the compiler cache I got a
fixed build of the kernel. The panic is gone! Thanks!

> 
> Does the following WARN_ON() trigger?
> diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
> index ca16c5d7bab1..12ffc91f7ef8 100644
> --- a/fs/ubifs/dir.c
> +++ b/fs/ubifs/dir.c
> @@ -554,6 +554,9 @@ static int ubifs_readdir(struct file *file,
> struct dir_context *ctx)
> 
> ?	/* 2 is a special value indicating that there are no more
> direntries */
> ?	ctx->pos = 2;
> +
> +	WARN_ON(err);
> +
> ?	return err;
> ?}

Best regards,
J?rg Krause


From computersforpeace at gmail.com  Fri Oct 28 19:50:27 2016
From: computersforpeace at gmail.com (Brian Norris)
Date: Fri, 28 Oct 2016 19:50:27 -0700
Subject: [PULL v2] mtd: nand: Fixes for 4.9-rc3
In-Reply-To: <f88ccae7-58f2-d86d-200a-0cf8cf642cc7@denx.de>
References: <20161028102649.7b90e308@bbrezillon>
 <f88ccae7-58f2-d86d-200a-0cf8cf642cc7@denx.de>
Message-ID: <20161029025027.GA124299@google.com>

Hi Boris and Marek,

On Fri, Oct 28, 2016 at 10:25:34PM +0200, Marek Vasut wrote:
> On 10/28/2016 10:26 AM, Boris Brezillon wrote:
> > Here is the PR I was mentioning yesterday.
> > As usual, let me know if you find something weird in this PR, and I'll
> > fix it.
> > 
> > Thanks,
> > 
> > Boris
> > 
> > The following changes since commit 07d9a380680d1c0eb51ef87ff2eab5c994949e69:
> > 
> >   Linux 4.9-rc2 (2016-10-23 17:10:14 -0700)
> > 
> > are available in the git repository at:
> > 
> >   git at github.com:linux-nand/linux.git tags/nand/fixes-for-4.9-rc3
> > 
> > for you to fetch changes up to 8ff0513bdcdd71e84aa561cce216675d43fb41b8:
> > 
> >   mtd: mtk: avoid warning in mtk_ecc_encode (2016-10-28 10:21:23 +0200)
> > 
> > ----------------------------------------------------------------
> > Three simple fixes:
> > 
> > - the first one is fixing a non-critical bug in the gpmi driver
> > - the second one is fixing a bug in the 'automatic NAND timings
> >   selection' feature introduced in 4.9-rc1
> > - the last one is fixing a false positive uninitialized-var warning
> > 
> > ----------------------------------------------------------------
> > Arnd Bergmann (1):
> >       mtd: mtk: avoid warning in mtk_ecc_encode
> > 
> > Boris Brezillon (1):
> >       mtd: nand: Fix data interface configuration logic
> > 
> > Fabio Estevam (1):
> >       mtd: nand: gpmi: disable the clocks on errors
> > 
> >  drivers/mtd/nand/gpmi-nand/gpmi-lib.c |  6 ++++--
> >  drivers/mtd/nand/mtk_ecc.c            | 19 +++++++++----------
> >  drivers/mtd/nand/nand_base.c          | 60 ++++++++++++++++++++++++++++++++++++++++++------------------
> >  include/linux/mtd/nand.h              |  2 +-
> >  4 files changed, 56 insertions(+), 31 deletions(-)

Looks good, thanks.

> I saw all those patches, so:
> 
> Acked-by: Marek Vasut <marex at denx.de>

Thanks!

Pulled into linux-mtd.git.

Brian


From richard at nod.at  Sat Oct 29 02:04:18 2016
From: richard at nod.at (Richard Weinberger)
Date: Sat, 29 Oct 2016 11:04:18 +0200
Subject: [PATCH] ubifs: Fix regression in ubifs_readdir()
In-Reply-To: <1477693395.31471.1.camel@embedded.rocks>
References: <1477648432-9543-1-git-send-email-richard@nod.at>
 <1477671544.8927.1.camel@embedded.rocks>
 <c542e099-0404-be8e-ebeb-d4265d3204d6@nod.at>
 <1477693395.31471.1.camel@embedded.rocks>
Message-ID: <0e2d577d-aa17-2b83-3e6c-4de950d2d02d@nod.at>

On 29.10.2016 00:23, J?rg Krause wrote:
>> Does reverting c83ed4c9dbb35 help?
>> And are you 100% sure you applied the fix?
> 
> I double double checked. The fix was applied on the git tree, but the
> compiler cache (I am using Buildroot with this option enabled) fooled
> me by using an old copy. After disabling the compiler cache I got a
> fixed build of the kernel. The panic is gone! Thanks!

Thanks for letting me know.
Let's get this fix into -rc3 then. :-)

Thanks,
//richard


From marek.vasut at gmail.com  Sat Oct 29 10:54:40 2016
From: marek.vasut at gmail.com (Marek Vasut)
Date: Sat, 29 Oct 2016 19:54:40 +0200
Subject: [PATCH RESEND v3] mtd: spi-nor: fix flags for s25fl128s
In-Reply-To: <514b12c9-447b-1688-29d3-aac839de08ac@gmail.com>
References: <4d3db993-d030-3659-2f62-94c373f57038@gmail.com>
 <808bf727-f562-79d4-a60f-5e437cc15da6@gmail.com>
 <514b12c9-447b-1688-29d3-aac839de08ac@gmail.com>
Message-ID: <5d633567-ca28-abe6-2789-ba9291e4eaf1@gmail.com>

On 10/27/2016 11:13 PM, Heiner Kallweit wrote:
> The Spansion S25FL128S also supports dual read mode.
> In addition remove flag SECT_4K. 4K erases are supported,
> but not uniformly.
> 
> Signed-off-by: Heiner Kallweit <hkallweit1 at gmail.com>
> Reviewed-by: Jagan Teki <jteki at openedev.com>

Acked-by: Marek Vasut <marek.vasut at gmail.com>

-- 
Best regards,
Marek Vasut


From marek.vasut at gmail.com  Sat Oct 29 10:59:09 2016
From: marek.vasut at gmail.com (Marek Vasut)
Date: Sat, 29 Oct 2016 19:59:09 +0200
Subject: [PATCH v2] mtd: m25p80: consider max message size in m25p80_read
In-Reply-To: <0e38d1ed-af5c-160f-e02a-f1433c507d23@gmail.com>
References: <6c95366c-7fcc-ef4c-033a-f9f6e152a669@gmail.com>
 <20160816164204.GV9347@sirena.org.uk>
 <b65240ff-7e28-5ecb-0670-abfca871246b@gmail.com>
 <a5aad691-fb3b-39a5-943e-43068df74c44@gmail.com>
 <e2e4ecfe-b888-f335-57f6-634f5c818252@gmail.com>
 <0e38d1ed-af5c-160f-e02a-f1433c507d23@gmail.com>
Message-ID: <6f1aed1e-9467-aa94-56cb-5e9435b21ae4@gmail.com>

On 10/28/2016 07:58 AM, Heiner Kallweit wrote:
> Consider a message size limit when calculating the maximum amount
> of data that can be read.
> 
> The message size limit has been introduced with 4.9, so cc it
> to stable.
> 
> Signed-off-by: Heiner Kallweit <hkallweit1 at gmail.com>
> Cc: <stable at vger.kernel.org> # 4.9.x
> ---
> v2:
> - This patch was part of a series and the other patches of the
>   series went into 4.9. It's needed to correctly support
>   reads > 64k on fsl-espi as first user of spi_max_message_size.
>   See commit 02a595d5d6e4 ("spi: fsl-espi: eliminate spi nor
>   flash read loop"). CC it to stable.  

Does this imply that we have to fix every single driver this way ?

> ---
>  drivers/mtd/devices/m25p80.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
> index 9cf7fcd..16a7df2 100644
> --- a/drivers/mtd/devices/m25p80.c
> +++ b/drivers/mtd/devices/m25p80.c
> @@ -172,7 +172,8 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
>  
>  	t[1].rx_buf = buf;
>  	t[1].rx_nbits = m25p80_rx_nbits(nor);
> -	t[1].len = min(len, spi_max_transfer_size(spi));
> +	t[1].len = min3(len, spi_max_transfer_size(spi),
> +			spi_max_message_size(spi) - t[0].len);
>  	spi_message_add_tail(&t[1], &m);
>  
>  	ret = spi_sync(spi, &m);
> 


-- 
Best regards,
Marek Vasut


From marek.vasut at gmail.com  Sat Oct 29 10:56:39 2016
From: marek.vasut at gmail.com (Marek Vasut)
Date: Sat, 29 Oct 2016 19:56:39 +0200
Subject: [PATCH] mtd: nand: pxa3xx_nand: write exactly one message on
 probe failure
In-Reply-To: <20161028100419.1ba04968@bbrezillon>
References: <1474276878-1021-1-git-send-email-u.kleine-koenig@pengutronix.de>
 <20161028100419.1ba04968@bbrezillon>
Message-ID: <ac811aeb-1f9d-e985-134b-8faba0a1a4cf@gmail.com>

On 10/28/2016 10:04 AM, Boris Brezillon wrote:
> On Mon, 19 Sep 2016 11:21:18 +0200
> Uwe Kleine-K?nig <u.kleine-koenig at pengutronix.de> wrote:
> 
>> For some error paths alloc_nand_resource() emitted an error message, for
>> others it didn't. Make it consistently print a message including the
>> error code where it's not constant and drop the hardly helpful
>> additional message printed by the caller of alloc_nand_resource.
>>
>> Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig at pengutronix.de>
> 
> It looks good to me. Ezequiel, Robert, any objection to this patch? If
> not, can I have your Acked/Reviewed-by ?
> 
>> ---
>>  drivers/mtd/nand/pxa3xx_nand.c | 17 ++++++++++-------
>>  1 file changed, 10 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
>> index 436dd6dc11f4..052e9725cf12 100644
>> --- a/drivers/mtd/nand/pxa3xx_nand.c
>> +++ b/drivers/mtd/nand/pxa3xx_nand.c
>> @@ -1774,8 +1774,11 @@ static int alloc_nand_resource(struct platform_device *pdev)
>>  	int ret, irq, cs;
>>  
>>  	pdata = dev_get_platdata(&pdev->dev);
>> -	if (pdata->num_cs <= 0)
>> +	if (pdata->num_cs <= 0) {
>> +		dev_err(&pdev->dev, "broken number of chip selects\n");

Not: Should be "invalid number of chip selects" . Also, if you turn the
num_cs to unsigned type in the platdata, the test can be if (foo == 0)
instead.

>>  		return -ENODEV;
>> +	}
>> +
>>  	info = devm_kzalloc(&pdev->dev,
>>  			    sizeof(*info) + sizeof(*host) * pdata->num_cs,
>>  			    GFP_KERNEL);
>> @@ -1814,8 +1817,9 @@ static int alloc_nand_resource(struct platform_device *pdev)
>>  	init_waitqueue_head(&chip->controller->wq);
>>  	info->clk = devm_clk_get(&pdev->dev, NULL);
>>  	if (IS_ERR(info->clk)) {
>> -		dev_err(&pdev->dev, "failed to get nand clock\n");
>> -		return PTR_ERR(info->clk);
>> +		ret = PTR_ERR(info->clk);
>> +		dev_err(&pdev->dev, "failed to get nand clock (%d)\n", ret);
>> +		return ret;
>>  	}
>>  	ret = clk_prepare_enable(info->clk);
>>  	if (ret < 0)
>> @@ -1843,6 +1847,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
>>  	info->mmio_base = devm_ioremap_resource(&pdev->dev, r);
>>  	if (IS_ERR(info->mmio_base)) {
>>  		ret = PTR_ERR(info->mmio_base);
>> +		dev_err(&pdev->dev, "failed to map register space (%d)\n", ret);
>>  		goto fail_disable_clk;
>>  	}
>>  	info->mmio_phys = r->start;
>> @@ -1862,7 +1867,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
>>  				   pxa3xx_nand_irq_thread, IRQF_ONESHOT,
>>  				   pdev->name, info);
>>  	if (ret < 0) {
>> -		dev_err(&pdev->dev, "failed to request IRQ\n");
>> +		dev_err(&pdev->dev, "failed to request IRQ (%d)\n", ret);
>>  		goto fail_free_buf;
>>  	}
>>  
>> @@ -1961,10 +1966,8 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
>>  	}
>>  
>>  	ret = alloc_nand_resource(pdev);
>> -	if (ret) {
>> -		dev_err(&pdev->dev, "alloc nand resource failed\n");
>> +	if (ret)
>>  		return ret;
>> -	}
>>  
>>  	info = platform_get_drvdata(pdev);
>>  	probe_success = 0;
> 
> 
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/
> 


-- 
Best regards,
Marek Vasut


From broonie at kernel.org  Sat Oct 29 11:09:08 2016
From: broonie at kernel.org (Mark Brown)
Date: Sat, 29 Oct 2016 12:09:08 -0600
Subject: [PATCH v2] mtd: m25p80: consider max message size in m25p80_read
In-Reply-To: <6f1aed1e-9467-aa94-56cb-5e9435b21ae4@gmail.com>
References: <6c95366c-7fcc-ef4c-033a-f9f6e152a669@gmail.com>
 <20160816164204.GV9347@sirena.org.uk>
 <b65240ff-7e28-5ecb-0670-abfca871246b@gmail.com>
 <a5aad691-fb3b-39a5-943e-43068df74c44@gmail.com>
 <e2e4ecfe-b888-f335-57f6-634f5c818252@gmail.com>
 <0e38d1ed-af5c-160f-e02a-f1433c507d23@gmail.com>
 <6f1aed1e-9467-aa94-56cb-5e9435b21ae4@gmail.com>
Message-ID: <20161029180908.txwr5tgr3ixux6gy@sirena.org.uk>

On Sat, Oct 29, 2016 at 07:59:09PM +0200, Marek Vasut wrote:
> On 10/28/2016 07:58 AM, Heiner Kallweit wrote:

> > - This patch was part of a series and the other patches of the
> >   series went into 4.9. It's needed to correctly support
> >   reads > 64k on fsl-espi as first user of spi_max_message_size.
> >   See commit 02a595d5d6e4 ("spi: fsl-espi: eliminate spi nor
> >   flash read loop"). CC it to stable.  

> Does this imply that we have to fix every single driver this way ?

Ideally.  Any SPI driver that has an upper limit really ought to export
it, and any driver that might bump into one of those limits should
check.  A lot of drivers are either unlikely to be deployed in a system
that has relevant limits or tend to only do short enough transfers
though - if systems are currently working it's just neatening things up
really.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 455 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20161029/5c38741d/attachment.sig>

From richard at nod.at  Sat Oct 29 12:07:15 2016
From: richard at nod.at (Richard Weinberger)
Date: Sat, 29 Oct 2016 21:07:15 +0200
Subject: [GIT PULL] UBI/UBIFS fixes for 4.9-rc3
Message-ID: <f0db8192-0b26-dfc3-95a9-395616c8d848@nod.at>

Linus,

The following changes since commit 14970f204b1993af7459d5bd34aaff38dfee6670:

  Merge branch 'akpm' (patches from Andrew) (2016-10-27 19:58:39 -0700)

are available in the git repository at:

  git://git.infradead.org/linux-ubifs.git tags/upstream-4.9-rc3

for you to fetch changes up to a00052a296e54205cf238c75bd98d17d5d02a6db:

  ubifs: Fix regression in ubifs_readdir() (2016-10-28 14:48:31 +0200)

----------------------------------------------------------------
This pull request contains fixes for issues in both UBI and UBIFS:
- A regression wrt. overlayfs, introduced in -rc2.
- An UBI issue, found by Dan Carpenter's static checker.

----------------------------------------------------------------
Boris Brezillon (1):
      ubi: fastmap: Fix add_vol() return value test in ubi_attach_fastmap()

Richard Weinberger (1):
      ubifs: Fix regression in ubifs_readdir()

 drivers/mtd/ubi/fastmap.c | 10 +++++-----
 fs/ubifs/dir.c            |  8 ++++++++
 2 files changed, 13 insertions(+), 5 deletions(-)


From boris.brezillon at free-electrons.com  Sat Oct 29 12:07:30 2016
From: boris.brezillon at free-electrons.com (Boris Brezillon)
Date: Sat, 29 Oct 2016 21:07:30 +0200
Subject: [PATCH] mtd: nand: pxa3xx_nand: write exactly one message on
 probe failure
In-Reply-To: <ac811aeb-1f9d-e985-134b-8faba0a1a4cf@gmail.com>
References: <1474276878-1021-1-git-send-email-u.kleine-koenig@pengutronix.de>
 <20161028100419.1ba04968@bbrezillon>
 <ac811aeb-1f9d-e985-134b-8faba0a1a4cf@gmail.com>
Message-ID: <20161029210730.7bb0b4fb@bbrezillon>

On Sat, 29 Oct 2016 19:56:39 +0200
Marek Vasut <marek.vasut at gmail.com> wrote:

> On 10/28/2016 10:04 AM, Boris Brezillon wrote:
> > On Mon, 19 Sep 2016 11:21:18 +0200
> > Uwe Kleine-K?nig <u.kleine-koenig at pengutronix.de> wrote:
> >   
> >> For some error paths alloc_nand_resource() emitted an error message, for
> >> others it didn't. Make it consistently print a message including the
> >> error code where it's not constant and drop the hardly helpful
> >> additional message printed by the caller of alloc_nand_resource.
> >>
> >> Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig at pengutronix.de>  
> > 
> > It looks good to me. Ezequiel, Robert, any objection to this patch? If
> > not, can I have your Acked/Reviewed-by ?
> >   
> >> ---
> >>  drivers/mtd/nand/pxa3xx_nand.c | 17 ++++++++++-------
> >>  1 file changed, 10 insertions(+), 7 deletions(-)
> >>
> >> diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> >> index 436dd6dc11f4..052e9725cf12 100644
> >> --- a/drivers/mtd/nand/pxa3xx_nand.c
> >> +++ b/drivers/mtd/nand/pxa3xx_nand.c
> >> @@ -1774,8 +1774,11 @@ static int alloc_nand_resource(struct platform_device *pdev)
> >>  	int ret, irq, cs;
> >>  
> >>  	pdata = dev_get_platdata(&pdev->dev);
> >> -	if (pdata->num_cs <= 0)
> >> +	if (pdata->num_cs <= 0) {
> >> +		dev_err(&pdev->dev, "broken number of chip selects\n");  
> 
> Not: Should be "invalid number of chip selects" .

Correct. I can fix that when applying.

> Also, if you turn the
> num_cs to unsigned type in the platdata, the test can be if (foo == 0)
> instead.

If we really want to turn num_cs into an unsigned int, then it should
be done in different patch, but honestly, that's not the first thing I
would rework in this driver ;-).

> 
> >>  		return -ENODEV;
> >> +	}
> >> +
> >>  	info = devm_kzalloc(&pdev->dev,
> >>  			    sizeof(*info) + sizeof(*host) * pdata->num_cs,
> >>  			    GFP_KERNEL);
> >> @@ -1814,8 +1817,9 @@ static int alloc_nand_resource(struct platform_device *pdev)
> >>  	init_waitqueue_head(&chip->controller->wq);
> >>  	info->clk = devm_clk_get(&pdev->dev, NULL);
> >>  	if (IS_ERR(info->clk)) {
> >> -		dev_err(&pdev->dev, "failed to get nand clock\n");
> >> -		return PTR_ERR(info->clk);
> >> +		ret = PTR_ERR(info->clk);
> >> +		dev_err(&pdev->dev, "failed to get nand clock (%d)\n", ret);
> >> +		return ret;
> >>  	}
> >>  	ret = clk_prepare_enable(info->clk);
> >>  	if (ret < 0)
> >> @@ -1843,6 +1847,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
> >>  	info->mmio_base = devm_ioremap_resource(&pdev->dev, r);
> >>  	if (IS_ERR(info->mmio_base)) {
> >>  		ret = PTR_ERR(info->mmio_base);
> >> +		dev_err(&pdev->dev, "failed to map register space (%d)\n", ret);
> >>  		goto fail_disable_clk;
> >>  	}
> >>  	info->mmio_phys = r->start;
> >> @@ -1862,7 +1867,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
> >>  				   pxa3xx_nand_irq_thread, IRQF_ONESHOT,
> >>  				   pdev->name, info);
> >>  	if (ret < 0) {
> >> -		dev_err(&pdev->dev, "failed to request IRQ\n");
> >> +		dev_err(&pdev->dev, "failed to request IRQ (%d)\n", ret);
> >>  		goto fail_free_buf;
> >>  	}
> >>  
> >> @@ -1961,10 +1966,8 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
> >>  	}
> >>  
> >>  	ret = alloc_nand_resource(pdev);
> >> -	if (ret) {
> >> -		dev_err(&pdev->dev, "alloc nand resource failed\n");
> >> +	if (ret)
> >>  		return ret;
> >> -	}
> >>  
> >>  	info = platform_get_drvdata(pdev);
> >>  	probe_success = 0;  
> > 
> > 
> > ______________________________________________________
> > Linux MTD discussion mailing list
> > http://lists.infradead.org/mailman/listinfo/linux-mtd/
> >   
> 
> 



From robert.jarzmik at free.fr  Sat Oct 29 12:59:18 2016
From: robert.jarzmik at free.fr (Robert Jarzmik)
Date: Sat, 29 Oct 2016 21:59:18 +0200
Subject: [PATCH] mtd: nand: pxa3xx_nand: write exactly one message on
 probe failure
In-Reply-To: <ac811aeb-1f9d-e985-134b-8faba0a1a4cf@gmail.com> (Marek Vasut's
 message of "Sat, 29 Oct 2016 19:56:39 +0200")
References: <1474276878-1021-1-git-send-email-u.kleine-koenig@pengutronix.de>
 <20161028100419.1ba04968@bbrezillon>
 <ac811aeb-1f9d-e985-134b-8faba0a1a4cf@gmail.com>
Message-ID: <87funf0vvt.fsf@belgarion.home>

Marek Vasut <marek.vasut at gmail.com> writes:

> On 10/28/2016 10:04 AM, Boris Brezillon wrote:
>> On Mon, 19 Sep 2016 11:21:18 +0200
>> Uwe Kleine-K?nig <u.kleine-koenig at pengutronix.de> wrote:
>> 
>>> For some error paths alloc_nand_resource() emitted an error message, for
>>> others it didn't. Make it consistently print a message including the
>>> error code where it's not constant and drop the hardly helpful
>>> additional message printed by the caller of alloc_nand_resource.
>>>
>>> Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig at pengutronix.de>
>> 
>> It looks good to me. Ezequiel, Robert, any objection to this patch? If
>> not, can I have your Acked/Reviewed-by ?
Hi,

Actually I was wondering if my mail system is utterly broken ... This is the
first mail I receive, while it seems to me I was in the recipients in the former
ones ...

You can take my Reviewed-by, at least from:
	https://patchwork.ozlabs.org/patch/671644/

As a side note, normally for pxa architecture we use a printk format to display
the return value as :
   pr_something("XXXX :%d\n", ret)

As pxa3xx_nand is shared with other architectures this will be Boris/Ezequiel's
call.

Cheers.

--
Robert


From hkallweit1 at gmail.com  Sun Oct 30 02:32:38 2016
From: hkallweit1 at gmail.com (Heiner Kallweit)
Date: Sun, 30 Oct 2016 10:32:38 +0100
Subject: [PATCH] mtd: spi-nor: add sleeping version of spi_nor_wait_till_ready
 for erase ops
Message-ID: <eaa526ca-f0b4-4fde-d334-2ca6af72c32d@gmail.com>

Currently spi_nor_wait_till_ready in the poll loop permanently checks
for the WIP flag to be reset. Erase ops typically take >100ms for
sector erase and >10s for chip erase. Permanently polling for such
longer time periods puts unnecessary load on the SPI subsystem
(especially on systems w/o SPI DMA support or systems using bitbanging).

Relax this by sleeping for a reasonable time between checking the
WIP flag.

Signed-off-by: Heiner Kallweit <hkallweit1 at gmail.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 27 +++++++++++++++++++++------
 1 file changed, 21 insertions(+), 6 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index d0fc165..808ea4c 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -17,6 +17,7 @@
 #include <linux/mutex.h>
 #include <linux/math64.h>
 #include <linux/sizes.h>
+#include <linux/delay.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/of_platform.h>
@@ -252,7 +253,8 @@ static int spi_nor_ready(struct spi_nor *nor)
  * Returns non-zero if error.
  */
 static int spi_nor_wait_till_ready_with_timeout(struct spi_nor *nor,
-						unsigned long timeout_jiffies)
+						unsigned long timeout_jiffies,
+						unsigned int sleep_msecs)
 {
 	unsigned long deadline;
 	int timeout = 0, ret;
@@ -269,7 +271,13 @@ static int spi_nor_wait_till_ready_with_timeout(struct spi_nor *nor,
 		if (ret)
 			return 0;
 
-		cond_resched();
+		if (!sleep_msecs)
+			cond_resched();
+		else if (sleep_msecs < 50)
+			usleep_range(sleep_msecs * 1000 - 100,
+				     sleep_msecs * 1000);
+		else
+			msleep(sleep_msecs);
 	}
 
 	dev_err(nor->dev, "flash operation timed out\n");
@@ -277,10 +285,17 @@ static int spi_nor_wait_till_ready_with_timeout(struct spi_nor *nor,
 	return -ETIMEDOUT;
 }
 
-static int spi_nor_wait_till_ready(struct spi_nor *nor)
+static inline int spi_nor_wait_till_ready_sleep(struct spi_nor *nor,
+						unsigned int sleep_msecs)
 {
 	return spi_nor_wait_till_ready_with_timeout(nor,
-						    DEFAULT_READY_WAIT_JIFFIES);
+						    DEFAULT_READY_WAIT_JIFFIES,
+						    sleep_msecs);
+}
+
+static inline int spi_nor_wait_till_ready(struct spi_nor *nor)
+{
+	return spi_nor_wait_till_ready_sleep(nor, 0);
 }
 
 /*
@@ -387,7 +402,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
 		timeout = max(CHIP_ERASE_2MB_READY_WAIT_JIFFIES,
 			      CHIP_ERASE_2MB_READY_WAIT_JIFFIES *
 			      (unsigned long)(mtd->size / SZ_2M));
-		ret = spi_nor_wait_till_ready_with_timeout(nor, timeout);
+		ret = spi_nor_wait_till_ready_with_timeout(nor, timeout, 100);
 		if (ret)
 			goto erase_err;
 
@@ -408,7 +423,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
 			addr += mtd->erasesize;
 			len -= mtd->erasesize;
 
-			ret = spi_nor_wait_till_ready(nor);
+			ret = spi_nor_wait_till_ready_sleep(nor, 2);
 			if (ret)
 				goto erase_err;
 		}
-- 
2.10.1



From robh at kernel.org  Sun Oct 30 19:45:26 2016
From: robh at kernel.org (Rob Herring)
Date: Sun, 30 Oct 2016 21:45:26 -0500
Subject: [PATCH v7 1/2] mtd: nand: add tango NFC dt bindings doc
In-Reply-To: <580F5B06.6030608@sigmadesigns.com>
References: <580F5AD2.9020909@sigmadesigns.com>
 <580F5B06.6030608@sigmadesigns.com>
Message-ID: <20161031024526.g3fadht2coqqu6a5@rob-hp-laptop>

On Tue, Oct 25, 2016 at 03:15:50PM +0200, Marc Gonzalez wrote:
> Add the tango NAND Flash Controller dt bindings documentation.
> 
> Signed-off-by: Marc Gonzalez <marc_gonzalez at sigmadesigns.com>
> ---
>  Documentation/devicetree/bindings/mtd/tango-nand.txt | 38 ++++++++++++++++++++++++++++++
>  1 file changed, 38 insertions(+)

Acked-by: Rob Herring <robh at kernel.org>


From cyrille.pitchen at atmel.com  Mon Oct 31 06:50:54 2016
From: cyrille.pitchen at atmel.com (Cyrille Pitchen)
Date: Mon, 31 Oct 2016 14:50:54 +0100
Subject: [PATCH] mtd: spi-nor: add sleeping version of
 spi_nor_wait_till_ready for erase ops
In-Reply-To: <eaa526ca-f0b4-4fde-d334-2ca6af72c32d@gmail.com>
References: <eaa526ca-f0b4-4fde-d334-2ca6af72c32d@gmail.com>
Message-ID: <716d2877-dc4f-f93d-5d93-cde671b89082@atmel.com>

Hi Heiner,

+Marek

Le 30/10/2016 ? 10:32, Heiner Kallweit a ?crit :
> Currently spi_nor_wait_till_ready in the poll loop permanently checks
> for the WIP flag to be reset. Erase ops typically take >100ms for
> sector erase and >10s for chip erase. Permanently polling for such
> longer time periods puts unnecessary load on the SPI subsystem
> (especially on systems w/o SPI DMA support or systems using bitbanging).
> 
> Relax this by sleeping for a reasonable time between checking the
> WIP flag.
> 
> Signed-off-by: Heiner Kallweit <hkallweit1 at gmail.com>
> ---
>  drivers/mtd/spi-nor/spi-nor.c | 27 +++++++++++++++++++++------
>  1 file changed, 21 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
> index d0fc165..808ea4c 100644
> --- a/drivers/mtd/spi-nor/spi-nor.c
> +++ b/drivers/mtd/spi-nor/spi-nor.c
> @@ -17,6 +17,7 @@
>  #include <linux/mutex.h>
>  #include <linux/math64.h>
>  #include <linux/sizes.h>
> +#include <linux/delay.h>
>  
>  #include <linux/mtd/mtd.h>
>  #include <linux/of_platform.h>
> @@ -252,7 +253,8 @@ static int spi_nor_ready(struct spi_nor *nor)
>   * Returns non-zero if error.
>   */
>  static int spi_nor_wait_till_ready_with_timeout(struct spi_nor *nor,
> -						unsigned long timeout_jiffies)
> +						unsigned long timeout_jiffies,
> +						unsigned int sleep_msecs)
>  {
>  	unsigned long deadline;
>  	int timeout = 0, ret;
> @@ -269,7 +271,13 @@ static int spi_nor_wait_till_ready_with_timeout(struct spi_nor *nor,
>  		if (ret)
>  			return 0;
>  
> -		cond_resched();
> +		if (!sleep_msecs)
> +			cond_resched();
> +		else if (sleep_msecs < 50)
> +			usleep_range(sleep_msecs * 1000 - 100,
> +				     sleep_msecs * 1000);
> +		else
> +			msleep(sleep_msecs);
>  	}
>  
>  	dev_err(nor->dev, "flash operation timed out\n");
> @@ -277,10 +285,17 @@ static int spi_nor_wait_till_ready_with_timeout(struct spi_nor *nor,
>  	return -ETIMEDOUT;
>  }
>  
> -static int spi_nor_wait_till_ready(struct spi_nor *nor)
> +static inline int spi_nor_wait_till_ready_sleep(struct spi_nor *nor,
> +						unsigned int sleep_msecs)
>  {
>  	return spi_nor_wait_till_ready_with_timeout(nor,
> -						    DEFAULT_READY_WAIT_JIFFIES);
> +						    DEFAULT_READY_WAIT_JIFFIES,
> +						    sleep_msecs);
> +}
> +
> +static inline int spi_nor_wait_till_ready(struct spi_nor *nor)
> +{
> +	return spi_nor_wait_till_ready_sleep(nor, 0);
>  }
>  

Not a big deal but, IMHO, you should remove spi_nor_wait_till_ready_sleep()
from your patch to avoid introducing a 3rd spi_nor_wait_till_ready* function,
so we don't have to wonder which version to call when we have to wait for the
memory to be ready again.

Besides, spi_nor_wait_ready_sleep() is called only once so it is not so
useful.

Finally, the duration expressed by the sleep_msecs parameter should not be
higher than the duration of timeout_jiffies in
spi_nor_wait_till_ready_with_timeout(). The spi_nor_wait_till_ready_sleep()
hides the timeout_jiffies value so it's less obvious to choose a right value
for sleep_msecs when you have to look at the implementation of the
spi_nor_wait_till_ready_sleep() function to find out the actual value of
timeout_jiffies.

What I mean is that those two parameters, timeout_jiffies and sleep_msec, are
tightly bound. So when calling one of the spi_nor_wait_till_ready* functions(),
those two parameters should be either both fixed (macro) or both variable.

Marek, what do you think about this point?

>  /*
> @@ -387,7 +402,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
>  		timeout = max(CHIP_ERASE_2MB_READY_WAIT_JIFFIES,
>  			      CHIP_ERASE_2MB_READY_WAIT_JIFFIES *
>  			      (unsigned long)(mtd->size / SZ_2M));
> -		ret = spi_nor_wait_till_ready_with_timeout(nor, timeout);
> +		ret = spi_nor_wait_till_ready_with_timeout(nor, timeout, 100);

Please, use macros instead of hardcoded values. For instance, here it could be
CHIP_ERASE_READY_WAIT_SLEEP_MSEC or something else which clearly states
that the value is for chip erase operations and is associated with the
CHIP_ERASE_2MB_READY_WAIT_JIFFIES macro.

>  		if (ret)
>  			goto erase_err;
>  
> @@ -408,7 +423,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
>  			addr += mtd->erasesize;
>  			len -= mtd->erasesize;
>  
> -			ret = spi_nor_wait_till_ready(nor);
> +			ret = spi_nor_wait_till_ready_sleep(nor, 2);
See comments above.

Do you have some figures to show the impact of this patch on the performances?
>  			if (ret)
>  				goto erase_err;
>  		}
> 

Best regards,

Cyrille


From jagan at openedev.com  Mon Oct 31 11:51:50 2016
From: jagan at openedev.com (Jagan Teki)
Date: Tue, 1 Nov 2016 00:21:50 +0530
Subject: [PATCH v3 2/9] mtd: spi-nor: add an alternative method to support
 memory >16MiB
In-Reply-To: <87ace1a307f4d9899a84108de999a2eeb151da1a.1477325128.git.cyrille.pitchen@atmel.com>
References: <cover.1477325128.git.cyrille.pitchen@atmel.com>
 <87ace1a307f4d9899a84108de999a2eeb151da1a.1477325128.git.cyrille.pitchen@atmel.com>
Message-ID: <CAD6G_RQvtJXMJecbDz=s=UOCiUC9q9f68zZsfu9m_i8AK5xcEw@mail.gmail.com>

Hi Cyrille,

On Mon, Oct 24, 2016 at 10:04 PM, Cyrille Pitchen
<cyrille.pitchen at atmel.com> wrote:
> This patch provides an alternative mean to support memory above 16MiB
> (128Mib) by replacing 3byte address op codes by their associated 4byte
> address versions.
>
> Using the dedicated 4byte address op codes doesn't change the internal
> state of the SPI NOR memory as opposed to using other means such as
> updating a Base Address Register (BAR) and sending command to enter/leave
> the 4byte mode.
>
> Hence when a CPU reset occurs, early bootloaders don't need to be aware
> of BAR value or 4byte mode being enabled: they can still access the first
> 16MiB of the SPI NOR memory using the regular 3byte address op codes.
>
> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
> Tested-by: Vignesh R <vigneshr at ti.com>
> ---
>  drivers/mtd/devices/serial_flash_cmds.h |   7 ---
>  drivers/mtd/devices/st_spi_fsm.c        |  28 ++++-----
>  drivers/mtd/spi-nor/spi-nor.c           | 104 +++++++++++++++++++++++++-------
>  include/linux/mtd/spi-nor.h             |  22 +++++--
>  4 files changed, 113 insertions(+), 48 deletions(-)
>
> diff --git a/drivers/mtd/devices/serial_flash_cmds.h b/drivers/mtd/devices/serial_flash_cmds.h
> index f59a125295d0..8b81e15105dd 100644
> --- a/drivers/mtd/devices/serial_flash_cmds.h
> +++ b/drivers/mtd/devices/serial_flash_cmds.h
> @@ -18,19 +18,12 @@
>  #define SPINOR_OP_RDVCR                0x85
>
>  /* JEDEC Standard - Serial Flash Discoverable Parmeters (SFDP) Commands */
> -#define SPINOR_OP_READ_1_2_2   0xbb    /* DUAL I/O READ */
> -#define SPINOR_OP_READ_1_4_4   0xeb    /* QUAD I/O READ */
> -
>  #define SPINOR_OP_WRITE                0x02    /* PAGE PROGRAM */
>  #define SPINOR_OP_WRITE_1_1_2  0xa2    /* DUAL INPUT PROGRAM */
>  #define SPINOR_OP_WRITE_1_2_2  0xd2    /* DUAL INPUT EXT PROGRAM */
>  #define SPINOR_OP_WRITE_1_1_4  0x32    /* QUAD INPUT PROGRAM */
>  #define SPINOR_OP_WRITE_1_4_4  0x12    /* QUAD INPUT EXT PROGRAM */
>
> -/* READ commands with 32-bit addressing */
> -#define SPINOR_OP_READ4_1_2_2  0xbc
> -#define SPINOR_OP_READ4_1_4_4  0xec
> -
>  /* Configuration flags */
>  #define FLASH_FLAG_SINGLE      0x000000ff
>  #define FLASH_FLAG_READ_WRITE  0x00000001
> diff --git a/drivers/mtd/devices/st_spi_fsm.c b/drivers/mtd/devices/st_spi_fsm.c
> index 5454b4113589..804313a33f2b 100644
> --- a/drivers/mtd/devices/st_spi_fsm.c
> +++ b/drivers/mtd/devices/st_spi_fsm.c
> @@ -507,13 +507,13 @@ static struct seq_rw_config n25q_read3_configs[] = {
>   *     - 'FAST' variants configured for 8 dummy cycles (see note above.)
>   */
>  static struct seq_rw_config n25q_read4_configs[] = {
> -       {FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ4_1_4_4,  0, 4, 4, 0x00, 0, 8},
> -       {FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ4_1_1_4,  0, 1, 4, 0x00, 0, 8},
> -       {FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ4_1_2_2,  0, 2, 2, 0x00, 0, 8},
> -       {FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ4_1_1_2,  0, 1, 2, 0x00, 0, 8},
> -       {FLASH_FLAG_READ_FAST,  SPINOR_OP_READ4_FAST,   0, 1, 1, 0x00, 0, 8},
> -       {FLASH_FLAG_READ_WRITE, SPINOR_OP_READ4,        0, 1, 1, 0x00, 0, 0},
> -       {0x00,                  0,                      0, 0, 0, 0x00, 0, 0},
> +       {FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ_1_4_4_4B, 0, 4, 4, 0x00, 0, 8},
> +       {FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ_1_1_4_4B, 0, 1, 4, 0x00, 0, 8},
> +       {FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ_1_2_2_4B, 0, 2, 2, 0x00, 0, 8},
> +       {FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ_1_1_2_4B, 0, 1, 2, 0x00, 0, 8},
> +       {FLASH_FLAG_READ_FAST,  SPINOR_OP_READ_FAST_4B,  0, 1, 1, 0x00, 0, 8},
> +       {FLASH_FLAG_READ_WRITE, SPINOR_OP_READ_4B,       0, 1, 1, 0x00, 0, 0},
> +       {0x00,                  0,                       0, 0, 0, 0x00, 0, 0},
>  };
>
>  /*
> @@ -553,13 +553,13 @@ static int stfsm_mx25_en_32bit_addr_seq(struct stfsm_seq *seq)
>   * entering a state that is incompatible with the SPIBoot Controller.
>   */
>  static struct seq_rw_config stfsm_s25fl_read4_configs[] = {
> -       {FLASH_FLAG_READ_1_4_4,  SPINOR_OP_READ4_1_4_4,  0, 4, 4, 0x00, 2, 4},
> -       {FLASH_FLAG_READ_1_1_4,  SPINOR_OP_READ4_1_1_4,  0, 1, 4, 0x00, 0, 8},
> -       {FLASH_FLAG_READ_1_2_2,  SPINOR_OP_READ4_1_2_2,  0, 2, 2, 0x00, 4, 0},
> -       {FLASH_FLAG_READ_1_1_2,  SPINOR_OP_READ4_1_1_2,  0, 1, 2, 0x00, 0, 8},
> -       {FLASH_FLAG_READ_FAST,   SPINOR_OP_READ4_FAST,   0, 1, 1, 0x00, 0, 8},
> -       {FLASH_FLAG_READ_WRITE,  SPINOR_OP_READ4,        0, 1, 1, 0x00, 0, 0},
> -       {0x00,                   0,                      0, 0, 0, 0x00, 0, 0},
> +       {FLASH_FLAG_READ_1_4_4,  SPINOR_OP_READ_1_4_4_4B,  0, 4, 4, 0x00, 2, 4},
> +       {FLASH_FLAG_READ_1_1_4,  SPINOR_OP_READ_1_1_4_4B,  0, 1, 4, 0x00, 0, 8},
> +       {FLASH_FLAG_READ_1_2_2,  SPINOR_OP_READ_1_2_2_4B,  0, 2, 2, 0x00, 4, 0},
> +       {FLASH_FLAG_READ_1_1_2,  SPINOR_OP_READ_1_1_2_4B,  0, 1, 2, 0x00, 0, 8},
> +       {FLASH_FLAG_READ_FAST,   SPINOR_OP_READ_FAST_4B,   0, 1, 1, 0x00, 0, 8},
> +       {FLASH_FLAG_READ_WRITE,  SPINOR_OP_READ_4B,        0, 1, 1, 0x00, 0, 0},
> +       {0x00,                   0,                        0, 0, 0, 0x00, 0, 0},
>  };
>
>  static struct seq_rw_config stfsm_s25fl_write4_configs[] = {
> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
> index 5c87b2d99507..423448c1c7a8 100644
> --- a/drivers/mtd/spi-nor/spi-nor.c
> +++ b/drivers/mtd/spi-nor/spi-nor.c
> @@ -75,6 +75,10 @@ struct flash_info {
>                                          * bit. Must be used with
>                                          * SPI_NOR_HAS_LOCK.
>                                          */
> +#define SPI_NOR_4B_OPCODES     BIT(10) /*
> +                                        * Use dedicated 4byte address op codes
> +                                        * to support memory size above 128Mib.
> +                                        */
>  };
>
>  #define JEDEC_MFR(info)        ((info)->id[0])
> @@ -188,6 +192,81 @@ static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd)
>         return mtd->priv;
>  }
>
> +
> +struct spi_nor_address_entry {
> +       u8      src_opcode;
> +       u8      dst_opcode;
> +};
> +
> +static u8 spi_nor_convert_opcode(u8 opcode,
> +                                const struct spi_nor_address_entry *entries,
> +                                size_t num_entries)
> +{
> +       int min, max;
> +
> +       min = 0;
> +       max = num_entries - 1;
> +       while (min <= max) {
> +               int mid = (min + max) >> 1;
> +               const struct spi_nor_address_entry *entry = &entries[mid];
> +
> +               if (opcode == entry->src_opcode)
> +                       return entry->dst_opcode;
> +
> +               if (opcode < entry->src_opcode)
> +                       max = mid - 1;
> +               else
> +                       min = mid + 1;
> +       }
> +
> +       /* No conversion found */
> +       return opcode;
> +}
> +
> +static u8 spi_nor_3to4_opcode(u8 opcode)
> +{
> +       /* MUST be sorted by 3byte opcode */
> +#define ENTRY_3TO4(_opcode)    { _opcode, _opcode##_4B }
> +       static const struct spi_nor_address_entry spi_nor_3to4_table[] = {
> +               ENTRY_3TO4(SPINOR_OP_PP),               /* 0x02 */
> +               ENTRY_3TO4(SPINOR_OP_READ),             /* 0x03 */
> +               ENTRY_3TO4(SPINOR_OP_READ_FAST),        /* 0x0b */
> +               ENTRY_3TO4(SPINOR_OP_BE_4K),            /* 0x20 */
> +               ENTRY_3TO4(SPINOR_OP_PP_1_1_4),         /* 0x32 */
> +               ENTRY_3TO4(SPINOR_OP_PP_1_4_4),         /* 0x38 */
> +               ENTRY_3TO4(SPINOR_OP_READ_1_1_2),       /* 0x3b */
> +               ENTRY_3TO4(SPINOR_OP_BE_32K),           /* 0x52 */
> +               ENTRY_3TO4(SPINOR_OP_READ_1_1_4),       /* 0x6b */
> +               ENTRY_3TO4(SPINOR_OP_READ_1_2_2),       /* 0xbb */
> +               ENTRY_3TO4(SPINOR_OP_SE),               /* 0xd8 */
> +               ENTRY_3TO4(SPINOR_OP_READ_1_4_4),       /* 0xeb */
> +       };
> +#undef ENTRY_3TO4
> +
> +       return spi_nor_convert_opcode(opcode, spi_nor_3to4_table,
> +                                     ARRAY_SIZE(spi_nor_3to4_table));
> +}
> +
> +static void spi_nor_set_4byte_opcodes(struct spi_nor *nor,
> +                                     const struct flash_info *info)
> +{
> +       /* Do some manufacturer fixups first */
> +       switch (JEDEC_MFR(info)) {
> +       case SNOR_MFR_SPANSION:
> +               /* No small sector erase for 4-byte command set */
> +               nor->erase_opcode = SPINOR_OP_SE;
> +               nor->mtd.erasesize = info->sector_size;
> +               break;
> +
> +       default:
> +               break;
> +       }
> +
> +       nor->read_opcode        = spi_nor_3to4_opcode(nor->read_opcode);
> +       nor->program_opcode     = spi_nor_3to4_opcode(nor->program_opcode);
> +       nor->erase_opcode       = spi_nor_3to4_opcode(nor->erase_opcode);
> +}
> +
>  /* Enable/disable 4-byte addressing mode. */
>  static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info,
>                             int enable)
> @@ -1476,27 +1555,10 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
>         else if (mtd->size > 0x1000000) {
>                 /* enable 4-byte addressing if the device exceeds 16MiB */
>                 nor->addr_width = 4;
> -               if (JEDEC_MFR(info) == SNOR_MFR_SPANSION) {
> -                       /* Dedicated 4-byte command set */
> -                       switch (nor->flash_read) {
> -                       case SPI_NOR_QUAD:
> -                               nor->read_opcode = SPINOR_OP_READ4_1_1_4;
> -                               break;
> -                       case SPI_NOR_DUAL:
> -                               nor->read_opcode = SPINOR_OP_READ4_1_1_2;
> -                               break;
> -                       case SPI_NOR_FAST:
> -                               nor->read_opcode = SPINOR_OP_READ4_FAST;
> -                               break;
> -                       case SPI_NOR_NORMAL:
> -                               nor->read_opcode = SPINOR_OP_READ4;
> -                               break;
> -                       }
> -                       nor->program_opcode = SPINOR_OP_PP_4B;
> -                       /* No small sector erase for 4-byte command set */
> -                       nor->erase_opcode = SPINOR_OP_SE_4B;
> -                       mtd->erasesize = info->sector_size;
> -               } else
> +               if (JEDEC_MFR(info) == SNOR_MFR_SPANSION ||
> +                   info->flags & SPI_NOR_4B_OPCODES)
> +                       spi_nor_set_4byte_opcodes(nor, info);

I am giving my inputs based on the discussion on this thread[1].

Seems like winbond[2], stmicron, spansion look better way or equally
same for accessing 4-byte addressing commands. and I find few of the
Macronix [3] have support of 4B addressing(see Table 5) but
lack/unable to find the 4B opcodes.

And about BAR support, based on my experience in u-boot and research
on above chips only require when controller isn't supporting 4-byte
addressing even if connected flash chip has > 16MiB, that means there
is no exact or equivalent requirement for flash side either.

So, adding the flags on flash table might be the good option instead
making code to convert 3B opcode to 4B because anyway the chips
require SPI_NOR_4B_OPCODES and also except winbond, stmicron, spansion
not too many flash needed > 16MiB support as of now.

[1] https://lkml.org/lkml/2016/10/24/276
[2] https://www.winbond.com/resource-files/w25q256fv_revg1_120214_qpi_website_rev_g.pdf
[3] http://www.zlgmcu.com/mxic/pdf/NOR_Flash_c/MX25L25635E_DS_EN.pdf

thanks!
-- 
Jagan Teki
Free Software Engineer | www.openedev.com
U-Boot, Linux | Upstream Maintainer
Hyderabad, India.


From jagan at openedev.com  Mon Oct 31 11:59:41 2016
From: jagan at openedev.com (Jagan Teki)
Date: Tue, 1 Nov 2016 00:29:41 +0530
Subject: [PATCH v2 1/1] MAINTAINERS: add a maintainer for the SPI NOR
 subsystem
In-Reply-To: <20161027201930.GA1582@localhost>
References: <aad52b708dcf6754edab87d2e0afe4f0ee6831f9.1476891131.git.cyrille.pitchen@atmel.com>
 <d92f8ef8-be78-0386-fa84-117c3cae6459@denx.de>
 <CAD6G_RRm0ttasw8DAQvE2fOpXd61tTsbNwyy_vJ_quAO0y3swA@mail.gmail.com>
 <20161027201930.GA1582@localhost>
Message-ID: <CAD6G_RQEgFbAgh25F8YE-gv66JV2qhUeb8pAVyEHzaXttgLF9g@mail.gmail.com>

On Fri, Oct 28, 2016 at 1:49 AM, Brian Norris
<computersforpeace at gmail.com> wrote:
> Hi,
>
> On Fri, Oct 21, 2016 at 11:28:00PM +0530, Jagan Teki wrote:
>> On Thu, Oct 20, 2016 at 7:12 PM, Marek Vasut <marex at denx.de> wrote:
>> > On 10/19/2016 05:34 PM, Cyrille Pitchen wrote:
>> >> I would like to volunteer as a maintainer for the SPI NOR part of the MTD
>> >> subsystem.
>
> Thanks! I'll be happy to have the help.
>
> [...]
>
>> >> Also both Marek Vasut and Richard Weinberger have volunteered as well as
>> >> maintainers for the SPI NOR subsystem.
>
> Snipped all mention of Richard, since he did not volunteer :)
>
>> >> Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
>> >> Acked-by: Boris Brezillon <boris.brezillon at free-electrons.com>
>> >
>> > Acked-by: Marek Vasut <marek.vasut at gmail.com>
>>
>> Acked-by: Jagan Teki <jteki at openedev.com>
>>
>> >
>> > btw I think I'll need higher privileges in patchwork to fiddle with patches.
>
> I expect you'll be mailing Jeremy soon then.
>
>> >> ---
>> >> ChangeLog:
>> >>
>> >> v1 -> v2:
>> >> - add Marek and Richard as maintainers.
>> >> - add Acked-by from Boris Brezillon.
>> >>
>> >>
>> >>  MAINTAINERS | 12 ++++++++++++
>> >>  1 file changed, 12 insertions(+)
>> >>
>> >> diff --git a/MAINTAINERS b/MAINTAINERS
>> >> index 757f9c4b388d..7e63b2015072 100644
>> >> --- a/MAINTAINERS
>> >> +++ b/MAINTAINERS
>> >> @@ -11390,6 +11390,18 @@ W:   http://www.st.com/spear
>> >>  S:   Maintained
>> >>  F:   drivers/clk/spear/
>> >>
>> >> +SPI NOR SUBSYSTEM
>> >> +M:   Cyrille Pitchen <cyrille.pitchen at atmel.com>
>> >> +M:   Marek Vasut <marek.vasut at gmail.com>
>> >> +M:   Richard Weinberger <richard at nod.at>
>
> Snipped the above line, and pushed to linux-mtd.git.
>
>>
>> May be I was little late, but if there is any space for one more or so
>> I would also like to co-maintain? Currently I am maintaining
>> SPI/SPI-FLASH for u-boot and working for generic MTD (with u-boot
>> driver model) + SPI-NOR addition on u-boot which eventually similar
>> conceptual theory what Linux follows.
>
> I'd be happy to add more if the others think that it's warranted. If
> not, I'm sure all involved would still be happy with extra review, and
> that could serve nearly the same purpose, as long as the committers
> don't fall asleep like I admittedly have too often.

True Brian, hope I may heard something form Marek or Cyrille.

thanks!
-- 
Jagan.


From hkallweit1 at gmail.com  Mon Oct 31 12:15:18 2016
From: hkallweit1 at gmail.com (Heiner Kallweit)
Date: Mon, 31 Oct 2016 20:15:18 +0100
Subject: [PATCH] mtd: spi-nor: add sleeping version of
 spi_nor_wait_till_ready for erase ops
In-Reply-To: <716d2877-dc4f-f93d-5d93-cde671b89082@atmel.com>
References: <eaa526ca-f0b4-4fde-d334-2ca6af72c32d@gmail.com>
 <716d2877-dc4f-f93d-5d93-cde671b89082@atmel.com>
Message-ID: <f49c0b7a-1c08-9f61-e1b1-4ce5d4e3687a@gmail.com>

Am 31.10.2016 um 14:50 schrieb Cyrille Pitchen:
> Hi Heiner,
> 
Thanks for the very prompt review comments!

> +Marek
> 
> Le 30/10/2016 ? 10:32, Heiner Kallweit a ?crit :
>> Currently spi_nor_wait_till_ready in the poll loop permanently checks
>> for the WIP flag to be reset. Erase ops typically take >100ms for
>> sector erase and >10s for chip erase. Permanently polling for such
>> longer time periods puts unnecessary load on the SPI subsystem
>> (especially on systems w/o SPI DMA support or systems using bitbanging).
>>
>> Relax this by sleeping for a reasonable time between checking the
>> WIP flag.
>>
>> Signed-off-by: Heiner Kallweit <hkallweit1 at gmail.com>
>> ---
>>  drivers/mtd/spi-nor/spi-nor.c | 27 +++++++++++++++++++++------
>>  1 file changed, 21 insertions(+), 6 deletions(-)
>>
>> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
>> index d0fc165..808ea4c 100644
>> --- a/drivers/mtd/spi-nor/spi-nor.c
>> +++ b/drivers/mtd/spi-nor/spi-nor.c
>> @@ -17,6 +17,7 @@
>>  #include <linux/mutex.h>
>>  #include <linux/math64.h>
>>  #include <linux/sizes.h>
>> +#include <linux/delay.h>
>>  
>>  #include <linux/mtd/mtd.h>
>>  #include <linux/of_platform.h>
>> @@ -252,7 +253,8 @@ static int spi_nor_ready(struct spi_nor *nor)
>>   * Returns non-zero if error.
>>   */
>>  static int spi_nor_wait_till_ready_with_timeout(struct spi_nor *nor,
>> -						unsigned long timeout_jiffies)
>> +						unsigned long timeout_jiffies,
>> +						unsigned int sleep_msecs)
>>  {
>>  	unsigned long deadline;
>>  	int timeout = 0, ret;
>> @@ -269,7 +271,13 @@ static int spi_nor_wait_till_ready_with_timeout(struct spi_nor *nor,
>>  		if (ret)
>>  			return 0;
>>  
>> -		cond_resched();
>> +		if (!sleep_msecs)
>> +			cond_resched();
>> +		else if (sleep_msecs < 50)
>> +			usleep_range(sleep_msecs * 1000 - 100,
>> +				     sleep_msecs * 1000);
>> +		else
>> +			msleep(sleep_msecs);
>>  	}
>>  
>>  	dev_err(nor->dev, "flash operation timed out\n");
>> @@ -277,10 +285,17 @@ static int spi_nor_wait_till_ready_with_timeout(struct spi_nor *nor,
>>  	return -ETIMEDOUT;
>>  }
>>  
>> -static int spi_nor_wait_till_ready(struct spi_nor *nor)
>> +static inline int spi_nor_wait_till_ready_sleep(struct spi_nor *nor,
>> +						unsigned int sleep_msecs)
>>  {
>>  	return spi_nor_wait_till_ready_with_timeout(nor,
>> -						    DEFAULT_READY_WAIT_JIFFIES);
>> +						    DEFAULT_READY_WAIT_JIFFIES,
>> +						    sleep_msecs);
>> +}
>> +
>> +static inline int spi_nor_wait_till_ready(struct spi_nor *nor)
>> +{
>> +	return spi_nor_wait_till_ready_sleep(nor, 0);
>>  }
>>  
> 
> Not a big deal but, IMHO, you should remove spi_nor_wait_till_ready_sleep()
> from your patch to avoid introducing a 3rd spi_nor_wait_till_ready* function,
> so we don't have to wonder which version to call when we have to wait for the
> memory to be ready again.
> 
> Besides, spi_nor_wait_ready_sleep() is called only once so it is not so
> useful.
> 
> Finally, the duration expressed by the sleep_msecs parameter should not be
> higher than the duration of timeout_jiffies in
> spi_nor_wait_till_ready_with_timeout(). The spi_nor_wait_till_ready_sleep()
> hides the timeout_jiffies value so it's less obvious to choose a right value
> for sleep_msecs when you have to look at the implementation of the
> spi_nor_wait_till_ready_sleep() function to find out the actual value of
> timeout_jiffies.
> 
> What I mean is that those two parameters, timeout_jiffies and sleep_msec, are
> tightly bound. So when calling one of the spi_nor_wait_till_ready* functions(),
> those two parameters should be either both fixed (macro) or both variable.
> 
> Marek, what do you think about this point?
> 
>>  /*
>> @@ -387,7 +402,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
>>  		timeout = max(CHIP_ERASE_2MB_READY_WAIT_JIFFIES,
>>  			      CHIP_ERASE_2MB_READY_WAIT_JIFFIES *
>>  			      (unsigned long)(mtd->size / SZ_2M));
>> -		ret = spi_nor_wait_till_ready_with_timeout(nor, timeout);
>> +		ret = spi_nor_wait_till_ready_with_timeout(nor, timeout, 100);
> 
> Please, use macros instead of hardcoded values. For instance, here it could be
> CHIP_ERASE_READY_WAIT_SLEEP_MSEC or something else which clearly states
> that the value is for chip erase operations and is associated with the
> CHIP_ERASE_2MB_READY_WAIT_JIFFIES macro.
> 
>>  		if (ret)
>>  			goto erase_err;
>>  
>> @@ -408,7 +423,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
>>  			addr += mtd->erasesize;
>>  			len -= mtd->erasesize;
>>  
>> -			ret = spi_nor_wait_till_ready(nor);
>> +			ret = spi_nor_wait_till_ready_sleep(nor, 2);
> See comments above.
> 
> Do you have some figures to show the impact of this patch on the performances?

Let's see whether Marek also has some comments, then I'll prepare a v2
of the patch. Regarding performance figures:

This patch saves me ~ 3 Mio SPI interrupts (5 Mio irq -> 2 Mio irq)
at first boot of OpenWRT/LEDE after flashing firmware (mainly when
preparing the jffs2 file system). Boot time is the same.

In detail per poll cycle (for my system setup):
With 33MHz SPI clock and 2 bytes for reading the status register
the SPI transfer per poll cycle takes ~ 0.5us. Plus overhead for
SPI message handling etc. let's assume one poll cycle takes ~ 1us.
With one interrupt per SPI transfer we then have 100.000 interrupts
just for waiting for one sector erase to finish.

In the patch the sleeping version is used just for sector erase
and chip erase. However there are more places where using it might
make sense, e.g. write_sr() takes longer time on several chips.

Rgds, Heiner

>>  			if (ret)
>>  				goto erase_err;
>>  		}
>>
> 
> Best regards,
> 
> Cyrille
> 



From christophe.jaillet at wanadoo.fr  Mon Oct 31 23:45:25 2016
From: christophe.jaillet at wanadoo.fr (Christophe JAILLET)
Date: Tue,  1 Nov 2016 07:45:25 +0100
Subject: [PATCH] UBIFS: Remove some dead code
Message-ID: <20161101064525.11813-1-christophe.jaillet@wanadoo.fr>

'ubifs_fast_find_freeable()' can not return an error pointer, so this test
can be removed.

Signed-off-by: Christophe JAILLET <christophe.jaillet at wanadoo.fr>
---
 fs/ubifs/gc.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/fs/ubifs/gc.c b/fs/ubifs/gc.c
index e845c64b6ce1..7b35e3d6cde7 100644
--- a/fs/ubifs/gc.c
+++ b/fs/ubifs/gc.c
@@ -846,10 +846,6 @@ int ubifs_gc_start_commit(struct ubifs_info *c)
 	 */
 	while (1) {
 		lp = ubifs_fast_find_freeable(c);
-		if (IS_ERR(lp)) {
-			err = PTR_ERR(lp);
-			goto out;
-		}
 		if (!lp)
 			break;
 		ubifs_assert(!(lp->flags & LPROPS_TAKEN));
-- 
2.9.3



